DevOps & Docker 11 мин чтения 2026-09-16

Свой n8n на VDS: развертывание в Docker Compose с PostgreSQL, Caddy и автопродлением SSL

Развертывание собственного сервера автоматизации n8n на VDS. Надежная связка Docker Compose с базой данных PostgreSQL 16, обратным прокси Caddy с авто-SSL и тонкой настройкой переменных окружения для стабильного приема вебхуков без блокировок и сбоев.

Инженерная редакция SysKit Проверено инженерами SysKit.ru

Облачные платформы автоматизации (Zapier, Make/Integromat) долгое время были золотым стандартом для связки сервисов без кода. Однако в современных реалиях разработчики и системные администраторы сталкиваются с жесткими барьерами: невозможность оплаты подписок российскими картами, лимиты в 1 000–5 000 операций на базовых тарифах и стоимость свыше $50–$100 в месяц за мало-мальски активный проект. Кроме того, передача конфиденциальных данных клиентов, переписок из Telegram и API-ключей на сторонние зарубежные сервера несет прямые юридические и коммерческие риски.

Развертывание open-source платформы n8n на собственном виртуальном сервере VDS полностью решает эту проблему. Вы получаете неограниченное число запусков сценариев, полный контроль над базами данных и изолированную среду исполнения на отечественном оборудовании с себестоимостью от 400 до 800 рублей в месяц. Ниже представлен детальный разбор настройки отказоустойчивого production-стека n8n на базе Docker Compose с СУБД PostgreSQL 16 и обратным прокси Caddy с автоматическим выпуском SSL-сертификатов.

1. Зачем разворачивать n8n на собственном VDS вместо Make и Zapier

Платформа n8n построена на событийно-ориентированной архитектуре Node.js и распространяется по лицензии Fair-code (Sustainable Use License). Это означает, что для внутренних нужд бизнеса, пет-проектов и автоматизации инфраструктуры вы можете использовать движок абсолютно бесплатно и без каких-либо функциональных урезаний.

Ключевые преимущества собственного сервера n8n по сравнению с SaaS-сервисами:

  • Нулевые лимиты на выполнения: в облачных сервисах каждый шаг сценария расходует квоту операций. Сложный пайплайн из 10 узлов при 1 000 заявок в день «сжигает» 300 000 операций в месяц, что в Make обходится в сотни долларов. На своем VDS вы платите только фиксированную стоимость хостинга независимо от количества триггеров.
  • Отсутствие жестких тайм-аутов: облачные платформы принудительно обрывают выполнения длиннее 30–60 секунд. Собственный n8n способен выполнять тяжелые пакетные выгрузки, обработку CSV-файлов или генерацию PDF часами без риска разрыва сессии.
  • Безопасность и соответствие законам: базы данных клиентов, токены Telegram-ботов и токены CRM-систем циркулируют внутри изолированного контура вашего сервера.
  • Доступ к внутренним ресурсам: сценарии n8n на VDS могут напрямую обращаться к базам данных (PostgreSQL, MySQL, Redis) и сервисам внутри защищенной локальной сети Docker или приватного VPC хостера без выставления портов наружу.

💡 Совет инженера: когда n8n критически необходим VDS

В отличие от локального компьютера или ноутбука, который засыпает при закрытии крышки или меняет динамический IP-адрес домашнего провайдера, виртуальный сервер VDS функционирует 24/7/365 с постоянным статическим белым IPv4. Это ключевое условие: входящие вебхуки от Telegram, платежных шлюзов, почтовых серверов и веб-форм должны гарантированно доставляться в любое время суток без задержек и потерь пакетов.

2. Системные требования к VDS и выбор конфигурации сервера

Движок n8n является достаточно легковесным при старте (потребляет около 250–350 МБ RAM), однако при параллельном выполнении сценариев с тяжелыми JSON-ответами, ветвлениями и работой с файлами аппетиты Node.js и базы данных возрастают. Для надежной работы необходимо правильно подобрать параметры сервера:

Параметр Минимальные требования Рекомендуемая конфигурация Комментарий инженера
Процессор (vCPU) 1 ядро 2 ядра Для парсинга больших массивов JSON и параллельных запросов
Оперативная память (RAM) 2 ГБ (+ 2 ГБ Swap) 4 ГБ 1 ГБ n8n + 512 МБ PostgreSQL + Caddy + буферы ОС
Дисковое пространство 25 ГБ NVMe 40–60 ГБ NVMe Высокая скорость случайных операций I/O для логов и очередей
Операционная система Ubuntu 24.04 LTS Ubuntu 24.04 / Debian 12 Чистый образ с поддержкой актуального Docker Engine
Сетевой адрес Статический IPv4 Статический IPv4 + IPv6 Для безошибочной доставки вебхуков внешними API

Перед началом настройки убедитесь, что ваш VDS имеет постоянный белый IP-адрес. Проверить текущий публичный адрес сервера можно с помощью утилиты Определение IP адреса.

3. Архитектура хранилища: почему SQLite не подходит для рабочих нагрузок

По умолчанию при быстром старте через команду docker run n8n инициализирует встроенную файловую базу данных SQLite. Для локального тестирования это удобно, но в рабочем окружении (production) это заложенная бомба замедленного действия.

Главная архитектурная проблема SQLite — блокировка всей базы данных на уровне файла при любой операции записи (database is locked). Когда на сервер одновременно поступает 5–10 внешних вебхуков (например, при рассылке сообщений или массовом оформлении заказов в интернет-магазине):

  • Потоки Node.js пытаются одновременно записать статус запуска сценария в файл database.sqlite;
  • Файловый дескриптор лочится, таймаут ожидания превышает допустимый лимит;
  • Входящие вебхуки завершаются ошибкой 500 Internal Server Error, а отправляющая сторона (Telegram или платежный шлюз) считает ваш сервер упавшим и прекращает доставку событий;
  • При внезапной перезагрузке сервера во время блокировки файл базы SQLite нередко повреждается (corruption), что приводит к полной потере настроенных связок.

Именно поэтому в рабочем окружении обязательна связка с СУБД PostgreSQL 16. PostgreSQL реализует построчные блокировки (Row-Level Locking), поддерживает пул одновременных подключений, надежный механизм опережающей записи в журнал (WAL) и гарантирует сохранение данных при пиковых всплесках нагрузки.

4. Безопасность и шифрование: генерация и фиксация N8N_ENCRYPTION_KEY

В сценариях автоматизации вы будете подключать конфиденциальные сервисы: базы данных клиентов, API-ключи OpenAI, токены ботов Telegram, пароли к почтовым ящикам SMTP и учетные записи платежных шлюзов. Платформа n8n шифрует эти параметры по алгоритму AES-256 перед сохранением в базу данных.

⚠️ Важное предупреждение: потеря N8N_ENCRYPTION_KEY фатальна

Если не зафиксировать ключ шифрования в переменных окружения вручную, n8n сгенерирует его автоматически и сохранит во временном файле внутри тома. При пересоздании контейнера, обновлении образа или смене пути монтирования ключ теряется. В этом случае n8n запустится, но все ваши сохраненные подключения и пароли станут нечитаемым мусором, а сценарии перестанут выполняться. Восстановить их без ключа математически невозможно.

Перед запуском контейнеров обязательно сгенерируйте стойкий 64-символьный шестнадцатеричный ключ шифрования прямо в консоли сервера:

openssl rand -hex 32

Скопируйте полученную строку: ее мы зафиксируем в переменной N8N_ENCRYPTION_KEY в конфигурационном файле .env.

5. Готовый production-стек docker-compose.yml: n8n, PostgreSQL 16 и Caddy

Создадим рабочую директорию проекта в стандартном расположении для автономных сервисов /opt/n8n-stack/:

sudo mkdir -p /opt/n8n-stack && cd /opt/n8n-stack
sudo mkdir -p data/n8n data/postgres data/caddy_data data/caddy_config

Создайте файл переменных окружения .env:

nano .env

Вставьте следующие параметры (замените домен, пароли и сгенерированный ключ шифрования на ваши реальные значения):

