nginx: как при помощи proxy_pass прокинуть и 80, и 443-й порты?
До сих пор я использовал nginx достаточно тривиальным образом: на него "приземлялись" http/https обращения, и он служил "базой", на которой работал certbot и обновлял letsencrypt - сертификаты для разных доменов. Как правило, статические сайты хостились на самом сервере с nginx, а для тех, которые обеспечивали api - работа после nginx шла по http, то есть, nginx работал в роли ssl-termination. То есть, "из интернета мы обращаемся по https, а внутри сети у нас ходит http" - и все были счастливы.
Но наступил момент, когда мне "захотелось странного". А именно - внутри сети появился gitlab.
Гитлаб - это штука весьма самостоятельная, и он сам хостит https-сертификаты. То есть, если у меня теперь происходит обращение снаружи по имени гитлаба - то мне надо https - запрос так и отфорвардить внутрь сети.
При этом я могу по всякому настраивать http/https порты на самом гитлабе, но сейчас ониу меня настроены на 8080 и 8443.
я почитал разные советы, про директиву proxy_ssl_server_name, но ни один их них мне, вроде бы, не подходит. И старый способ с ssl-termination на уровне nginx мне тоже не подходит.
Типичный файл для proxy_pass выглядит примерно так:
server {
root /var/www/<folder_of_site>;
index index.html index.htm index.nginx-debian.html;
server_name mygitlab.myserver.ru www.mygitlab.myserver.ru;
client_max_body_size 2048m;
location / {
proxy_redirect http://192.168.0.10:8080 /;
proxy_pass_header Server;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Scheme $scheme;
proxy_set_header Host $http_host;
proxy_set_header X-NginX-Proxy true;
proxy_connect_timeout 5;
proxy_read_timeout 240;
proxy_intercept_errors on;
proxy_pass http://192.168.0.10:8080;
}
}
Обратите внимание: здесь нигде не написано, что перекидываются соединения с 80-го порта, видимо, это поведение по умолчанию. Вот если бы я в директиве location мог указать порт - я бы просто два раза повторил тот кусочек файла, который сожержит внутри себя директивы proхy_... - и получил бы желаемый результат, видимо.
А желаемое поведение nginx-а я проиллюстрирую вот такой картинкой:
Буду очень благодарен за советы!
Что в итоге
Уважаемые господа, этот пункт добавлен уже после того, как всё получилось. Я последовал совету Pak Uula и сделал так,К ак он в своём ответе называет "правильно": теперь у меня nginx занмается ssl-termination, а Gitlab "просто работает". Оказывается, не нужно предпринимать дополнительных усилий для отключения https у гитлаба, в руководстве пишут "By default, Omnibus GitLab does not use HTTPS".
Таким образом, у меня всё заработало. Для тех, кто будет читать это пост я напишу даже чуть чуть подробнее:
0-й шаг: в DMZ на машинке с адресом 192.168.0.10 я поднимаю гитлаб в контейнере командой типа
sudo docker run --detach \
--hostname docker.junecat.ru \
--publish 8443:443 --publish 8080:80 --publish 1022:22 \
--name gitlab1 \
--restart always \
--volume $GITLAB_HOME/config:/etc/gitlab \
--volume $GITLAB_HOME/logs:/var/log/gitlab \
--volume $GITLAB_HOME/data:/var/opt/gitlab \
--shm-size 256m \
gitlab/gitlab-ce:latest
1-й шаг: создаю для nginx файл /etc/nginx/sites-available/docker.junecat.ru с таким содержимым:
server {
listen 80;
listen [::]:80;
root /var/www/docker.junecat.ru/;
index index.html index.htm;
server_name docker.junecat.ru www.docker.junecat.ru;
location / {
proxy_redirect http://192.168.0.10:8080/ /;
proxy_pass_header Server;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Scheme $scheme;
proxy_set_header X-NginX-Proxy true;
proxy_connect_timeout 5;
proxy_read_timeout 240;
proxy_intercept_errors on;
proxy_pass http://192.168.0.10:8080/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
обратите внимание, что команда
sudo ln -s /etc/nginx/sites-available/docker.junecat.ru /etc/nginx/sites-enabled/
уже выполнена ранее, и сайт есть не только в "доступных", но и в "разрешенных".
Как видите, пока никакого https и сертификатов - нет. Они возникнут на
2-й шаг: говорим сертботу получить сертификаты и исправить в соответствии с ними файл nginx'а:
sudo certbot --nginx -d docker.junecat.ru -d www.docker.junecat.ru
Ну, и в заключение - исправленная картинка, как всё сейчас работает (просто чтоы никого не вводить в заблуждение):
Ответы (1 шт):
По умолчанию деректива server создаёт конфигурацию, которая слушает 80-й порт. Чтобы указать порт для сервера, используйте дерективу listen. Если в одном блоке server несколько listen, то созданный сервер будет слушать все указанные порты.
В вашем случае я бы сделал две записи server, одну HTTP для порта 80, вторую STREAM для порта 443 ssl.
Почему stream для 443-го порта. Если делать для этого порта простой блок server, то в него нужно добавлять сертификаты, которые, как вы написали, хранятся в gitlab. Поэтому нужно просто транслировать tcp трафик между внешним портом и портом 8443 gitlab-а. В минимальном варианте это может выглядеть вот так:
stream {
# ...
server {
listen 0.0.0.0:443;
proxy_pass 192.168.0.10:8443;
}
}
При такой настройке весь трафик, идущий на 443-й порт, будет перенаправляться на бэкэнд с адресом 192.168.0.10, порт 8443. Вся обработка TLS/SSL перекладывается на бэкэнд.
Но на самом деле стал бы делать по-другому. Все запросы на 80-й порт я бы перенаправлял на 443-й, а бизнес-логику повесил уже на защищенный порт. То есть я бы забил на возможности gitlab по работе с HTTPS и оставил бы только HTTP.
- Перенаправление всех запросов, вне зависимости от имени, на защищенный порт
server {
listen 80 default_server;
server_name _;
return 301 https://$host$request_uri;
}
- Прокси на защищенном порту (минимальная конфигурация)
server {
listen 443 ssl;
server_name mygitlab.myserver.ru www.mygitlab.myserver.ru;
location / {
proxy_pass http://192.168.0.10:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
ssl_certificate /etc/letsencrypt/live/<server name>/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/<server name>/privkey.pem; # managed by Certbot
}
Сертификаты для защищенного сервера я обычно получаю через certbot. Сертификаты храню на входном сервере, а внутри периметра трафик ходит в открытом виде.
FYI, в сервере, который работает на proxy_pass инструкция index избыточна, ведь все запросы вы перенаправляете в gitlab.

