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

Я установил 1Panel на VPS, развернул Discourse (в контейнере) и настроил обратный прокси через OpenResty (также в контейнере). Домен хостится на Cloudflare с включённым CDN (желтое облако). Ниже приведено решение проблемы, при которой IP-адрес пользователя отображается как 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.ваш_домен.club/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 &;/' > $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

# Проверка и перемещение файлов
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

# Используйте путь внутри контейнера
include /www/sites/www.ваш_домен/proxy/cf-ips-v4.conf;
include /www/sites/www.ваш_домен/proxy/cf-ips-v6.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

Просмотрите access-лог OpenResty:

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

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

5. Настройка стороны Discourse

Отредактируйте файл app.yml и добавьте следующий код внутри блока run::

  # После развертывания Discourse в Docker необходимо добавить следующие три раздела, чтобы обеспечить передачу реального IP-адреса пользователей форума
  - file:
      path: /etc/nginx/conf.d/outlets/server/set-real-ip-from-docker.conf
      chmod: 644
      contents: |
        set_real_ip_from 172.16.0.0/12;
        set_real_ip_from 127.0.0.1;
  
  - file:
      path: /etc/nginx/conf.d/outlets/server/real-ip-header.conf
      chmod: 644
      contents: |
        real_ip_header x-forwarded-for;
  
  - file:
      path: /etc/nginx/conf.d/outlets/server/real-ip-recursive.conf
      chmod: 644
      contents: |
        real_ip_recursive on;

Таким образом, встроенный Nginx в Discourse будет:

  1. Доверять IP-диапазону Docker (172.16.0.0/12)
  2. Считывать реальный IP из заголовка x-forwarded-for
  3. Рекурсивно разбирать цепочку прокси

6. Примечания

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

Поэтому нет необходимости добавлять - "templates/cloudflare.template.yml" в app.yml Discourse.


Обновлено: 03.07.2026

2 лайка

Ссылка

Цепочка доверия для обработки реального IP-адреса конечного пользователя — Документы / Самостоятельное размещение — Discourse Meta

Обновить пост в теме.