Защита n8n с помощью reverse proxy Nginx, TLS и заголовков безопасности

11 мин чтения·Matthieu·webhookssecuritylets-encryptreverse-proxynginxn8n|

Разместите свой self-hosted экземпляр n8n за Nginx с TLS от Let's Encrypt, заголовками безопасности, ограничением частоты запросов, правилами файрвола и защитой вебхуков. Каждый шаг включает команду проверки.

Это руководство размещает твой self-hosted экземпляр n8n за Nginx с TLS, заголовками безопасности, ограничением частоты запросов и правилами файрвола. Ты перейдёшь от n8n, открытого на порту 5678, к конфигурации, готовой к продакшену, где только HTTPS-трафик достигает редактора и вебхуков.

Предварительные требования:

  • n8n, запущенный через Docker Compose на VPS ()
  • Доменное имя (например, n8n.example.com) с A-записью, указывающей на IP твоего сервера
  • SSH-доступ к серверу под непривилегированным пользователем с sudo
  • Порты 80 и 443 открыты в файрволе хостинг-провайдера (Virtua Cloud открывает их по умолчанию)

Руководство написано для Ubuntu 24.04 LTS. Команды работают на Debian 12 с небольшими изменениями. Везде используется n8n версии 2.x.

Как настроить Nginx в качестве reverse proxy для n8n с поддержкой WebSocket?

Nginx стоит между интернетом и n8n, перенаправляя запросы на localhost:5678. Редактор n8n использует WebSocket-соединения для обновлений в реальном времени. Без правильного проксирования WebSocket интерфейс редактора зависает и показывает «Connection lost». Нужны proxy_pass на localhost:5678, заголовки upgrade HTTP/1.1 для WebSocket и переменная окружения N8N_PROXY_HOPS=1, чтобы n8n читал реальный IP клиента из X-Forwarded-For.

Установка Nginx

sudo apt update && sudo apt install -y nginx

Проверь, что Nginx запущен:

sudo systemctl status nginx

Ты должен увидеть active (running) зелёным цветом. Если нет, запусти и включи:

sudo systemctl enable --now nginx

Флаг enable --now делает две вещи: enable настраивает автозапуск Nginx после перезагрузки, а --now запускает его сразу.

Создание серверного блока Nginx

Создай новый файл конфигурации для домена n8n:

sudo nano /etc/nginx/sites-available/n8n.example.com

Вставь эту конфигурацию. Замени n8n.example.com на свой домен:

map $http_upgrade $connection_upgrade {
    default upgrade;
    ''      close;
}

server {
    listen 80;
    listen [::]:80;
    server_name n8n.example.com;

    # Will be replaced by Certbot later
    location / {
        proxy_pass http://127.0.0.1:5678;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection $connection_upgrade;
        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_buffering off;
        proxy_cache off;
        chunked_transfer_encoding off;
    }
}

Блок map в начале обрабатывает WebSocket-апгрейды. Когда браузер отправляет заголовок Upgrade: websocket, Nginx пропускает его. Для обычных HTTP-запросов отправляется close. Это поддерживает отзывчивость редактора n8n.

proxy_buffering off и proxy_cache off не дают Nginx буферизировать server-sent events от n8n, что вызвало бы задержки в редакторе.

Включи сайт и проверь конфигурацию:

sudo ln -s /etc/nginx/sites-available/n8n.example.com /etc/nginx/sites-enabled/
sudo nginx -t

Ты должен увидеть:

nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful

Если тест пройден, перезагрузи:

sudo systemctl reload nginx

Проверь, что n8n доступен через Nginx:

curl -s -o /dev/null -w "%{http_code}" http://n8n.example.com

Ответ 200 означает, что Nginx проксирует трафик в n8n. 502 означает, что n8n не запущен на порту 5678. Проверь командой docker ps.

Обновление переменных окружения n8n

Открой файл .env для n8n (в том же каталоге, что и docker-compose.yml):

nano ~/n8n-docker/.env

Добавь или обнови эти переменные:

N8N_HOST=n8n.example.com
N8N_PROTOCOL=https
N8N_PROXY_HOPS=1
WEBHOOK_URL=https://n8n.example.com/
N8N_EDITOR_BASE_URL=https://n8n.example.com/
N8N_SECURE_COOKIE=true

Что делает каждая переменная:

Переменная Значение Назначение
N8N_HOST Твой домен Указывает n8n, какой хост использовать в URL вебхуков
N8N_PROTOCOL https n8n генерирует HTTPS URL вебхуков вместо HTTP
N8N_PROXY_HOPS 1 n8n доверяет одному уровню X-Forwarded-For для получения реального IP клиента
WEBHOOK_URL Полный URL Перезаписывает автоматически сгенерированный базовый URL вебхуков
N8N_EDITOR_BASE_URL Полный URL URL для email-уведомлений и SAML-редиректов
N8N_SECURE_COOKIE true Куки отправляются только по HTTPS. Предотвращает перехват сессии по незашифрованному HTTP

Перезапусти n8n для применения изменений:

cd ~/n8n-docker && docker compose down && docker compose up -d

Проверь, что n8n загрузил новые переменные окружения:

docker compose logs --tail=20 n8n | grep -i "editor\|webhook\|proxy"

В логах должны быть строки с твоим доменом и протоколом HTTPS.

Как добавить TLS Let's Encrypt к reverse proxy для n8n?

Certbot автоматизирует выпуск сертификатов Let's Encrypt и автоматически настраивает Nginx для TLS. После запуска Certbot весь HTTP-трафик перенаправляется на HTTPS, а редактор n8n и вебхуки шифруются при передаче.

Установка Certbot

sudo apt install -y certbot python3-certbot-nginx

Получение сертификата

sudo certbot --nginx -d n8n.example.com

Certbot выполнит:

  1. Подтверждение владения доменом через HTTP-01 challenge
  2. Получение сертификата от Let's Encrypt
  3. Изменение конфигурации Nginx для добавления настроек TLS и редиректа HTTP-на-HTTPS

Когда запросят email, введи настоящий адрес. Туда придут предупреждения о неудачных продлениях.

Проверка работы TLS

curl -I https://n8n.example.com

Ищи HTTP/2 200 в ответе. Если видишь ошибку сертификата, подожди несколько минут для распространения DNS.

Проверь цепочку сертификатов с локальной машины (не с сервера):

openssl s_client -connect n8n.example.com:443 -servername n8n.example.com </dev/null 2>/dev/null | head -20

Ищи Verify return code: 0 (ok).

Проверка автоматического продления

Certbot устанавливает таймер systemd, который продлевает сертификаты до истечения срока. Убедись, что он активен:

sudo systemctl status certbot.timer

Ты должен увидеть active (waiting). Протестируй процесс продления без реального продления:

sudo certbot renew --dry-run

Успешный dry run означает, что сертификаты будут продлеваться автоматически каждые 60-90 дней.

Какие заголовки безопасности нужны n8n в продакшене?

Заголовки безопасности указывают браузерам, как обрабатывать контент твоего сайта. Без них редактор n8n уязвим для кликджекинга (clickjacking), атак с подменой MIME-типов и межсайтового скриптинга. Добавь шесть заголовков в конфигурацию Nginx, чтобы закрыть эти уязвимости.

Открой конфигурацию Nginx, которую изменил Certbot:

sudo nano /etc/nginx/sites-available/n8n.example.com

Внутри блока server, который слушает порт 443 (созданного Certbot), добавь эти заголовки над блоком location /:

    # Security headers
    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
    add_header X-Frame-Options "DENY" always;
    add_header X-Content-Type-Options "nosniff" always;
    add_header Referrer-Policy "strict-origin-when-cross-origin" always;
    add_header Permissions-Policy "camera=(), microphone=(), geolocation=()" always;
    add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self' data:; connect-src 'self' wss://n8n.example.com; frame-ancestors 'none'" always;

Замени n8n.example.com в директиве CSP connect-src на свой домен. Запись wss:// разрешает WebSocket-соединения к редактору.

Что делает каждый заголовок:

Заголовок Значение Что предотвращает
Strict-Transport-Security 1 год, поддомены Браузер всегда использует HTTPS. Блокирует атаки SSL stripping
X-Frame-Options DENY Никто не может встроить редактор n8n в iframe. Блокирует кликджекинг
X-Content-Type-Options nosniff Браузер доверяет объявленному MIME-типу. Блокирует атаки с подменой MIME
Referrer-Policy strict-origin-when-cross-origin Ограничивает информацию о реферере, передаваемую внешним сайтам
Permissions-Policy Запрет камеры, микрофона, геолокации Браузер блокирует доступ к аппаратным API, которые n8n не использует
Content-Security-Policy См. выше Контролирует, какие скрипты, стили и соединения разрешает браузер

