Вопрос или проблема
Я использую nginx для мультиплексирования SSH и HTTPS с помощью этого файла /etc/nginx/nginx.config
:
stream {
upstream ssh {
server 127.0.0.1:22;
}
upstream https {
server 127.0.0.1:8443;
}
map $ssl_preread_protocol $upstream {
default ssh;
"TLSv1.2" https;
"TLSv1.3" https;
"TLSv1.1" https;
"TLSv1.0" https;
}
server {
listen 443;
proxy_pass $upstream;
ssl_preread on;
}
}
Это успешно направляет трафик, но имеет побочный эффект: все соединения выглядят как приходящие с 127.0.0.1 как для SSH, так и для HTTPS:
$ last
jason pts/3 127.0.0.1 Ср Фев 19 22:25 - 22:25 (00:00)
...
$ tail -1 /var/log/nginx/access.log
127.0.0.1 - - [19/Фев/2025:20:31:36 +0100] "GET /favicon.ico HTTP/1.1" 200 1406 "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/132.0.0.0 Safari/537.36"
Я пытался использовать прозрачное проксирование, изменив файл /etc/nginx/nginx.config
следующим образом:
user root; # было: www-data
...
server {
listen 443;
proxy_bind $remote_addr transparent;
proxy_pass $upstream;
ssl_preread on;
}
...
Однако это вызывает зависание и тайминги входящих соединений SSH и HTTPS. Я пытался отключить файрвол ufw
, но это не дало эффекта.
Документация proxy_bind
недостаточно определенна по поводу того, что делать: https://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_bind
Для работы этого параметра обычно необходимо запускать рабочие процессы nginx с привилегиями суперпользователя. На Linux это не требуется (1.13.8), так как если указан параметр transparent, рабочие процессы наследуют способность CAP_NET_RAW от главного процесса. Также необходимо настроить таблицу маршрутизации ядра для перехвата сетевого трафика с проксируемого сервера.
Я изменил на user root;
и запускаю nginx через sudo systemctl start nginx
, так что у меня должна быть часть “суперпользователя”, верно?
Как мне “настроить таблицу маршрутизации ядра для перехвата сетевого трафика с проксируемого сервера”? Обратите внимание, что я в настоящее время использую ufw
для настройки iptables, если это имеет значение.
ИЗМЕНИТЬ: Альтернативно, если я смогу каким-то образом применить proxy_protocol
или внедрить HTTP заголовки с $remote_addr
для HTTP стороны (и сохранить SSH поток нетронутым), это уже решит половину проблемы: логи моего сайта будут содержать правильный IP адрес. Я, вероятно, смогу смириться с тем, что логи SSH неверны.
Это стандартный способ добавления удаленного IP адреса при проксировании:
proxy_set_header X-Real-IP $remote_addr;
Затем используйте заголовок X-Real-IP
на вашем upstream веб-сервере для логирования IP адресов.
Ответ или решение
Теория и Контекст
В случае, если вы используете Nginx для мультиплексирования SSH и HTTPS трафика, ваши текущие настройки могут вызвать проблему, при которой все входящие соединения на серверы SSH и HTTPS отображаются как происходящие с IP-адреса 127.0.0.1. Это может затруднить ведение журналов и мониторинг реальных IP-адресов клиентов. Для того чтобы решить эту проблему, существует два подхода: использовать транспарентное проксирование или применять Proxy Protocol.
Транспарентное Проксирование
Транспарентное проксирование позволяет вам сохранять исходный IP-адрес клиента, тем самым сохраняя возможность отслеживать реальные адреса в логах сервера. Тем не менее, реализация требует дополнительных настроек сетевых правил. Попробуем разобраться, как это можно сделать.
-
CAP_NET_ADMIN и CAP_NET_RAW: Убедитесь, что nginx работает с нужными привилегиями. В некоторых системах, даже если Nginx запущен от имени суперпользователя, для работоспособности транспарентного проксирования требуется, чтобы процессы nginx унаследовали возможности
CAP_NET_RAW
иCAP_NET_ADMIN
. Дать такие права можно с помощью:sudo setcap 'cap_net_bind_service=+ep' /path/to/nginx sudo setcap 'cap_net_admin,cap_net_raw=+ep' /path/to/nginx
-
Настройка таблиц маршрутизации: Необходимо настроить правила iptables для перехвата входящего трафика и его корректной маршрутизации. Попробуйте следующие команды:
# Создаем правила для модуля nf_conntrack sudo iptables -t mangle -N DIVERT sudo iptables -t mangle -A PREROUTING -p tcp -m socket -j DIVERT sudo iptables -t mangle -A DIVERT -j MARK --set-mark 1 sudo iptables -t mangle -A DIVERT -j ACCEPT sudo ip rule add fwmark 1 lookup 100 sudo ip route add local 0.0.0.0/0 dev lo table 100
-
Отладка: Убедитесь, что команда
ip rule show
подтверждает наличие правил маршрутизации с установленным fwmark. Также используйте командыiptables -t mangle -L
иip route show table 100
для проверки корректности настроек.
Если после выполнения всех шагов транспарентное проксирование не работает, вы можете столкнуться с специфическими ограничениями дистрибутива Linux или конфигурацией сети.
Proxy Protocol
Альтернативный путь к решению вашей проблемы — использование Proxy Protocol, который позволяет проксирующему серверу передавать информацию о реальном клиентском IP-адресе через дополнительный заголовок.
-
Настройка Nginx: Добавьте в конфигурацию Nginx использование Proxy Protocol:
server { listen 443 proxy_protocol; proxy_pass $upstream; ssl_preread on; # Другие настройки... }
-
Настройка Upstream серверов: Убедитесь, что бэкенды HTTP поддерживают Proxy Protocol. Если это веб-сервер типа Apache или другой сервер, который не поддерживает Proxy Protocol напрямую, можно применить директивы вроде
proxy_set_header
и подставить IP-адрес клиента в X-Real-IP:proxy_set_header X-Real-IP $proxy_protocol_addr;
-
Конфигурация SSH demon (sshd): Для SSH потребуется дополнительная обработка, поскольку многие версии sshd не поддерживают Proxy Protocol. В этом случае единственное возможное решение — разделить потоки таким образом, чтобы Proxy Protocol воздействовал только на HTTPS-трафик, а для SSH оставался прежний механизм.
Применение и Заключение
Конфигурация проксирования — задача, которая включает в себя интеграцию нескольких системных и программных настроек, где много факторов могут повлиять на конечный результат. При этом, ни один из методов не является универсальным решением и может потребовать адаптации в зависимости от специфики вашего окружения или используемых версий программного обеспечения.
Рекомендую начать с настройкой Proxy Protocol, так как она более гибкая и реализуется через конфигурацию, что позволяет в дальнейшем легче отладить процесс. Как альтернативы можно рассмотреть использование протоколов и настроек другого уровня — например, сетевого, в случае отсутствия необходимых поддерживаемых версий приложений.