// DevOps

Устанавливаем n8n в Docker с HAProxy: Понятное руководство для начинающих

Опубликовано 22.09.2026

В этом руководстве разворачиваем n8n в Docker, а наружу публикуем его через HAProxy — обратный прокси, который принимает HTTPS и передаёт запросы n8n. Инструкция рассчитана на начинающих: каждый шаг объяснён. Команды и параметры сверены с документацией n8n для ветки 2.x (на сентябрь 2026 года актуальна 2.40).

Зачем нужен HAProxy

Открыть порт n8n прямо в интернет можно, но это небезопасно и неудобно. HAProxy решает три задачи:

  1. HTTPS. Прокси принимает зашифрованные соединения и хранит сертификат, а n8n работает внутри сервера по обычному HTTP.
  2. Единая точка входа. Все запросы на домен приходят на HAProxy, и он решает, какому приложению их передать. На тот же сервер потом можно добавить другие сервисы.
  3. Гибкость. Правила маршрутизации, ограничения и балансировку можно добавить позже, не трогая n8n. Подробнее о HAProxy — в статье «Прокси-серверы: Часть 3 — HAProxy».

Что понадобится

  • Сервер с Ubuntu или Debian. Для небольшой установки хватит 2 ядер и 2–4 ГБ памяти; выбор между облаком n8n и своим сервером разобран в статье «n8n: Часть 2 — Облачная версия или собственный сервер».
  • Docker и Docker Compose (плагин docker compose).
  • Доменное имя с A-записью на IP-адрес сервера.
  • SSH-доступ с правами sudo.

Шаг 1: Подготовка сервера и структуры проекта

  1. Обновите пакеты:

    bash
    sudo apt update && sudo apt upgrade -y
  2. Проверьте Docker:

    bash
    docker --version
    docker compose version

    Если команды не найдены, установите Docker по официальной инструкции для вашей системы.

  3. Создайте каталог проекта и подкаталоги:

    bash
    mkdir -p ~/n8n-project/haproxy/certs
    cd ~/n8n-project

Шаг 2: Файл .env с секретами

В каталоге ~/n8n-project создайте файл .env. Docker Compose подставит из него значения в docker-compose.yml.

env
N8N_DOMAIN=n8n.example.com
POSTGRES_USER=n8n
POSTGRES_PASSWORD=замените-на-длинный-пароль
POSTGRES_DB=n8n
# ключ шифрования учётных данных в n8n: сгенерируйте один раз и сохраните
N8N_ENCRYPTION_KEY=замените-на-результат-openssl-rand-hex-32

Ключ шифрования сгенерируйте командой openssl rand -hex 32. Этим ключом n8n шифрует сохранённые учётные данные (credentials): если его потерять, восстановить их из резервной копии не получится. Храните ключ отдельно от сервера.


Шаг 3: Файл docker-compose.yml

Создайте ~/n8n-project/docker-compose.yml. Строка version: в начале файла больше не нужна: современный Docker Compose её игнорирует.

