Когда на одном сервере работают несколько приложений — веб-сайт, API, микросервис — они не могут слушать один и тот же порт 80 или 443. Решение: поместить перед ними обратный прокси, который распределяет входящие запросы по приложениям. Nginx для этого идеален: он лёгкий, быстрый и справляется с тысячами одновременных подключений. В этом руководстве разберём, как настроить Nginx reverse proxy для нескольких приложений на одном VPS, обезопасить их SSL/TLS и автоматизировать отказоустойчивость.
Зачем нужен reverse proxy
На типовом VPS вы часто запускаете несколько сервисов одновременно: веб-приложение на порту 3000, API на 8000, статический блог на 5000. Напрямую отправлять пользователей на разные порты неудобно и небезопасно. Reverse proxy (обратный прокси) решает три задачи сразу.
Первое: единая точка входа. Пользователь обращается к example.com, не зная и не заботясь о том, какой порт слушает приложение внутри сервера. Nginx получает запрос на порту 80 или 443, парсит Host и URL, и перенаправляет запрос на нужное приложение.
Второе: безопасность. Приложения можно запустить на localhost (127.0.0.1), закрыв их от прямого доступа из интернета. Nginx слушает внешние порты, проверяет запросы, фильтрует вредоносный трафик. Если одно приложение скомпрометировано, атакующий всё равно не сможет напрямую обратиться к другим.
Для сайтов, ботов и pet-проектов можно использовать Beget: виртуальный хостинг от 420 ₽/мес., VPS от 330 ₽/мес. и тестовый период.
Третье: масштабирование. Если одно приложение часто перегружается, можно запустить несколько копий на разных портах и настроить Nginx балансировать нагрузку между ними. Пользователи не заметят никакой разницы.
Типовая архитектура
Представьте себе такую схему:
Internet (users on port 80, 443)
|
Nginx reverse proxy
(listens on 80, 443)
|
+----+----+----+
| | | |
App1 App2 App3 App4
:3000 :8000 :5000 :9000
(localhost)
Каждое приложение слушает только localhost на своём порту. Nginx перенаправляет запросы по хостнейму или пути URL. Например:
api.example.com→ приложение на :8000blog.example.com→ приложение на :5000example.com/admin→ приложение на :9000example.com/→ приложение на :3000
Установка и первый запуск Nginx
На Debian/Ubuntu установка стандартна:
sudo apt update
sudo apt install nginx
На CentOS/RHEL:
sudo yum install -y nginx
sudo systemctl enable nginx
sudo systemctl start nginx
Проверьте, что Nginx запустился и слушает порт 80:
sudo systemctl status nginx
sudo ss -ltnp | grep nginx
Базовая конфигурация: один upstream, один сервер
Конфигурация Nginx обычно находится в /etc/nginx/nginx.conf или в отдельных файлах в /etc/nginx/sites-enabled/ (Debian) или /etc/nginx/conf.d/ (RHEL). Создадим файл /etc/nginx/sites-available/example.com:
sudo nano /etc/nginx/sites-available/example.com
Вставим базовую конфигурацию:
upstream app_backend {
server 127.0.0.1:3000;
}
server {
listen 80;
listen [::]:80;
server_name example.com www.example.com;
location / {
proxy_pass http://app_backend;
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;
}
}
Что здесь происходит:
upstream app_backend— группа серверов, на которые проксировать запросы. Здесь одна копия приложения на :3000.serverблок — настройки для доменов example.com и www.example.com.listen 80— Nginx слушает HTTP на порту 80.location /— для всех путей перенаправлять на upstream.proxy_set_header— передавать исходные заголовки приложению, чтобы оно знало настоящий IP пользователя и схему (HTTP/HTTPS).
Активируем конфигурацию и перезагружаем Nginx:
sudo ln -s /etc/nginx/sites-available/example.com \
/etc/nginx/sites-enabled/example.com
sudo nginx -t
sudo systemctl reload nginx
nginx -t проверяет синтаксис: если есть ошибка, команда выведет её и не перезагрузит Nginx, чтобы не сломать живую конфигурацию.
Несколько приложений на разных портах
Теперь усложним. У вас есть:
- Веб-приложение на :3000
- REST API на :8000
- Статический блог на :5000
Определим три upstream блока и один server блок с несколькими location:
upstream web_app {
server 127.0.0.1:3000;
}
upstream api_backend {
server 127.0.0.1:8000;
}
upstream blog_app {
server 127.0.0.1:5000;
}
server {
listen 80;
listen [::]:80;
server_name example.com www.example.com;
# Основной сайт
location / {
proxy_pass http://web_app;
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;
}
# REST API
location /api/ {
proxy_pass http://api_backend;
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;
}
# Статический блог
location /blog/ {
proxy_pass http://blog_app;
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;
}
}
Несколько приложений на разных доменах
Если приложения работают на отдельных поддоменах, структура тоже простая:
upstream web_app {
server 127.0.0.1:3000;
}
upstream api_server {
server 127.0.0.1:8000;
}
upstream admin_panel {
server 127.0.0.1:9000;
}
# Основной домен
server {
listen 80;
listen [::]:80;
server_name example.com www.example.com;
location / {
proxy_pass http://web_app;
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;
}
}
# API поддомен
server {
listen 80;
listen [::]:80;
server_name api.example.com;
location / {
proxy_pass http://api_server;
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;
}
}
# Admin панель
server {
listen 80;
listen [::]:80;
server_name admin.example.com;
location / {
proxy_pass http://admin_panel;
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;
}
}
SSL/TLS и HTTPS
Пользователи должны обращаться к вашим приложениям через HTTPS. Используем Let’s Encrypt и certbot для автоматического получения сертификата:
sudo apt install -y certbot python3-certbot-nginx
sudo certbot certonly --nginx -d example.com -d www.example.com -d api.example.com
Затем обновляем конфигурацию Nginx, добавляя HTTPS блоки и редирект с HTTP:
upstream web_app {
server 127.0.0.1:3000;
}
# HTTP редирект на HTTPS
server {
listen 80;
listen [::]:80;
server_name example.com www.example.com api.example.com;
return 301 https://$server_name$request_uri;
}
# HTTPS
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name example.com www.example.com;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;
location / {
proxy_pass http://web_app;
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;
}
}
Балансировка нагрузки между несколькими копиями приложения
Если одно приложение часто перегружается, запустите его на нескольких портах и дайте Nginx балансировать:
upstream web_app_pool {
server 127.0.0.1:3000 weight=1;
server 127.0.0.1:3001 weight=1;
server 127.0.0.1:3002 weight=1;
}
server {
listen 443 ssl http2;
server_name example.com;
location / {
proxy_pass http://web_app_pool;
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;
}
}
weight=1 означает, что все три копии получают поровну запросов. Если одна копия мощнее, можно установить weight=2. Методы распределения: round-robin (по умолчанию), least-conn (к с наименьшим числом подключений), ip-hash (по IP пользователя) и другие.
Проверка здоровья приложений (health checks)
Если одно приложение зависает или рушится, Nginx должен понимать это и перестать отправлять туда запросы. В коммерческой версии (Nginx Plus) это встроено, но в открытом исходнике можно использовать модуль lua или внешний мониторинг:
upstream web_app_pool {
server 127.0.0.1:3000 max_fails=3 fail_timeout=30s;
server 127.0.0.1:3001 max_fails=3 fail_timeout=30s;
server 127.0.0.1:3002 max_fails=3 fail_timeout=30s;
}
server {
listen 443 ssl http2;
server_name example.com;
location / {
proxy_pass http://web_app_pool;
proxy_connect_timeout 3s;
proxy_read_timeout 5s;
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;
}
}
max_fails=3 означает, что после трёх неудачных попыток Nginx будет считать этот сервер недоступным на 30 секунд (fail_timeout). proxy_connect_timeout и proxy_read_timeout — сколько секунд ждать ответа приложения до отката на следующий сервер.
Логирование и отладка
Настройте подробные логи для отладки проблем с проксированием:
server {
listen 443 ssl http2;
server_name example.com;
access_log /var/log/nginx/example.com.access.log;
error_log /var/log/nginx/example.com.error.log warn;
location / {
proxy_pass http://web_app;
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 tail -f /var/log/nginx/example.com.access.log
sudo journalctl -u nginx -f
Оптимизация производительности
Для высоконагруженных систем добавьте кэширование и буферизацию:
http {
# Кэш результатов проксирования
proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=cache_zone:10m;
upstream web_app {
server 127.0.0.1:3000;
}
server {
listen 443 ssl http2;
server_name example.com;
location / {
proxy_pass http://web_app;
proxy_cache cache_zone;
proxy_cache_valid 200 10m;
proxy_cache_valid 404 5m;
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;
}
}
}
Типичные ошибки и их решение
Ошибка 1: 502 Bad Gateway. Nginx не может подключиться к приложению. Проверьте, запущено ли оно и слушает ли нужный порт: sudo ss -ltnp | grep :3000. Убедитесь, что приложение слушает 127.0.0.1, а не только 0.0.0.0.
Ошибка 2: неправильный Host в приложении. Если приложение видит Host = localhost вместо example.com, добавьте proxy_set_header Host $host;. Убедитесь, что приложение не переопределяет Host самостоятельно.
Ошибка 3: CORS ошибки при обращении к API с клиента. Убедитесь, что API приложение отправляет правильные CORS заголовки (Access-Control-Allow-Origin). Если используете поддомены (api.example.com), убедитесь, что приложение знает о них.
Ошибка 4: потеря реального IP пользователя. Приложение видит IP самого Nginx (127.0.0.1). Добавьте в конфигурацию приложения парсинг заголовка X-Real-IP или X-Forwarded-For. В Node.js это часто работает автоматически через trust proxy middleware.
Использование генератора Nginx на prizraks.ru
На нашем сайте есть инструмент для генерации конфигурации Nginx reverse proxy. Используйте его для быстрого создания блоков upstream и server, особенно если у вас много приложений. Генератор учитывает все правильные заголовки и настройки безопасности.
Заключение
Nginx reverse proxy — это стандартный способ организовать несколько приложений на одном VPS. Он обеспечивает единую точку входа, безопасность и масштабируемость. Начните с простой конфигурации, проверьте логи, добавьте SSL/TLS, потом масштабируйте с балансировкой нагрузки и кэшированием.
Если вам нужна помощь с настройкой сложной архитектуры на VPS — например, много микросервисов, Docker контейнеры или Kubernetes — свяжитесь с нами для консультации по настройке VPS на Beget и оптимизации вашей инфраструктуры.
Подборка онлайн-курсов для разработчиков — Python, Java, веб и DevOps.
14 практических страниц: SSH, firewall, обновления, резервные копии, WordPress, Docker и действия при признаках взлома.
Проверим SSH, firewall, обновления, резервные копии, Docker и журналы. Аудит — от 9 900 ₽.
Статья может содержать партнёрские ссылки. Это не влияет на стоимость для вас, но помогает развивать блог.

