PurpleSchool — курсы программирования онлайн
  • Пути
    • Frontend React разработчик
    • Frontend Vue разработчик
    • Backend разработчик Node.js
    • Fullstack разработчик React / Node.js
    • Mobile разработчик React Native
    • Backend разработчик Golang
    • Devops инженер
    • Backend разработчик Python
  • AI для кодаНовое
  • О нас
    • Отзывы
    • Реферальная программа
    • О компании
    • Контакты
  • Иконка открытия меню
    • Сообщество
    • PurpleПлюс
    • AI Собеседование
    • AI тренажёр
    • Проекты
PurpleSchool — платформа бесплатных roadmap и курсов для разработчиков
ютуб иконка
Telegram иконка
VK иконка
VK иконка
Курсы
ГлавнаяКаталог курсовFrontendBackendFullstack
Практика
КарьераПроектыPurpleПлюс
Материалы
БлогБаза знаний
Документы
Договор офертаПолитика конфиденциальностиПроверка сертификатаМиграция курсовРеферальная программа
Реквизиты
ИП Ларичев Антон АндреевичИНН 773373765379contact@purpleschool.ru

PurpleSchool © 2020 -2026 Все права защищены

  • Курсы
    • FrontendИконка стрелки
    • AI разработкаИконка стрелки
    • BackendИконка стрелки
    • DevOpsИконка стрелки
    • MobileИконка стрелки
    • ТестированиеИконка стрелки
    • Soft-skillsИконка стрелки
    • ДизайнИконка стрелки
    Иконка слояПерейти в каталог курсов
  • Бесплатно
    • Курсы
    • JavaScript Основы разработкиPython Основы PythonCSS CSS FlexboxКарта развитияВопросы для собеседований
    • База знанийИконка стрелки
    • Новостные рассылкиИконка стрелки
  • PurpleSchool — курсы программирования онлайн
    • AI для кодаНовое
    • Сообщество
    • PurpleПлюс
    • AI Собеседование
    • AI тренажёр
    • Проекты
    Главная
    Сообщество
    Nginx как reverse proxy для Node.js: настройка за 30 минут

    Nginx как reverse proxy для Node.js: настройка за 30 минут

    Аватар автора Nginx как reverse proxy для Node.js: настройка за 30 минут

    Антон Ларичев

    Иконка календаря17 июня 2026
    nginxnodejsdevopsreverse-proxydeploymentmiddleИконка уровня middle
    Картинка поста Nginx как reverse proxy для Node.js: настройка за 30 минут

    Введение

    Node.js отлично справляется с обработкой запросов, но запускать его в продакшене напрямую — плохая идея. Прямой запуск на 80 или 443 порту требует прав root, не даёт нормально терминировать SSL, отдавать статику и балансировать нагрузку между несколькими инстансами. Решение — поставить перед Node.js обратный прокси-сервер Nginx.

    Nginx возьмёт на себя SSL, gzip-сжатие, отдачу статики, лимиты соединений и кэширование. А приложение на Node.js сосредоточится только на бизнес-логике. В этой статье разберём базовую настройку, балансировку нагрузки, проксирование WebSocket и типичные грабли.

    Зачем вообще нужен reverse proxy

    Reverse proxy принимает запросы от клиентов и перенаправляет их на внутренние сервисы. В отличие от обычного прокси он защищает не клиента, а сервер. Преимущества такого подхода:

    • Один публичный порт (443) для нескольких приложений
    • SSL-терминация в одном месте
    • Балансировка нагрузки между инстансами Node.js
    • Защита от медленных клиентов (slowloris-атаки)
    • Кэширование и отдача статики на уровне C, а не JavaScript

    Node.js при этом слушает локальный порт вроде 3000, и снаружи он недоступен.

    Установка и базовая конфигурация

    Ставим Nginx на Ubuntu или Debian:

    sudo apt update
    sudo apt install nginx
    sudo systemctl enable --now nginx
    

    Конфиги сайтов лежат в /etc/nginx/sites-available/, а активируются симлинком в /etc/nginx/sites-enabled/. Создаём файл /etc/nginx/sites-available/app.conf:

    server {
        listen 80;
        server_name example.com www.example.com;
    
        location / {
            # Проксируем все запросы на Node.js, который слушает localhost:3000
            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;
    
            # Таймауты на чтение и подключение к upstream
            proxy_connect_timeout 5s;
            proxy_read_timeout 60s;
        }
    }
    

    Активируем сайт и проверяем конфигурацию:

    sudo ln -s /etc/nginx/sites-available/app.conf /etc/nginx/sites-enabled/
    sudo nginx -t
    sudo systemctl reload nginx
    

    Команда nginx -t проверит синтаксис до перезагрузки — это спасёт от падения сервера в проде.

    Доверие к заголовкам в Express

    Если в приложении используется Express, нужно сказать ему доверять прокси, иначе req.ip будет возвращать 127.0.0.1:

    const express = require('express');
    const app = express();
    
    // Доверяем первому прокси — Nginx на той же машине
    app.set('trust proxy', 'loopback');
    
    app.get('/', (req, res) => {
        // Теперь здесь будет реальный IP клиента из X-Forwarded-For
        res.send(`Ваш IP: ${req.ip}`);
    });
    
    app.listen(3000, '127.0.0.1');
    

    Обратите внимание на 127.0.0.1 в listen — приложение принципиально не слушает внешний интерфейс.

    SSL через Let's Encrypt

    Для HTTPS используем certbot — он сам выпустит сертификат и поправит конфиг Nginx:

    sudo apt install certbot python3-certbot-nginx
    sudo certbot --nginx -d example.com -d www.example.com
    

    Certbot добавит блок listen 443 ssl и редирект с HTTP на HTTPS. Автообновление настраивается через systemd-таймер, ничего делать не надо.

    Балансировка нескольких инстансов

    Node.js однопоточный, поэтому для использования всех ядер запускают несколько процессов на разных портах. Nginx распределит между ними нагрузку через директиву upstream:

    upstream node_backend {
        # least_conn отправит запрос на инстанс с минимальным числом активных соединений
        least_conn;
    
        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;
    
        # Держим до 32 keepalive-соединений к каждому бэкенду
        keepalive 32;
    }
    
    server {
        listen 443 ssl http2;
        server_name example.com;
    
        location / {
            proxy_pass http://node_backend;
            proxy_http_version 1.1;
            # Пустой Connection нужен для работы keepalive с upstream
            proxy_set_header Connection "";
            proxy_set_header Host $host;
        }
    }
    

    Алгоритм least_conn лучше дефолтного round-robin для долгих запросов. Если у вас сессии в памяти процесса — добавьте ip_hash, чтобы клиент всегда попадал на тот же инстанс.

    Отдача статики и WebSocket

    Node.js не должен отдавать CSS, JS и картинки — это работа Nginx:

    location /static/ {
        alias /var/www/app/public/;
        # Кэшируем статику в браузере на год
        expires 1y;
        add_header Cache-Control "public, immutable";
    }
    
    location /ws {
        proxy_pass http://node_backend;
        proxy_http_version 1.1;
        # Обязательные заголовки для апгрейда соединения до WebSocket
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        # WebSocket может висеть долго — увеличиваем таймаут
        proxy_read_timeout 3600s;
    }
    

    Частые ошибки

    502 Bad Gateway. Nginx не может достучаться до upstream. Проверьте, что Node.js действительно запущен и слушает указанный порт: ss -tlnp | grep 3000. Часто причина в SELinux или AppArmor, которые блокируют исходящие соединения от Nginx.

    Реальный IP теряется. Без X-Forwarded-For и trust proxy приложение видит только IP Nginx. Это ломает rate limiting и аналитику.

    WebSocket рвётся через минуту. Дефолтный proxy_read_timeout — 60 секунд. Если соединение неактивно, Nginx его закроет. Поднимайте таймаут или настройте ping-pong со стороны приложения.

    Большие загрузки падают с 413. Лимит на размер тела запроса по умолчанию 1 МБ. Добавьте client_max_body_size 50M; в нужный server или location.

    Бесконечный редирект на HTTPS. Если за Nginx стоит ещё один прокси или CDN, приложение может не понимать, что соединение уже зашифровано. Проверяйте X-Forwarded-Proto и доверяйте ему в коде.

    Утечка соединений к upstream. Без keepalive в upstream и пустого заголовка Connection Nginx открывает новое TCP-соединение на каждый запрос. На высокой нагрузке это съедает порты.

    Заключение

    Nginx перед Node.js — стандарт для продакшен-деплоя. Получасовая настройка даёт SSL, балансировку, защиту от примитивных атак и быструю отдачу статики практически бесплатно по ресурсам. Главное — не забыть про trust proxy в приложении, корректно прокинуть заголовки и поднять таймауты для WebSocket. Дальше можно идти в сторону кэширования ответов API через proxy_cache, rate limiting через limit_req_zone и вынесения Nginx на отдельную машину перед кластером бэкендов.

    Иконка глаза3

    Комментарии

    0

    Постройте личный план изучения Next.js 15 - с нуля, React TypeScript, Hooks, SSR и CSS Grid до уровня Middle — бесплатно!

    Next.js 15 - с нуля, React TypeScript, Hooks, SSR и CSS Grid — часть карты развития Frontend

    • step100+ шагов развития
    • lessons30 бесплатных лекций
    • lessons300 бонусных рублей на счет

    Бесплатные лекции

    Лучшие курсы по теме

    изображение курса

    Vue 3 и Pinia

    Антон Ларичев
    AI-тренажерыAI-тренажеры
    Практика в студииПрактика в студии
    Гарантия
    Бонусы
    иконка звёздочки рейтинга4.8
    3 999 ₽ 6 990 ₽
    Подробнее
    изображение курса

    Nuxt

    Антон Ларичев
    AI-тренажерыAI-тренажеры
    Практика в студииПрактика в студии
    Гарантия
    Бонусы
    иконка звёздочки рейтинга5.0
    3 999 ₽ 6 990 ₽
    Подробнее
    изображение курса

    Feature-Sliced Design

    Антон Ларичев
    AI-тренажерыAI-тренажеры
    Практика в студииПрактика в студии
    Гарантия
    Бонусы
    иконка звёздочки рейтинга4.5
    3 999 ₽ 6 990 ₽
    Подробнее

    Похожие статьи

    Картинка поста Docker для разработчика: полный гайд с нуля до продакшена
    Иконка аватараАнтон
    Иконка календаря03 июня 2026
    dockerdevopsконтейнеризация+ 1juniorИконка уровня junior

    Docker для разработчика: полный гайд с нуля до продакшена

    Docker для разработчика — полный гайд с нуля: образы, контейнеры, Dockerfile, docker-compose и работа с продакшеном простыми словами.

    Иконка чипа0
    Иконка глаза295
    Иконка комментариев0
    Картинка поста Как перейти с Junior на Middle разработчика: план роста
    Иконка аватараАнтон
    Иконка календаря16 июня 2026
    карьераразвитиеjunior+ 2juniorИконка уровня junior

    Как перейти с Junior на Middle разработчика: план роста

    Переход с Junior на Middle разработчика: конкретный план развития hard и soft skills, чек-листы навыков и примеры задач для роста.

    Иконка чипа0
    Иконка глаза56
    Иконка комментариев0
    Картинка поста Оптимизация производительности React: memo, lazy, Suspense, Profiler
    Иконка аватараАнтон
    Иконка календаря15 июня 2026
    ReactPerformanceOptimization+ 1middleИконка уровня middle

    Оптимизация производительности React: memo, lazy, Suspense, Profiler

    Оптимизация производительности React приложений с помощью memo, lazy, Suspense и Profiler. Разбираем мемоизацию, ленивую загрузку и профилирование рендеров.

    Иконка чипа0
    Иконка глаза91
    Иконка комментариев0
    Иконка чипа0