Как настроить Nginx reverse proxy на Ubuntu
Nginx reverse proxy, он же обратный прокси, принимает запросы на портах 80 и 443 и передаёт их вашему приложению, которое слушает только сам сервер. Так обычно публикуют приложения на Node.js, Python или Go: Nginx берёт на себя HTTPS, медленных клиентов и статику, приложение занимается своим делом. Инструкция для Ubuntu 24.04 с Nginx 1.24, на 22.04 всё так же.
Как направить домен на приложение на порту 3000
Запустите приложение так, чтобы оно слушало 127.0.0.1:3000, а не все адреса: тогда снаружи к нему не попасть в обход Nginx. В Node.js это server.listen(3000, '127.0.0.1'), в Gunicorn и Uvicorn — --bind 127.0.0.1:3000 или --host 127.0.0.1 --port 3000. Если Nginx ещё не стоит, начните с установки Nginx на Ubuntu.
Создайте файл сайта. Вместо app.example.com подставьте свой домен:
sudo nano /etc/nginx/sites-available/app.example.comserver {
listen 80;
listen [::]:80;
server_name app.example.com;
location / {
proxy_pass http://127.0.0.1:3000;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}Включите сайт, проверьте настройки, перечитайте их и запросите страницу:
sudo ln -s /etc/nginx/sites-available/app.example.com /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx
curl -I http://app.example.com/В ответе должны быть статус и заголовки вашего приложения, а сверху — Server: nginx. В proxy_pass пишите 127.0.0.1, а не localhost: имя localhost ведёт ещё и на IPv6-адрес [::1], а приложение, которое слушает только IPv4, такие соединения не примет.
Зачем нужны строки proxy_set_header
Без них приложение видит каждый запрос как пришедший с 127.0.0.1 и не знает ни настоящего домена, ни того, зашёл ли посетитель по HTTPS.
Host $host— домен, который набрал посетитель. Без этой строки Nginx передаёт адрес изproxy_pass, и ссылки, которые строит приложение, ведут на127.0.0.1.X-Real-IP $remote_addr— IP-адрес посетителя.X-Forwarded-For $proxy_add_x_forwarded_for— цепочка адресов, через которые прошёл запрос, с адресом посетителя в конце.X-Forwarded-Proto $scheme—httpилиhttps. По нему приложение строит правильные ссылки и ставит защищённые cookie, когда появится HTTPS.
Доверять этим заголовкам приложение должно только от прокси. В большинстве фреймворков для этого есть настройка: trust proxy в Express, --forwarded-allow-ips в Gunicorn и Uvicorn. В пакете Nginx из Ubuntu есть файл /etc/nginx/proxy_params с теми же четырьмя заголовками, так что их можно заменить строкой include proxy_params;.
Как пропустить WebSocket
WebSocket начинается с обычного запроса с заголовком Upgrade, а его Nginx сам дальше не передаёт. К тому же Nginx 1.24 по умолчанию говорит с приложением по HTTP/1.0, поэтому строка proxy_http_version 1.1 нужна. Сначала добавьте map, который выставит заголовок Connection. Он должен стоять внутри блока http, а все файлы из /etc/nginx/conf.d/ Ubuntu читает как раз там:
sudo nano /etc/nginx/conf.d/websocket.confmap $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}Потом добавьте две строки в location / файла сайта. Целиком блок теперь такой:
location / {
proxy_pass http://127.0.0.1:3000;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
}sudo nginx -t
sudo systemctl reload nginxЕсли по соединению 60 секунд ничего не идёт, Nginx его закрывает (proxy_read_timeout). Для чата или живых обновлений пусть приложение чаще шлёт WebSocket-пинги, либо поднимите proxy_read_timeout в этом location.
Таймауты и ошибка «413 Request Entity Too Large»
По умолчанию Nginx принимает тело запроса до 1 МБ. На файл побольше он отвечает 413 Request Entity Too Large, а в error.log появляется client intended to send too large body. Поднимите client_max_body_size в блоке server до самого большого файла, который ждёте. Три таймаута прокси по умолчанию — по 60 секунд, и считают они паузу между двумя чтениями или записями, а не весь запрос. proxy_read_timeout стоит поднимать, только если приложению правда нужно дольше думать над ответом, например над отчётом или выгрузкой.
client_max_body_size 50m;
location / {
# строки proxy_pass и proxy_set_header из примера выше
proxy_connect_timeout 5s;
proxy_send_timeout 60s;
proxy_read_timeout 120s;
}sudo nginx -t
sudo systemctl reload nginxКороткий proxy_connect_timeout подходит приложению на том же сервере: если за 5 секунд соединиться не вышло, приложение лежит, и посетитель сразу видит ошибку, а не ждёт минуту. Если приложение на PHP, у него свои ограничения на загрузку: как поднять memory_limit и лимиты загрузки в PHP.
Почему Nginx отвечает 502 Bad Gateway
502 значит, что Nginx не дождался ответа от приложения. Причина всегда записана в журнале ошибок, в строке рядом с запросом:
sudo tail -n 20 /var/log/nginx/error.logconnect() failed (111: Connection refused) while connecting to upstream— на этом порту никто не слушает. Проверьте, что приложение запущено и на каком адресе:sudo ss -tlnp | grep 3000Если в журналеupstream: "http://[::1]:3000/", напишите вproxy_pass127.0.0.1вместоlocalhost.upstream prematurely closed connection while reading response header from upstream— приложение упало или оборвало соединение посреди ответа. Смотрите журнал самого приложения, например:journalctl -u <служба приложения> -n 50upstream sent too big header while reading response header from upstream— заголовки ответа не влезают в буфер, обычно из-за большого числа cookie или их размера. Добавьте в locationproxy_buffer_size 16k;иproxy_buffers 8 16k;.upstream timed out (110: Connection timed out) while reading response header from upstream— это уже504 Gateway Time-out, а не 502. Приложение думает дольше, чемproxy_read_timeout. Ускорьте медленный запрос или поднимите таймаут для него.
Если вы работаете и на Mac

Сборка мусора в MacWashing находит кэш всех знакомых ей программ, в том числе спрятанный внутри их данных, а ещё журналы, мусор Xcode и остатки удалённых программ. Она показывает, сколько места занимает каждая находка, и очищает всё за один раз. Всё спорное остаётся без галочки, пока вы не решите.
Бесплатная пробная версия · macOS 14 и новее
Вопросы и ответы
Что такое Nginx reverse proxy?
Это Nginx перед вашим приложением: посетители подключаются к Nginx на портах 80 и 443, а он передаёт каждый запрос приложению на локальный порт и возвращает ответ. Само приложение снаружи закрыто.
Как добавить HTTPS к прокси?
Направьте домен на сервер и запустите Certbot с плагином для Nginx. Он допишет сертификат в тот же файл сайта и не тронет proxy_pass: как получить сертификат Let’s Encrypt через Certbot.
Может ли один Nginx проксировать несколько приложений?
Да. Дайте каждому приложению свой порт и свой файл сайта со своим server_name. Или один домен с несколькими блоками location, у каждого свой proxy_pass.