Заголовок CSP — самый сложный. Редактор n8n использует inline-скрипты и eval() для конструктора воркфлоу, поэтому 'unsafe-inline' и 'unsafe-eval' необходимы для script-src. Это известный компромисс. Остальные директивы ограничительные: только ресурсы того же происхождения и WebSocket-соединения к твоему домену.

Проверь и перезагрузи:

sudo nginx -t && sudo systemctl reload nginx

Проверь наличие заголовков:

curl -sI https://n8n.example.com | grep -iE "strict-transport|x-frame|x-content|referrer|permissions|content-security"

В выводе должны быть все шесть заголовков. Если какого-то нет, проверь конфигурационный файл на опечатки.

Как настроить файрвол для n8n на VPS?

UFW блокирует весь трафик, кроме явно разрешённого. Для n8n за Nginx нужны только три открытых порта: 22 (SSH), 80 (HTTP, для продления Certbot и редиректов) и 443 (HTTPS). Порт 5678, на котором n8n слушает напрямую, должен быть заблокирован снаружи. Многие руководства пропускают этот шаг, оставляя n8n доступным без TLS.

Подробнее о UFW читай в .

sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow 22/tcp comment 'SSH'
sudo ufw allow 80/tcp comment 'HTTP - Certbot renewal'
sudo ufw allow 443/tcp comment 'HTTPS - n8n via Nginx'
sudo ufw enable

При запросе подтверждения введи y. Проверь правила:

sudo ufw status verbose

Ты должен увидеть три правила ALLOW для портов 22, 80 и 443. Больше ничего. Порта 5678 в списке нет — значит, он заблокирован.

Убедись, что n8n недоступен напрямую. С локальной машины:

curl -s --connect-timeout 3 http://n8n.example.com:5678 || echo "Connection refused - correct!"

Если получишь «Connection refused» или таймаут — файрвол работает. Если получишь ответ от n8n — скорее всего, Docker обходит UFW. Docker модифицирует iptables напрямую и может переопределить правила UFW.

Привязка n8n к localhost и предотвращение обхода UFW Docker'ом

Самый простой вариант — привязать n8n только к localhost. В docker-compose.yml измени маппинг портов:

    ports:
      - "127.0.0.1:5678:5678"

Это гарантирует, что n8n принимает соединения только с той же машины. Nginx на том же сервере может к нему обращаться, а внешний трафик — нет.

Перезапусти n8n:

cd ~/n8n-docker && docker compose down && docker compose up -d

Если одного этого недостаточно (проверь снова curl с локальной машины), можно также отключить управление iptables в Docker. Отредактируй /etc/docker/daemon.json:

sudo nano /etc/docker/daemon.json

Добавь:

{
  "iptables": false
}

Затем перезапусти Docker:

sudo systemctl restart docker
cd ~/n8n-docker && docker compose up -d

Предупреждение: установка "iptables": false запрещает Docker создавать правила NAT и форвардинга. Это может сломать межконтейнерное взаимодействие и исходящий доступ в интернет из контейнеров. Если твои воркфлоу n8n отправляют HTTP-запросы к внешним API (большинство так делают), проверь исходящую связность после этого изменения. Привязки к localhost обычно достаточно.

Снова проверь с локальной машины, что порт 5678 недоступен.

Как ограничить частоту запросов к вебхук-эндпоинтам n8n в Nginx?

Rate limiting защищает вебхук-эндпоинты от злоупотреблений и DoS-атак. Ты задаёшь частоту запросов на IP-адрес. Легитимные интеграции (GitHub, Stripe) отправляют вебхуки с предсказуемой частотой. Атакующий, бомбящий URL вебхука, получает ответ 429 Too Many Requests вместо срабатывания воркфлоу.

Подробнее о стратегиях rate limiting читай в .

Добавь директиву limit_req_zone в начало конфигурационного файла Nginx, за пределами любого блока server, рядом с существующей директивой map:

limit_req_zone $binary_remote_addr zone=webhooks:10m rate=10r/s;
limit_req_zone $binary_remote_addr zone=editor:10m rate=30r/s;