yaml
services:
  postgres:
    image: postgres:18
    restart: unless-stopped
    environment:
      POSTGRES_USER: ${POSTGRES_USER}
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
      POSTGRES_DB: ${POSTGRES_DB}
      PGDATA: /var/lib/postgresql/data
    volumes:
      - db-storage:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -h localhost -U ${POSTGRES_USER} -d ${POSTGRES_DB}"]
      interval: 5s
      timeout: 5s
      retries: 10

  n8n:
    image: n8nio/n8n:2.40.5   # закрепите версию и обновляйте осознанно
    restart: unless-stopped
    ports:
      - "127.0.0.1:5678:5678"   # порт доступен только внутри сервера
    environment:
      DB_TYPE: postgresdb
      DB_POSTGRESDB_HOST: postgres
      DB_POSTGRESDB_PORT: "5432"
      DB_POSTGRESDB_DATABASE: ${POSTGRES_DB}
      DB_POSTGRESDB_USER: ${POSTGRES_USER}
      DB_POSTGRESDB_PASSWORD: ${POSTGRES_PASSWORD}
      N8N_ENCRYPTION_KEY: ${N8N_ENCRYPTION_KEY}
      N8N_HOST: ${N8N_DOMAIN}
      N8N_PORT: "5678"
      N8N_PROTOCOL: https
      WEBHOOK_URL: https://${N8N_DOMAIN}/
      N8N_PROXY_HOPS: "1"       # n8n работает за одним обратным прокси
      NODE_ENV: production
    volumes:
      - n8n-data:/home/node/.n8n
    depends_on:
      postgres:
        condition: service_healthy

  haproxy:
    image: haproxy:3.2          # ветка с долгосрочной поддержкой
    restart: unless-stopped
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./haproxy:/usr/local/etc/haproxy:ro
    depends_on:
      - n8n

volumes:
  db-storage:
  n8n-data:

Что здесь важно:

  • Никаких логина и пароля в переменных. Раньше в таких инструкциях задавали N8N_BASIC_AUTH_USER и N8N_BASIC_AUTH_PASSWORD, но поддержку basic auth убрали ещё в n8n 1.0. Вход теперь только через учётную запись владельца, которую вы создадите при первом открытии n8n.
  • PostgreSQL вместо SQLite. Для постоянной работы документация n8n рекомендует PostgreSQL; строка PGDATA нужна, чтобы Postgres 18 хранил данные в подключённом томе.
  • WEBHOOK_URL и N8N_PROTOCOL. Без них n8n будет показывать адреса веб-хуков вида http://localhost:5678/…, и внешние сервисы до них не достучатся.
  • N8N_PROXY_HOPS=1 сообщает n8n, что перед ним один прокси, и он берёт адрес клиента из заголовка X-Forwarded-For.
  • Порт 127.0.0.1:5678 не виден из интернета — к n8n можно попасть только через HAProxy.

Шаг 4: HAProxy для HTTP

Сначала запускаем всё по HTTP: сертификата ещё нет. Создайте ~/n8n-project/haproxy/haproxy.cfg:

ini
global
    log stdout format raw local0

defaults
    log     global
    mode    http
    option  httplog
    option  forwardfor
    timeout connect 5s
    timeout client  50s
    timeout server  50s
    timeout tunnel  1h

frontend http_front
    bind :80
    acl host_n8n hdr(host) -i n8n.example.com
    use_backend n8n_backend if host_n8n

backend n8n_backend
    server n8n n8n:5678 check
  • option forwardfor добавляет заголовок X-Forwarded-For с адресом клиента.
  • timeout tunnel 1h нужен для WebSocket: редактор n8n держит постоянное соединение с сервером, и без этого параметра HAProxy обрывал бы его через 50 секунд.
  • server n8n n8n:5678 check — адрес контейнера по имени сервиса из docker-compose.yml и проверка его доступности.

Запустите контейнеры и проверьте их состояние:

bash
cd ~/n8n-project
docker compose up -d
docker compose ps

Шаг 5: Сертификат Let’s Encrypt через acme.sh

