Solucionar el problema de que en Discourse desplegado con 1Panel, todas las IPs de usuario muestren Cloudflare en lugar de la IP real del navegador

He instalado 1Panel en un VPS, seguido de Discourse (despliegue en contenedor) y un proxy inverso con OpenResty (también en contenedor). El dominio está alojado en Cloudflare con la nube amarilla (CDN) activada. A continuación, presento un tutorial para resolver el problema de que las direcciones IP de los usuarios se muestran como procedentes de Cloudflare en lugar de la IP real del navegador del usuario.

I. Crear una tarea programada en 1Panel para descargar semanalmente la lista actualizada de IPs de Cloudflare y guardarla en el directorio de configuración de OpenResty.

  1. En el menú lateral izquierdo de 1Panel, haz clic en “Tareas programadas”.

  2. Haz clic en el botón “Crear tarea programada” en la esquina superior derecha.

  3. Rellena los siguientes parámetros (puedes copiar y pegar directamente):

  • Tipo de tarea: Selecciona Script Shell.

  • Nombre de la tarea: Por ejemplo, Actualización automática de rangos IP de Cloudflare.

  • Ciclo de ejecución: Se recomienda Semanal (por ejemplo, todos los sábados a las 03:00 de la madrugada).

  • Contenido del script: Copia y pega el siguiente código completo (Nota: antes de ejecutarlo, modifica el nombre del contenedor y la ruta del directorio de configuración al inicio del código):

#!/bin/bash
# Zona de configuración
CONTAINER_NAME="Nombre del contenedor de openresty en 1Panel"
# Modifica esta ruta por el directorio proxy del sitio web específico
CONF_DIR="/opt/1panel/www/sites/www.tu-dominio.com/proxy"

echo "[$(date)] Iniciando la obtención de los últimos rangos IP de Cloudflare..."
TEMP_DIR=$(mktemp -d)

# Obtener y convertir la lista de IPs al formato reconocido por Nginx
curl -fsS https://www.cloudflare.com/ips-v4 | sed 's/.*/set_real_ip_from \&;/' > $TEMP_DIR/cf-ips-v4.conf
curl -fsS https://www.cloudflare.com/ips-v6 | sed 's/.*/set_real_ip_from \&;/' > $TEMP_DIR/cf-ips-v6.conf

# Verificar y mover los archivos
if [[ -s $TEMP_DIR/cf-ips-v4.conf ]] && [[ -s $TEMP_DIR/cf-ips-v6.conf ]]; then
    mv $TEMP_DIR/cf-ips-v4.conf $CONF_DIR/
    mv $TEMP_DIR/cf-ips-v6.conf $CONF_DIR/
    echo "[$(date)] Los archivos de configuración se han actualizado correctamente en $CONF_DIR."
else
    echo "[$(date)] Error: ¡Fallo al obtener las IPs de Cloudflare!"
    rm -rf $TEMP_DIR
    exit 1
fi
rm -rf $TEMP_DIR

# Probar y recargar Nginx
echo "[$(date)] Realizando prueba de configuración de Nginx..."
if docker exec $CONTAINER_NAME nginx -t; then
    docker exec $CONTAINER_NAME nginx -s reload
    echo "[$(date)] ¡Éxito! Recarga de configuración de OpenResty completada."
else
    echo "[$(date)] ¡Fallo! La prueba de configuración de Nginx no se ha superado."
    exit 1
fi

Una vez creada la tarea, no es necesario esperar al sábado; puedes probarla inmediatamente: en la lista de “Tareas programadas”, busca la tarea que acabas de crear.

Haz clic en el botón “Reporte” a la derecha. Revisa la ventana de registros emergente. Si las últimas líneas muestran ¡Éxito! Recarga de configuración de OpenResty completada, significa que todo el proceso se ha ejecutado correctamente dentro de 1Panel.

II. Configuración adicional de realip en OpenResty

Crea un nuevo archivo en el directorio de la máquina anfitriona /opt/1panel/www/sites/www.tu-dominio.com/proxy/ (el nombre del archivo es arbitrario, debe terminar en .conf para ser cargado automáticamente por la configuración principal mediante include *.conf): realip.conf

real_ip_header CF-Connecting-IP;
real_ip_recursive on;

III. Recargar OpenResty

docker exec Nombre_del_contenedor_de_openresty_en_1Panel nginx -t
docker exec Nombre_del_contenedor_de_openresty_en_1Panel nginx -s reload

IV. Verificar si OpenResty ha obtenido la IP real

Revisa el registro de acceso (access log) de OpenResty:

tail -f /opt/1panel/www/sites/www.tu-dominio.com/log/access.log

Si la configuración es correcta, la primera IP en el registro debería ser tu IP pública real, y no un rango de Cloudflare como 173.245.x.x.

V. Consideraciones para Discourse

Agregar - "templates/cloudflare.template.yml" al archivo app.yml de Discourse solo es efectivo cuando Discourse está expuesto directamente a Cloudflare. Dado que hemos añadido un proxy inverso OpenResty en medio, el contenedor de Discourse verá la IP del gateway de Docker (como 172.17.0.1 o 172.18.0.1) como origen, por lo que la directiva set_real_ip_from <CloudflareIP> en esa plantilla no coincidirá.

Sin embargo, siempre que sigas los pasos anteriores para restaurar la IP real en la capa de OpenResty y transmitir un encabezado X-Forwarded-For limpio, el backend Rails de Discourse podrá identificar correctamente la IP real del usuario, ya que Rails confía por defecto en rangos de red privados de Docker como 172.x.x.x.

Por lo tanto, no es necesario agregar - "templates/cloudflare.template.yml" al archivo app.yml de Discourse.