Это создаёт две зоны:

  • webhooks: 10 запросов в секунду на IP. Обрабатывает callback'и от внешних сервисов.
  • editor: 30 запросов в секунду на IP. Редактор делает много мелких API-вызовов, поэтому ему нужен лимит повыше.

Внутри блока server, слушающего на 443, добавь отдельный блок location для путей вебхуков перед основным location /:

    # Rate limit webhook endpoints
    location /webhook/ {
        limit_req zone=webhooks burst=20 nodelay;
        limit_req_status 429;

        proxy_pass http://127.0.0.1:5678;
        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;

        # Generous timeout for long-running webhook workflows
        proxy_read_timeout 300s;
        proxy_send_timeout 300s;
    }

    location /webhook-test/ {
        limit_req zone=webhooks burst=5 nodelay;
        limit_req_status 429;

        proxy_pass http://127.0.0.1:5678;
        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;
    }

Параметр burst=20 разрешает кратковременные всплески до 20 запросов, прежде чем сработает ограничение. Это покрывает случаи, когда GitHub отправляет несколько webhook-событий от одного push. nodelay обрабатывает burst-запросы немедленно, а не ставит в очередь.

В основном блоке location / добавь ограничение для редактора:

    location / {
        limit_req zone=editor burst=50 nodelay;
        limit_req_status 429;

        # ... existing proxy settings ...
    }

Проверь и перезагрузи:

sudo nginx -t && sudo systemctl reload nginx

Проверь работу rate limiting, отправив серию запросов на тестовый вебхук:

for i in $(seq 1 30); do
    curl -s -o /dev/null -w "%{http_code} " https://n8n.example.com/webhook/test-rate-limit
done
echo

Ты должен увидеть смесь ответов 404 (путь вебхука не существует, и это нормально) и 429, когда сработает ограничение.

Как ограничить доступ к редактору n8n по IP-адресам?

По умолчанию любой, кто знает URL твоего n8n, может открыть страницу логина. Белый список IP на уровне Nginx добавляет защитный слой перед собственной аутентификацией n8n. Только запросы с твоего IP (или VPN) достигают редактора. Вебхук-эндпоинты остаются открытыми для интернета, чтобы внешние сервисы могли их вызывать.

Добавь новый блок location для путей редактора. Размести его после location'ов вебхуков и перед основным location /:

    # Restrict editor/API access to specific IPs
    location /rest/ {
        allow 203.0.113.50;   # Your office/home IP
        allow 10.0.0.0/8;     # Your VPN range
        deny all;

        limit_req zone=editor burst=50 nodelay;

        proxy_pass http://127.0.0.1:5678;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection $connection_upgrade;
        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_buffering off;
    }

Замени 203.0.113.50 на свой IP. Узнай его командой:

curl -4 ifconfig.me

Путь /rest/ обрабатывает API-вызовы редактора n8n. Основной location / по-прежнему обслуживает фронтенд редактора и вебхуки. Для более строгой блокировки можно также ограничить корневой путь и добавить отдельные открытые location'ы только для /webhook/ и /webhook-test/.

Проверь и перезагрузи:

sudo nginx -t && sudo systemctl reload nginx

Проверь с разрешённого IP:

curl -s -o /dev/null -w "%{http_code}" https://n8n.example.com/rest/settings

200 означает, что доступ есть. С другого IP (используй телефон, не подключённый к твоему Wi-Fi), открой https://n8n.example.com/rest/settings в браузере. Должен быть 403 Forbidden.

Как защитить вебхуки n8n от несанкционированного доступа?

URL вебхуков по умолчанию публичные. Любой, кто обнаружит или угадает URL, может запустить твои воркфлоу. Две стратегии защищают от этого: непредсказуемые пути вебхуков и валидация HMAC-подписей внутри воркфлоу.

Использование продакшен-вебхуков с уникальными ID

n8n генерирует два пути вебхука для каждого узла Webhook:

  • Тестовый URL: /webhook-test/<id> (активен только при открытом редакторе)
  • Продакшен URL: /webhook/<id> (активен, когда воркфлоу активирован)

<id> по умолчанию — UUID. Не меняй его на что-то угадываемое, вроде /webhook/github или /webhook/stripe. Случайный UUID — первый рубеж обороны.

Валидация HMAC-подписей в воркфлоу

Сервисы вроде GitHub и Stripe подписывают полезную нагрузку вебхуков общим секретом. Твой воркфлоу n8n должен проверять эту подпись, прежде чем обрабатывать данные.