HAProxy не раздаёт файлы с диска, поэтому проверку домена проще пройти в режиме standalone: acme.sh на несколько секунд сам поднимает веб-сервер на порту 80. Чтобы порт был свободен, на время выпуска и продления HAProxy останавливается — это делают хуки --pre-hook и --post-hook, которые acme.sh запоминает и повторяет при каждом продлении.

  1. Установите acme.sh и socat (socat нужен режиму standalone):

    bash
    sudo apt install -y socat
    curl https://get.acme.sh | sh -s email=admin@example.com
    source ~/.bashrc
  2. Выберите центр сертификации. С версии 3.0 acme.sh по умолчанию обращается к ZeroSSL; если нужен Let’s Encrypt, укажите его явно:

    bash
    ~/.acme.sh/acme.sh --set-default-ca --server letsencrypt
  3. Выпустите сертификат:

    bash
    ~/.acme.sh/acme.sh --issue --standalone -d n8n.example.com \
        --pre-hook  "docker compose -f $HOME/n8n-project/docker-compose.yml stop haproxy" \
        --post-hook "docker compose -f $HOME/n8n-project/docker-compose.yml start haproxy"
  4. Установите сертификат для HAProxy. HAProxy ждёт ключ и цепочку сертификатов в одном файле. Команда из --reloadcmd собирает этот файл и перезапускает HAProxy при каждом продлении:

    bash
    ~/.acme.sh/acme.sh --install-cert -d n8n.example.com \
        --key-file       ~/n8n-project/haproxy/certs/privkey.pem \
        --fullchain-file ~/n8n-project/haproxy/certs/fullchain.pem \
        --reloadcmd      "cat ~/n8n-project/haproxy/certs/fullchain.pem ~/n8n-project/haproxy/certs/privkey.pem > ~/n8n-project/haproxy/certs/n8n.pem && docker compose -f ~/n8n-project/docker-compose.yml restart haproxy"

Продлением занимается задача cron, которую acme.sh добавил при установке; проверить её можно командой crontab -l.


Шаг 6: Включаем HTTPS в HAProxy

Приведите haproxy.cfg к такому виду:

ini
global
    log stdout format raw local0
    ssl-default-bind-options ssl-min-ver TLSv1.2

defaults
    log     global
    mode    http
    option  httplog
    option  forwardfor
    timeout connect 5s
    timeout client  50s
    timeout server  50s
    timeout tunnel  1h

frontend http_https_front
    bind :80
    bind :443 ssl crt /usr/local/etc/haproxy/certs/n8n.pem alpn h2,http/1.1

    # всех, кто пришёл по HTTP, отправляем на HTTPS
    http-request redirect scheme https code 301 unless { ssl_fc }

    acl host_n8n hdr(host) -i n8n.example.com
    use_backend n8n_backend if host_n8n

backend n8n_backend
    http-request set-header X-Forwarded-Proto https if { ssl_fc }
    server n8n n8n:5678 check

Проверьте синтаксис и примените конфигурацию:

bash
cd ~/n8n-project
docker compose run --rm haproxy haproxy -c -f /usr/local/etc/haproxy/haproxy.cfg
docker compose restart haproxy

Шаг 7: Проверка

Откройте https://n8n.example.com. Должны быть замок в адресной строке и мастер создания учётной записи владельца — заполните его сразу, пока адрес не нашли посторонние. После входа откройте любой узел Webhook: адрес веб-хука должен начинаться с https://n8n.example.com/.

Обслуживание

  • Обновление n8n. Прочитайте примечания к новой версии, сделайте резервную копию и поменяйте тег образа в docker-compose.yml, затем:
    bash
    docker compose pull n8n
    docker compose up -d
  • Резервное копирование. Нужны три вещи: дамп базы (docker compose exec postgres pg_dump -U n8n n8n > n8n.sql), том n8n-data и ключ шифрования из .env.
  • Сертификат продлевается автоматически; при сбое смотрите журнал ~/.acme.sh/acme.sh.log.
  • Рост нагрузки. Когда процессов станет много, n8n переводят в режим очереди с отдельными воркерами — об этом статья «n8n: Часть 5 — Масштабирование».

Та же установка без HAProxy, на панели FastPanel, описана в статье «Устанавливаем n8n на FastPanel с Docker Compose».

// Reviews

Отзывы по теме

// Contact

Нужна помощь?

Свяжись со мной и я помогу решить проблему

Написать в Telegram

Отвечаю в течение рабочего дня (03:00–13:00 GMT)

Или оставьте заявку здесь:

Подтвердите, что вы не бот.

Написать и получить быстрый ответ