# Основные настройки домена
DOMAIN_NAME=n8n.example.ru
SUBDOMAIN=n8n
GENERIC_TIMEZONE=Europe/Moscow

# База данных PostgreSQL
POSTGRES_USER=n8n_db_user
POSTGRES_PASSWORD=UltraSecure_N8N_Password_2026!
POSTGRES_DB=n8n_production

# Ключ шифрования учетных записей (сгенерированный через openssl rand -hex 32)
N8N_ENCRYPTION_KEY=a7d83f0b24e6c91d8e129fbb61047d928413bcae528198f1234567890abcdef1

# Настройки пользователя внутри контейнера n8n
N8N_USER_ID=1000
N8N_GROUP_ID=1000

Теперь создайте манифест развертывания docker-compose.yml:

services:
  postgres:
    image: postgres:16-alpine
    container_name: n8n_postgres
    restart: unless-stopped
    environment:
      POSTGRES_USER: ${POSTGRES_USER}
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
      POSTGRES_DB: ${POSTGRES_DB}
    volumes:
      - ./data/postgres:/var/lib/postgresql/data
    networks:
      - n8n_internal
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -h localhost -U ${POSTGRES_USER} -d ${POSTGRES_DB}"]
      interval: 5s
      timeout: 5s
      retries: 10
    mem_limit: 512m
    cpus: 1.0
    deploy:
      resources:
        limits:
          cpus: '1.0'
          memory: 512M

  n8n:
    image: docker.n8n.io/n8nio/n8n:latest
    container_name: n8n_app
    restart: unless-stopped
    depends_on:
      postgres:
        condition: service_healthy
    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=${DOMAIN_NAME}
      - N8N_PORT=5678
      - N8N_PROTOCOL=https
      - NODE_ENV=production
      - WEBHOOK_URL=https://${DOMAIN_NAME}/
      - GENERIC_TIMEZONE=${GENERIC_TIMEZONE}
      # Автоматическая очистка истории выполнений
      - EXECUTIONS_DATA_PRUNE=true
      - EXECUTIONS_DATA_MAX_AGE=168
      - EXECUTIONS_DATA_PRUNE_MAX_COUNT=50000
      # Лимит размера тела вебхука (до 32 МБ)
      - N8N_PAYLOAD_SIZE_MAX=32
    volumes:
      - ./data/n8n:/home/node/.n8n
    networks:
      - n8n_internal
    mem_limit: 2048m
    cpus: 2.0
    deploy:
      resources:
        limits:
          cpus: '2.0'
          memory: 2048M

  caddy:
    image: caddy:2-alpine
    container_name: n8n_caddy
    restart: unless-stopped
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./Caddyfile:/etc/caddy/Caddyfile:ro
      - ./data/caddy_data:/data
      - ./data/caddy_config:/config
    networks:
      - n8n_internal
    depends_on:
      - n8n

networks:
  n8n_internal:
    driver: bridge

Обратите внимание на изоляцию сети: порты базы данных PostgreSQL (5432) и самого приложения n8n (5678) не проброшены во внешнюю сеть хоста. Доступ открыт исключительно по портам 80 и 443 через Caddy. Проверить отсутствие лишних открытых портов на внешнем IP после старта можно через Сканер открытых портов.

6. Конфигурация Caddyfile: автоматический выпуск SSL и маршрутизация вебхуков

Вместо классической связки Nginx и Certbot, требующей ручной настройки cron-заданий и скриптов обновления, мы используем веб-сервер Caddy. Caddy содержит встроенный ACME-клиент: он автоматически запрашивает бесплатные TLS-сертификаты у Let's Encrypt и ZeroSSL, продлевает их в фоновом режиме за 30 дней до окончания срока действия и прозрачно проксирует протокол WebSocket, на котором работает редактор n8n.

Создайте конфигурационный файл Caddyfile:

nano Caddyfile

Добавьте следующие правила маршрутизации:

n8n.example.ru {
    # Сжатие трафика для ускорения веб-интерфейса
    encode zstd gzip

    # Проксирование всех запросов в контейнер n8n
    reverse_proxy n8n:5678 {
        # Корректная передача заголовков хоста и реального IP клиента
        header_up Host {host}
        header_up X-Real-IP {remote_host}
        header_up X-Forwarded-For {remote_host}
        header_up X-Forwarded-Proto {scheme}

        # Буферизация для стабильной обработки тяжелых ответов
        flush_interval -1
    }

    # Безопасные заголовки
    header {
        Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
        X-Content-Type-Options "nosniff"
        X-Frame-Options "SAMEORIGIN"
        Referrer-Policy "strict-origin-when-cross-origin"
    }
}

Перед запуском контейнеров убедитесь, что в панели управления DNS вашего регистратора добавлена A-запись для поддомена (например, n8n.example.ru), указывающая на внешний IP-адрес вашего VDS. Проверить распространение записи по мировым DNS-серверам можно онлайн через утилиту DNS Lookup и Резолвер.

7. Запуск контейнеров и инициализация рабочего окружения

По умолчанию контейнер n8n работает от непривилегированного пользователя node с идентификатором UID 1000. Если не назначить корректные права на каталог данных, n8n упадет с ошибкой EACCES: permission denied, open '/home/node/.n8n/config'.

Выставим корректного владельца на папки перед первым стартом:

sudo chown -R 1000:1000 data/n8n
sudo chmod -R 750 data/n8n

Запустите стек контейнеров в фоновом режиме:

docker compose up -d

Проверьте статус всех трех сервисов:

docker compose ps

Вы должны увидеть три работающих сервиса: n8n_postgres со статусом healthy, n8n_app со статусом running и n8n_caddy со статусом running. Проверьте журнал логов n8n:

docker compose logs -f n8n

Если в выводе присутствует строка Editor is now accessible via: https://n8n.example.ru/, установка выполнена безупречно. Откройте ваш домен в браузере. При первом входе система предложит создать учетную запись главного администратора (Owner Account) — укажите email и стойкий пароль.

💡 Совет инженера: проверка валидности SSL-сертификата

Сразу после старта проверьте корректность цепочки выпущенного сертификата, поддержку протоколов TLS 1.2/1.3 и отсутствие ошибок смешанного содержимого с помощью утилиты Проверка SSL / TLS сертификата онлайн.

8. Проверка сквозной работы: настройка вебхука и прием данных от Telegram-бота

Чтобы убедиться, что обратный прокси Caddy, база данных и маршрутизация вебхуков работают слаженно, настроим простейший тестовый сценарий приема сообщений от Telegram-бота:

  1. В интерфейсе n8n нажмите «Create Workflow».
  2. Добавьте триггерный узел Webhook.
  3. В параметрах узла выберите:
    • HTTP Method: POST;
    • Path: telegram-webhook;
    • Response Mode: On Received (с возвратом HTTP 200 OK);
  4. Обратите внимание: узел предоставляет два URL:
    • Test URL: https://n8n.example.ru/webhook-test/telegram-webhook (активен только тогда, когда в редакторе нажата кнопка «Listen for Test Event»);
    • Production URL: https://n8n.example.ru/webhook/telegram-webhook (работает постоянно в фоновом режиме после перевода тумблера сценария в положение Active).

Проверим отправку данных через утилиту curl из терминала:

curl -X POST https://n8n.example.ru/webhook-test/telegram-webhook \
  -H "Content-Type: application/json" \
  -d '{"event": "test_ping", "user": "Alexey", "status": "success"}'

В окне редактора n8n моментально отобразится принятая JSON-структура со всеми полями. Это подтверждает, что внешний трафик успешно проходит через Caddy с SSL-терминацией и без задержек сохраняется в PostgreSQL.

9. Ограничение ресурсов, тюнинг памяти и ротация логов контейнеров