Для вебхука GitHub добавь узел IF после узла Webhook с таким условием:

  1. В настройках репозитория GitHub установи секрет вебхука (сгенерируй командой openssl rand -base64 32)
  2. В воркфлоу n8n добавь узел Code после узла Webhook:
const crypto = require('crypto');
const secret = $env.GITHUB_WEBHOOK_SECRET;
const signature = $input.first().headers['x-hub-signature-256'];
const body = JSON.stringify($input.first().json);
const expected = 'sha256=' + crypto.createHmac('sha256', secret).update(body).digest('hex');

if (signature !== expected) {
  throw new Error('Invalid webhook signature');
}

return $input.all();
  1. Храни секрет в переменных окружения n8n, а не захардкоженным в воркфлоу. Добавь его в файл .env:
GITHUB_WEBHOOK_SECRET=your-generated-secret-here

И передай его в n8n через docker-compose.yml:

    environment:
      - GITHUB_WEBHOOK_SECRET=${GITHUB_WEBHOOK_SECRET}

Для вебхуков Stripe паттерн аналогичный, но используется другой заголовок (stripe-signature) и timing-safe сравнение. Подробности в документации Stripe по подписям вебхуков.

Скрытие информации о версии n8n

По умолчанию n8n включает информацию о версии в ответы API. Отключи раскрытие версии, чтобы затруднить разведку:

В файле .env:

N8N_VERSION_NOTIFICATIONS_ENABLED=false

В конфигурации Nginx добавь внутри блока server:

    server_tokens off;

Раскрытие версии помогает атакующим нацеливаться на известные уязвимости конкретных релизов n8n. Сокрытие вынуждает их зондировать вслепую.

Как настроить таймауты и лимиты загрузки для n8n?

Некоторые воркфлоу n8n работают минутами, обрабатывая большие датасеты или ожидая ответа внешних API. Стандартный таймаут Nginx в 60 секунд прервёт такие запросы. Воркфлоу загрузки файлов упадут, если полезная нагрузка превысит стандартный лимит Nginx в 1 МБ на тело запроса.

В основном блоке location / HTTPS-сервера добавь или обнови:

    # Timeout tuning for long-running workflows
    proxy_connect_timeout 60s;
    proxy_read_timeout 300s;
    proxy_send_timeout 300s;

    # Allow file uploads up to 50 MB
    client_max_body_size 50m;

proxy_read_timeout 300s даёт воркфлоу до 5 минут на ответ. Подстрой значение под время выполнения твоего самого долгого воркфлоу. У блока location для вебхуков уже есть свои таймауты из раздела rate limiting.

client_max_body_size 50m разрешает загрузку файлов до 50 МБ через эндпоинты вебхуков и редактора. Воркфлоу n8n, обрабатывающие импорт CSV, загрузку изображений или конвертацию документов, нуждаются в этом.

Проверь и перезагрузи:

sudo nginx -t && sudo systemctl reload nginx

Полная конфигурация Nginx

Полная конфигурация после всех изменений. Сравни её со своим файлом:

map $http_upgrade $connection_upgrade {
    default upgrade;
    ''      close;
}

limit_req_zone $binary_remote_addr zone=webhooks:10m rate=10r/s;
limit_req_zone $binary_remote_addr zone=editor:10m rate=30r/s;

server {
    listen 80;
    listen [::]:80;
    server_name n8n.example.com;
    return 301 https://$host$request_uri;
}

