Решение проблемы отображения всех IP-адресов пользователей как Cloudflare вместо реальных IP-адресов в браузере при развертывании Discourse через 1Panel

Я установил 1Panel на VPS, развернул Discourse (в контейнере) и настроил обратный прокси с помощью OpenResty (также в контейнере). Домен размещён в Cloudflare, включён CDN (желтый облачко). Ниже приведена инструкция, как решить проблему, при которой IP-адреса пользователей отображаются как адреса Cloudflare, а не реальные IP-адреса браузеров.

1. Создание запланированной задачи в 1Panel для еженедельного скачивания актуального списка IP-адресов Cloudflare и сохранения его в директорию конфигурации OpenResty.

  1. В левом меню 1Panel нажмите “Запланированные задачи”.

  2. В правом верхнем углу нажмите “Создать задачу”.

  3. Заполните параметры следующим образом (можно просто скопировать и вставить):

  • Тип задачи: выберите Shell-скрипт.

  • Название задачи: например, Автоматическое обновление диапазонов IP Cloudflare.

  • Периодичность выполнения: рекомендуется выбрать Еженедельно (например, каждую субботу в 03:00).

  • Содержимое скрипта: скопируйте и вставьте полный код ниже (обратите внимание: сначала измените имя контейнера и путь к директории конфигурации в начале скрипта):

#!/bin/bash
# Область конфигурации
CONTAINER_NAME="Имя контейнера openresty в 1Panel"
# Измените на указанный путь к директории proxy сайта
CONF_DIR="/opt/1panel/www/sites/www.ваш-домен/proxy"

echo "[$(date)] Начало получения актуальных диапазонов IP от Cloudflare..."
TEMP_DIR=$(mktemp -d)

# Получение и преобразование списка IP в формат, распознаваемый Nginx
curl -fsS https://www.cloudflare.com/ips-v4 | sed 's/.*/set_real_ip_from \0;/' > $TEMP_DIR/cf-ips-v4.conf
curl -fsS https://www.cloudflare.com/ips-v6 | sed 's/.*/set_real_ip_from \0;/' > $TEMP_DIR/cf-ips-v6.conf

# Проверка и перемещение файлов
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)] Файлы конфигурации успешно обновлены в $CONF_DIR."
else
    echo "[$(date)] Ошибка: не удалось получить IP-адреса Cloudflare!"
    rm -rf $TEMP_DIR
    exit 1
fi
rm -rf $TEMP_DIR

# Тестирование и перезагрузка Nginx
echo "[$(date)] Проверка конфигурации Nginx..."
if docker exec $CONTAINER_NAME nginx -t; then
    docker exec $CONTAINER_NAME nginx -s reload
    echo "[$(date)] Успешно! Конфигурация OpenResty перезапущена."
else
    echo "[$(date)] Не удалось! Проверка конфигурации Nginx не пройдена."
    exit 1
fi

После создания задачи не нужно ждать субботу — вы можете сразу протестировать её: в списке “Запланированные задачи” найдите только что созданную задачу.

Нажмите кнопку “Отчёт” справа. Откроется окно с логами. Если в последних строках отображается Успешно! Конфигурация OpenResty перезапущена, значит весь процесс внутри 1Panel выполнен корректно!

2. Добавление конфигурации realip в OpenResty

В директории хост-системы /opt/1panel/www/sites/www.ваш-домен/proxy/ создайте новый файл (имя произвольное, но должно заканчиваться на .conf, чтобы он автоматически подгружался через include *.conf в основной конфигурации): realip.conf

real_ip_header CF-Connecting-IP;
real_ip_recursive on;

3. Перезагрузка OpenResty

docker exec Имя_контейнера_openresty_в_1Panel nginx -t
docker exec Имя_контейнера_openresty_в_1Panel nginx -s reload

4. Проверка получения OpenResty реального IP-адреса

Просмотрите лог доступа OpenResty:

tail -f /opt/1panel/www/sites/www.ваш-домен/log/access.log

Если конфигурация верна, первый IP-адрес в логе должен быть вашим реальным публичным IP, а не адресом из диапазона Cloudflare (например, 173.245.x.x).

5. Пояснения для Discourse

Добавление - "templates/cloudflare.template.yml" в app.yml Discourse эффективно только тогда, когда Discourse напрямую обращается к Cloudflare. Поскольку между ними находится обратный прокси OpenResty, контейнер Discourse видит источник IP как шлюз Docker (например, 172.17.0.1 или 172.18.0.1), поэтому директивы set_real_ip_from <CloudflareIP> из этого шаблона не сработают.

Однако, если вы выполнили описанные выше шаги на уровне OpenResty для восстановления реального IP и передачи чистого заголовка X-Forwarded-For, то бэкенд Rails в Discourse корректно определит реальный IP пользователя, поскольку Rails по умолчанию доверяет приватным диапазонам Docker (например, 172.x.x.x).

Таким образом, добавлять - "templates/cloudflare.template.yml" в app.yml Discourse не нужно.