Длительно работающий сервер автоматизации может столкнуться с двумя проблемами: утечка оперативной памяти из-за зависших JavaScript-функций и исчерпание места на диске логами Docker (/var/lib/docker/containers/*-json.log).

Для предотвращения аварий настройте общесистемную ротацию логов Docker Engine. Отредактируйте файл /etc/docker/daemon.json:

{
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "50m",
    "max-file": "3"
  }
}

Перезапустите демон Docker для применения ограничений: sudo systemctl restart docker.

Кроме того, в нашем docker-compose.yml уже активированы критически важные переменные автоочистки n8n:

  • EXECUTIONS_DATA_PRUNE=true: включает фоновый процесс сборки мусора;
  • EXECUTIONS_DATA_MAX_AGE=168: автоматически удаляет детали выполненных сценариев старше 7 дней (168 часов). Без этой директивы через 3–6 месяцев таблица execution_entity в PostgreSQL разрастается до 20–50 ГБ, забивая накопитель VDS до отказа;
  • EXECUTIONS_DATA_PRUNE_MAX_COUNT=50000: удерживает общее количество записей в истории в пределах безопасного лимита.

10. Стратегия резервного копирования воркфлоу и учетных записей

Резервное копирование сервера n8n состоит из двух уровней: экспорт логики сценариев в JSON и создание дампа базы данных PostgreSQL.

Платформа n8n имеет встроенную утилиту командной строки (CLI) для пакетного экспорта. Создадим скрипт автоматического бэкапа /opt/n8n-stack/backup.sh:

#!/usr/bin/env bash
set -e

BACKUP_DIR="/opt/n8n-stack/backups"
TIMESTAMP=$(date +"%Y%m%d_%H%M%S")
mkdir -p "${BACKUP_DIR}"

echo "[+] Экспорт воркфлоу n8n..."
docker exec -u node n8n_app n8n export:workflow --all --output=/home/node/.n8n/workflows_export.json
cp /opt/n8n-stack/data/n8n/workflows_export.json "${BACKUP_DIR}/workflows_${TIMESTAMP}.json"

echo "[+] Экспорт зашифрованных учетных записей..."
docker exec -u node n8n_app n8n export:credentials --all --output=/home/node/.n8n/credentials_export.json
cp /opt/n8n-stack/data/n8n/credentials_export.json "${BACKUP_DIR}/credentials_${TIMESTAMP}.json"

echo "[+] Создание дампа PostgreSQL..."
docker exec n8n_postgres pg_dump -U n8n_db_user -d n8n_production | gzip > "${BACKUP_DIR}/postgres_${TIMESTAMP}.sql.gz"

echo "[+] Удаление архивов старше 14 дней..."
find "${BACKUP_DIR}" -type f -mtime +14 -delete

echo "[OK] Резервное копирование успешно завершено: ${TIMESTAMP}"

Сделайте скрипт исполняемым: chmod +x /opt/n8n-stack/backup.sh и добавьте запуск в ночной cron через crontab -e:

0 3 * * * /opt/n8n-stack/backup.sh >> /var/log/n8n-backup.log 2>&1

Подробное руководство по автоматической отправке созданных архивов в защищенное S3-хранилище с алертами об ошибках читайте в статье Автоматический бэкап баз данных и файлов с VDS в S3-хранилище.

11. Сводная таблица параметров и устранение типовых неполадок

Ниже собраны наиболее распространенные сбои при эксплуатации n8n в Docker Compose и проверенные шаги по их локализации:

Симптом ошибки Вероятная причина Метод решения
404 The requested webhook is not registered Сценарий не переведен в режим Active или используется тестовый URL Активируйте тумблер воркфлоу в верхнем правом углу и отправляйте запросы строго на /webhook/... вместо /webhook-test/....
EACCES: permission denied, open config Несоответствие владельца директории данных тома Выполните на хосте команду sudo chown -R 1000:1000 data/n8n и перезапустите контейнер.
PayloadTooLargeError: request entity too large Тело входящего вебхука превышает стандартный лимит Node.js (16 МБ) Задайте в блоке environment файла compose директиву N8N_PAYLOAD_SIZE_MAX=32 (или более).
SSL certificate handshake failed Порт 80 закрыт в UFW, либо DNS-запись еще не обновилась Убедитесь, что в фаерволе открыты порты 80 и 443 (ufw allow 80,443/tcp), и проверьте A-запись домена.
FATAL: password authentication failed Пароль в .env изменен после первичной инициализации тома PostgreSQL PostgreSQL сохраняет первичный пароль в данных тома. При смене пароля в .env обновите его внутри базы командой ALTER USER ... WITH PASSWORD '...'.

Готовы развернуть собственный сервер автоматизации без ограничений?

Запустите надежный VDS с быстрыми NVMe-дисками, белым статическим IP и чистой операционной системой Ubuntu 24.04 LTS у проверенных российских хостинг-провайдеров.

Рекомендуемые VDS-провайдеры

Отказоустойчивые сервера с быстрыми NVMe и каналом до 1 Гбит/с

Выбор редакции
⚡

Timeweb Cloud

Идеально для запуска n8n и PostgreSQL: моментальный деплой чистой Ubuntu 24.04 LTS, выделенный статический IPv4 для стабильного приема вебхуков, сверхбыстрые NVMe-диски со скоростью до 3500 МБ/с и изолированная сеть.

Конфигурация
от 1–2 vCPU / 2–4 GB RAM / 30–50 GB NVMe
Highload & Надежность
🔷

Selectel

Серверы в дата-центрах Tier III с гарантированной доступностью 99.98%. Аппаратная защита от DDoS-атак, скорость портов до 1 Гбит/с без жестких лимитов и быстрое масштабирование дисковой подсистемы под очереди очередей.

Конфигурация
от 2 vCPU / 4 GB RAM / 40 GB NVMe
Удобство и автобэкапы
🟠

Beget

Интуитивная панель управления VDS, бесплатные автоматические снапшоты состояния сервера, встроенный мониторинг потребления оперативной памяти и отзывчивая круглосуточная техническая поддержка 24/7.

Конфигурация
от 1–2 vCPU / 2–4 GB RAM / 30 GB NVMe

Вопросы и ответы (FAQ)

Популярные вопросы вебмастеров и сисадминов по данной теме

Можно ли запустить n8n на сервере с 1 ГБ оперативной памяти?
Запустить связку n8n + PostgreSQL + Caddy на 1 ГБ RAM возможно только при обязательном создании Swap-файла размером не менее 2 ГБ. Однако при одновременной обработке нескольких входящих вебхуков или разборе больших JSON-массивов Node.js может кратковременно потребовать более 800 МБ памяти, что вызовет жесткое замедление из-за активного своппинга или аварийное завершение процесса механизмом Linux OOM Killer. Для коммерческой эксплуатации мы настоятельно рекомендуем тарифы с объемом RAM от 2 ГБ.
Что произойдет, если изменить домен сервера n8n после запуска?
При смене домена достаточно обновить значения переменных DOMAIN_NAME, N8N_HOST и WEBHOOK_URL в файле .env, а также имя хоста в Caddyfile, после чего перезапустить стек командой docker compose up -d --force-recreate. Все существующие сценарии, узлы и учетные записи сохранятся в неизменном виде в базе данных PostgreSQL. Единственное, что потребуется сделать — обновить адреса вебхуков в сторонних сервисах (например, перерегистрировать адрес в Telegram Bot API через метод setWebhook).
Безопасно ли хранить боевые API-ключи от платежных систем и CRM в n8n?
Да, абсолютно безопасно при условии, что вы зафиксировали переменную N8N_ENCRYPTION_KEY и не открываете порт n8n 5678 в публичный интернет. n8n шифрует значения всех учетных записей алгоритмом AES-256 перед записью в PostgreSQL. Даже если злоумышленник получит доступ к дампу базы данных без секретного ключа шифрования, извлечь исходные API-токены будет невозможно.
Как обновлять образы n8n, PostgreSQL и Caddy без риска потери данных?
Благодаря тому, что все постоянные данные вынесены в каталоги хоста (data/postgres, data/n8n, data/caddy_data), обновление происходит полностью безболезненно. Сначала создайте резервную копию скриптом backup.sh, затем выполните: docker compose pull, чтобы скачать свежие слои образов, и команду docker compose up -d, которая перезапустит контейнеры на новых версиях с сохранением всех данных.

Читайте также в блоге SysKit

Смежные руководства и полезные технические статьи