server {
    listen 443 ssl;
    listen [::]:443 ssl;
    server_name n8n.example.com;

    ssl_certificate /etc/letsencrypt/live/n8n.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/n8n.example.com/privkey.pem;
    include /etc/letsencrypt/options-ssl-nginx.conf;
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;

    server_tokens off;

    # Security headers
    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
    add_header X-Frame-Options "DENY" always;
    add_header X-Content-Type-Options "nosniff" always;
    add_header Referrer-Policy "strict-origin-when-cross-origin" always;
    add_header Permissions-Policy "camera=(), microphone=(), geolocation=()" always;
    add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self' data:; connect-src 'self' wss://n8n.example.com; frame-ancestors 'none'" always;

    client_max_body_size 50m;

    # Rate limit webhook endpoints
    location /webhook/ {
        limit_req zone=webhooks burst=20 nodelay;
        limit_req_status 429;

        proxy_pass http://127.0.0.1:5678;
        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_read_timeout 300s;
        proxy_send_timeout 300s;
    }

    location /webhook-test/ {
        limit_req zone=webhooks burst=5 nodelay;
        limit_req_status 429;

        proxy_pass http://127.0.0.1:5678;
        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;
    }

    # Restrict editor API to specific IPs
    location /rest/ {
        allow 203.0.113.50;
        allow 10.0.0.0/8;
        deny all;

        limit_req zone=editor burst=50 nodelay;

        proxy_pass http://127.0.0.1:5678;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection $connection_upgrade;
        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_buffering off;
    }

    # Main location - editor frontend and fallback
    location / {
        limit_req zone=editor burst=50 nodelay;
        limit_req_status 429;

        proxy_pass http://127.0.0.1:5678;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection $connection_upgrade;
        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_buffering off;
        proxy_cache off;
        chunked_transfer_encoding off;
        proxy_connect_timeout 60s;
        proxy_read_timeout 300s;
        proxy_send_timeout 300s;
    }
}

Как проверить работу WebSocket-соединений в редакторе n8n?

Редактор n8n использует WebSocket-соединение на /rest/push для получения обновлений о выполнении воркфлоу в реальном времени. Если это соединение не работает, ты увидишь баннер «Connection lost», и редактор не будет обновляться после запуска воркфлоу.

Открой редактор n8n в браузере. Открой инструменты разработчика (F12), перейди на вкладку Network и отфильтруй по «WS» (WebSocket). Ты должен увидеть соединение к wss://n8n.example.com/rest/push со статусом 101 (Switching Protocols).

Из командной строки протестируй WebSocket-апгрейд:

curl -sI -H "Upgrade: websocket" -H "Connection: Upgrade" -H "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==" -H "Sec-WebSocket-Version: 13" https://n8n.example.com/rest/push

Ответ 101 Switching Protocols подтверждает, что WebSocket-проксирование работает. 200 или 400 означает, что заголовки upgrade не доходят до n8n. Вернись и проверь директиву map и прокси-заголовки Upgrade/Connection.

Что-то пошло не так?

Редактор n8n показывает «Connection lost»

WebSocket-проксирование сломано. Проверь:

  1. Блок map $http_upgrade $connection_upgrade существует в начале конфигурации
  2. proxy_set_header Upgrade $http_upgrade и proxy_set_header Connection $connection_upgrade находятся в блоке location /
  3. Установлен proxy_http_version 1.1 (WebSocket требует HTTP/1.1)

Проверь логи Nginx:

sudo journalctl -u nginx -f

«502 Bad Gateway» после перезапуска

Контейнер n8n не запущен или не слушает на порту 5678:

docker ps | grep n8n
docker compose logs --tail=50 n8n

Продление Certbot не работает

Проверь, что таймер запущен, и протестируй вручную:

sudo systemctl status certbot.timer
sudo certbot renew --dry-run

Если продление не работает, убедись, что порт 80 открыт в UFW и HTTP-серверный блок на месте (Certbot нужен для HTTP-01 challenge).

«403 Forbidden» с разрешённого IP

Твой IP мог измениться. Проверь текущий IP командой curl -4 ifconfig.me и обнови директиву allow в конфигурации Nginx.

Слишком агрессивный rate limiting

Если легитимные отправители вебхуков получают ошибки 429, увеличь значения rate и burst в директивах limit_req_zone и limit_req. Сначала посмотри частоту входящих запросов:

sudo tail -f /var/log/nginx/access.log | grep webhook

Следующие шаги

  • Настроить автоматическое резервное копирование и обновления для экземпляра n8n ()
  • Узнать больше о паттернах reverse proxy в Nginx ()
  • Изучить настройку TLS подробнее ()
  • Вернуться к обзору автоматизации воркфлоу (автоматизация воркфлоу на своём сервере)

Авторское право 2026 Virtua.Cloud. Все права защищены. Данный контент является оригинальным произведением команды Virtua.Cloud. Воспроизведение, повторная публикация или распространение без письменного разрешения запрещены.

Готовы попробовать?

Разверните свой сервер за секунды. Linux, Windows или FreeBSD.

Смотреть тарифы VPS
Защита n8n с Nginx, TLS и заголовками безопасности