n8n — low-code платформа для автоматизации бизнес-процессов: вебхуки, интеграции с сотнями сервисов, обработка данных и ИИ-агенты собираются мышкой в визуальном редакторе. Развернуть n8n self-hosted под Ubuntu 24.04 LTS — значит держать все данные и учётные записи у себя, без лимитов на исполнения и без зависимости от внешнего облака. Ниже — воспроизводимый сценарий: установка n8n через Docker Compose, боевой стек с PostgreSQL, обратный прокси Nginx с корректными вебхуками и бесплатный SSL от Let's Encrypt. На выходе — рабочая инфраструктура по вашему домену через HTTPS, готовая к продакшну: параллельные вебхуки, длинные workflow и восстановление после сбоя.
Зачем разворачивать n8n на своём сервере и что для этого нужно
n8n распространяется в двух формах: облачный n8n Cloud по подписке и self-hosted-версия с открытым кодом. Для российского бизнеса выбор чаще предопределён: платить за зарубежную подписку n8n Cloud из РФ непросто, а данные workflow физически лежат за пределами страны — и с 1 июля 2025 года хранение персональных данных россиян на зарубежных серверах прямо ограничено законом. Собственный инстанс снимает эти вопросы.
n8n Cloud или собственный сервер: контроль над данными и отсутствие лимитов
Главный аргумент за self-hosted — данные. Через n8n проходят токены доступа к CRM, ключи платёжных систем, персональные данные клиентов из форм и таблиц. Когда инстанс работает на вашем VPS, эти сведения не покидают контролируемый контур — это напрямую отвечает требованиям 152-ФЗ к обработке персональных данных на территории РФ.
Второй аргумент — экономика. В тарифах n8n Cloud количество исполнений ограничено пакетом, и активная автоматизация быстро упирается в потолок. На своём сервере лимит один — ресурсы железа: если workflow вызывает вебхук тысячу раз в час, вы платите за сервер, а не за каждый запуск. Взамен обновления, бэкапы и мониторинг ложатся на вас.
Сколько ресурсов нужно под нагрузку: конфигурации VPS (RAM/CPU/диск)
Потребление ресурсов n8n зависит от характера использования. Сам процесс Node.js в простое потребляет немного, но каждый параллельный запуск — это память, а тяжёлые ноды (большие JSON, файлы, ИИ-запросы) дают пики. На 1 GB RAM инстанс с PostgreSQL стабильно сталкивается с OOM уже на паре одновременных вебхуков — это нижняя граница, ниже которой ставить не стоит.
Ориентир по конфигурациям VPS/VDS:
|
Профиль нагрузки |
vCPU |
RAM |
SSD |
Комментарий |
|---|---|---|---|---|
|
Тест, до ~15 простых workflow, редкие запуски |
2 |
2 ГБ |
30 ГБ |
Минимум для n8n + PostgreSQL в Docker |
|
Рабочий инстанс, десятки workflow, регулярные вебхуки |
2–4 |
4 ГБ |
60 ГБ |
Комфортный дефолт для большинства команд |
|
Интенсивная автоматизация, ИИ-ноды, пики параллелизма |
4+ |
8 ГБ |
80–120 ГБ |
Запас под задачи с большими данными |
|
Queue mode с Redis и отдельными воркерами |
4–8 |
8–16 ГБ |
120 ГБ+ |
Горизонтальное масштабирование |
Диск считайте с запасом: база PostgreSQL растёт за счёт истории исполнений, и без автоочистки таблица раздувается незаметно. SSD здесь оправдан — история запусков читается и пишется постоянно.
Подойдёт любой VPS с чистой Ubuntu 24.04 и root-доступом. Например, эту задачу закрывает аренда сервера с Ubuntu от Cloud4U: VDS с преднастроенной Ubuntu поднимается за несколько минут, в тариф уже входят SSD-хранилище, защита от DDoS и автоматические резервные копии на стороне провайдера — удобный второй рубеж поверх собственных бэкапов n8n. Инструкция при этом вендоронезависима: те же команды отработают на любом сервере с Ubuntu 24.04.
Подготовка сервера Ubuntu 24.04: домен, Docker и базовая защита
Прежде чем разворачивать контейнеры, приведём чистый сервер в порядок: привяжем домен, заведём рабочего пользователя вместо root, поставим Docker и закроем лишние порты.
Домен, A-запись и непривилегированный пользователь
n8n за прокси и с SSL проще всего развернуть на полноценном домене или поддомене. Let's Encrypt с недавних пор умеет выпускать сертификаты и на IP-адрес, но это отдельный краткосрочный сценарий; для боевого инстанса берите домен. Заведите A-запись, указывающую на публичный IP сервера. Обычно под автоматизацию выделяют поддомен вида n8n.example.ru:
Тип: A
Имя: n8n
Значение: 203.0.113.10 (IP вашего сервера)
TTL: 300
DNS обновляется не мгновенно — от нескольких минут до пары часов. Проверить, что запись разошлась:
dig +short n8n.example.ru
Пока команда не вернёт IP сервера — с выпуском сертификата спешить нет смысла.
Дальше безопасность хоста. Работать под root на постоянной основе не стоит: заведём отдельного пользователя с правами sudo и добавим его в группу docker.
adduser deploy
usermod -aG sudo deploy
usermod -aG docker deploy
После этого переподключитесь по SSH уже под deploy. Хорошая практика — отключить вход root по паролю и перейти на ключи, но это отдельная тема; дальше все команды идут от непривилегированного пользователя.
Установка Docker и Docker Compose, настройка firewall ufw
Ставить Docker из стандартного репозитория Ubuntu не надо — там версия отстаёт. Подключаем официальный репозиторий Docker с проверкой GPG-ключа:
sudo apt update && sudo apt upgrade -y
sudo apt install -y ca-certificates curl gnupg
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | \
sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
sudo chmod a+r /etc/apt/keyrings/docker.gpg
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] \
https://download.docker.com/linux/ubuntu $(. /etc/os-release && echo $VERSION_CODENAME) stable" | \
sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
Современный Docker Compose ставится как плагин и вызывается через docker compose (с пробелом), а не устаревшей командой docker-compose. Проверка:
docker --version
docker compose version
Теперь firewall. Держать наружу лишние порты незачем — оставляем SSH и веб:
sudo ufw allow OpenSSH
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw enable
Порт 5678, на котором слушает n8n, наружу мы не открываем сознательно — доступ к нему пойдёт только через локальный прокси.
Боевой стек: docker-compose.yml с PostgreSQL и переменными окружения
Дефолтный n8n хранит данные в SQLite — одном файле. Для продакшна не годится: SQLite блокирует базу на запись целиком, и при параллельных вебхуках возникают блокировки базы данных (database locks) — пока один workflow пишет результат, остальные ждут и под нагрузкой завершаются с ошибками. PostgreSQL снимает это за счёт построчных блокировок. Поэтому боевой стек — два контейнера: n8n и Postgres рядом.
Создайте рабочий каталог и в нём — docker-compose.yml:
services:
postgres:
image: postgres:16
restart: unless-stopped
environment:
- POSTGRES_USER=${POSTGRES_USER}
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
- POSTGRES_DB=${POSTGRES_DB}
volumes:
- postgres_data:/var/lib/postgresql/data
healthcheck:
test: ['CMD-SHELL', 'pg_isready -U ${POSTGRES_USER} -d ${POSTGRES_DB}']
interval: 10s
timeout: 5s
retries: 5
n8n:
image: docker.n8n.io/n8nio/n8n:latest
restart: unless-stopped
ports:
- '127.0.0.1:5678:5678'
environment:
- DB_TYPE=postgresdb
- DB_POSTGRESDB_HOST=postgres
- DB_POSTGRESDB_DATABASE=${POSTGRES_DB}
- DB_POSTGRESDB_USER=${POSTGRES_USER}
- DB_POSTGRESDB_PASSWORD=${POSTGRES_PASSWORD}
- N8N_HOST=${N8N_HOST}
- N8N_PROTOCOL=https
- N8N_PORT=5678
- WEBHOOK_URL=https://${N8N_HOST}/
- N8N_ENCRYPTION_KEY=${N8N_ENCRYPTION_KEY}
- N8N_SECURE_COOKIE=true
- N8N_RUNNERS_ENABLED=true
- GENERIC_TIMEZONE=Europe/Moscow
- NODE_ENV=production
volumes:
- n8n_data:/home/node/.n8n
depends_on:
postgres:
condition: service_healthy
volumes:
postgres_data:
n8n_data:
Нюансы, которые отличают этот файл от того, что часто копируют:
- Никакого
version:в начале — в Compose v2 ключ устарел и только засоряет вывод предупреждениями. - Образ
docker.n8n.io/n8nio/n8n— рекомендованный сейчас реестр, а не старыйn8nio/n8nс Docker Hub. - Порт привязан к
127.0.0.1— снаружи достучаться до n8n напрямую нельзя. Пропустите127.0.0.1— и порт 5678 окажется открыт всему интернету в обход прокси. healthcheckу Postgres плюсdepends_on ... condition: service_healthy— n8n стартует только после того, как база готова принимать соединения.
Файл .env, N8N_HOST, WEBHOOK_URL и другие переменные окружения
Секреты в compose-файл не пишут — их выносят в .env рядом, Docker Compose подхватывает его автоматически.
# .env
POSTGRES_USER=n8n
POSTGRES_PASSWORD=смените_на_длинный_случайный_пароль
POSTGRES_DB=n8n
N8N_HOST=n8n.example.ru
N8N_ENCRYPTION_KEY=сюда_сгенерированный_ключ
Ключевые переменные окружения:
N8N_HOST— ваш домен. По нему n8n формирует ссылки и понимает, под каким именем живёт.WEBHOOK_URL— самая частая причина неработающих вебхуков. Это базовый адрес, который n8n подставляет во все URL вебхуков; если он не совпадает с реальным HTTPS-доменом, внешние сервисы обращаются не по тому адресу. Должно быть строгоhttps://ваш-домен/.N8N_PROTOCOL=httpsиN8N_SECURE_COOKIE=true— говорят n8n, что он работает под HTTPS.GENERIC_TIMEZONE— таймзона для нод расписания (Cron/Schedule). Без неё запуски по времени поедут относительно вашего часового пояса.
Права на .env стоит сузить: chmod 600 .env — в файле пароли и ключ шифрования.
N8N_ENCRYPTION_KEY: почему потеря ключа означает потерю всех учётных данных
Момент, который пропускают почти все инструкции, а он критически важен. Все учётные данные (credentials) в n8n — токены API, пароли, ключи, OAuth-доступы — хранятся в базе в зашифрованном виде, и шифруются они значением N8N_ENCRYPTION_KEY. Если ключ задан явно в .env, вы контролируете его; если не задан — n8n при первом старте генерирует его сам и кладёт в ~/.n8n/config внутри тома.
Отсюда следствие: дамп базы без ключа шифрования бесполезен. Восстановите PostgreSQL на новом сервере, но забудьте перенести ключ — и все credentials расшифровать не удастся, их придётся заводить заново. Поэтому ключ задают явно и хранят отдельно от сервера — в менеджере секретов.
Сгенерировать стойкое значение:
openssl rand -hex 32
Полученную строку впишите в N8N_ENCRYPTION_KEY в .env до первого запуска. Менять ключ на работающем инстансе нельзя — ранее сохранённые credentials перестанут расшифровываться.
Запускаем стек:
docker compose up -d
docker compose logs -f n8n
В логах должно появиться, что n8n слушает порт 5678. Наружу он пока не смотрит — этим займётся прокси.
Обратный прокси и бесплатный SSL: Nginx с WebSocket и Let's Encrypt
n8n умеет отдавать HTTPS сам, но на продакшне перед ним ставят обратный прокси (reverse proxy): он терминирует SSL, добавляет заголовки безопасности и разгружает приложение. Из вариантов — Nginx, Traefik, Caddy — возьмём Nginx: он прозрачен, стоит почти везде и даёт полный контроль.
Конфиг Nginx с поддержкой WebSocket и таймаутами для длинных workflow
Ставим Nginx на хост (не в контейнер — так проще с certbot):
sudo apt install -y nginx
Ключевой момент, на котором часто возникают проблемы: редактор n8n работает поверх WebSocket. Push-соединение держит редактор «живым» — показывает статус исполнения в реальном времени, обновляет ноды. Если прокси не пробрасывает заголовки Upgrade, интерфейс подвисает, кнопка выполнения крутится вечно, а соединение обрывается по таймауту.
Создайте /etc/nginx/sites-available/n8n:
server {
listen 80;
server_name n8n.example.ru;
location / {
proxy_pass http://127.0.0.1:5678;
proxy_http_version 1.1;
# Проброс WebSocket — без этих строк редактор зависает
proxy_set_header Upgrade $http_upgrade;
proxy_set_header 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;
# Таймауты под длинные workflow: исполнение может идти минутами
proxy_read_timeout 3600s;
proxy_send_timeout 3600s;
proxy_buffering off;
}
}
Почему proxy_read_timeout 3600s, а не дефолтные 60 секунд: workflow с ожиданием ответа внешнего API, паузой или обработкой большого объёма данных легко исполняется дольше минуты. С коротким таймаутом Nginx обрывает соединение на середине, и в интерфейсе вы видите обрыв, хотя на бэкенде процесс ещё шёл. proxy_buffering off нужен, чтобы серверные события доходили до редактора сразу.
Активируем конфиг и проверяем синтаксис:
sudo ln -s /etc/nginx/sites-available/n8n /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx
Выпуск и автопродление сертификата Let's Encrypt через certbot
Теперь бесплатный SSL от Let's Encrypt. Ставим certbot с плагином для Nginx:
sudo apt install -y certbot python3-certbot-nginx
sudo certbot --nginx -d n8n.example.ru
Certbot проверит владение доменом по HTTP-01, выпустит сертификат и сам перепишет конфиг Nginx: добавит блок на 443 порту, пропишет пути к сертификату и настроит редирект с HTTP на HTTPS. После этого перепроверьте X-Forwarded-Proto $scheme — именно он сообщает n8n, что клиент пришёл по HTTPS.
Подводные камни certbot рядом с Docker:
- Порт 80 должен быть свободен для проверки. Мы отдали его Nginx на хосте, а не контейнеру — конфликта нет.
- Автопродление уже настроено. Пакет certbot ставит системный таймер, который дважды в день проверяет сертификаты и обновляет те, которым осталось меньше 30 дней. Проверить, что механизм жив:
sudo systemctl status certbot.timer
sudo certbot renew --dry-run
Если --dry-run отработал без ошибок — реальное автопродление тоже пройдёт. При обновлении Nginx перечитывает конфиг сам, ронять контейнеры n8n не требуется.
Откройте https://n8n.example.ru — должна появиться форма создания аккаунта администратора. Заведите владельца (owner) — это первый пользователь. Учтите, что штатное восстановление пароля работает через письмо, а SMTP по умолчанию не настроен, — поэтому логин и пароль владельца сохраните сразу.
Эксплуатация: обновление, резервное копирование и типовые ошибки
Инстанс открылся по HTTPS — половина дела. Вторая половина в том, чтобы он пережил обновления и сбои.
Резервное копирование и восстановление: том PostgreSQL и ключ шифрования
Бэкап n8n — это три вещи, и пропуск любой ломает восстановление:
- Том PostgreSQL — сами workflow, история исполнений, зашифрованные credentials.
- Каталог
~/.n8n(томn8n_data) — конфиг инстанса и служебные файлы. N8N_ENCRYPTION_KEY— ключ, без которого содержимое базы не расшифровать. Он у вас в.env, но убедитесь, что копия.envтоже уходит в бэкап и хранится в защищённом месте.
Дамп базы снимается штатным pg_dump изнутри контейнера:
docker compose exec -T postgres \
pg_dump -U n8n -d n8n | gzip > n8n_db_$(date +%F).sql.gz
Эту команду логично оформить в виде скрипта и запустить по cron — ежедневно ночью, с ротацией копий за 7–14 дней и выгрузкой в отдельное хранилище (не на тот же сервер).
Восстановление на новом сервере: разворачиваете тот же docker-compose.yml, переносите .env с тем же N8N_ENCRYPTION_KEY, поднимаете Postgres и заливаете дамп:
gunzip < n8n_db_2026-07-15.sql.gz | \
docker compose exec -T postgres psql -U n8n -d n8n
Если ключ совпадает — все credentials восстанавливаются без повторного ввода. Если ключ забыли — база восстановится, но токены и пароли внутри останутся нечитаемыми. Это и есть цена потерянного ключа шифрования.
Обновление n8n и разбор типовых ошибок (webhook not registered, редирект-петля, 502)
Обновление n8n на Docker Compose — две команды: загружаем свежий образ и пересоздаём контейнер.
docker compose pull
docker compose up -d
Данные при этом на месте — они в томах, а не в контейнере. Разумный порядок: сначала снять бэкап базы, потом обновляться. Перед апдейтом полезно заглянуть в changelog на предмет ломающих изменений.
Типовые ошибки и их причины:
Webhook not registered/ вебхук не срабатывает. В девяти случаях из десяти виноват неверныйWEBHOOK_URL— он должен точно равнятьсяhttps://ваш-домен/. Вторая причина: production-URL требует включённого (active) workflow, тестовый URL живёт, только пока открыт редактор.- Бесконечный редирект / не удаётся войти. Типичная ситуация при работе за прокси:
N8N_SECURE_COOKIE=trueтребует HTTPS, а прокси не передаёт n8n, что соединение защищённое. Браузер получает secure-cookie по HTTP, отбрасывает её, n8n снова перенаправляет на страницу входа — и так по кругу. Решается проброшенным заголовкомX-Forwarded-Proto httpsи корректнымN8N_PROTOCOL=https. - 502 Bad Gateway. Nginx не смог достучаться до апстрима. Причины по частоте: контейнер n8n не поднялся (смотрим
docker compose psиdocker compose logs n8n), не совпадает порт вproxy_passи в проброске контейнера, либо база не готова и n8n перезапускается по кругу. Начинайте диагностику с логов контейнера.
Главные выводы
Разница между «n8n запустился» и «n8n работает в продакшне» держится на нескольких решениях. PostgreSQL вместо SQLite снимает блокировки базы при параллельных вебхуках; привязка порта к 127.0.0.1 и весь трафик через Nginx закрывают приложение от прямого доступа снаружи; корректный проброс WebSocket и увеличенные таймауты не дают редактору зависать на длинных workflow; сертификат Let's Encrypt с проверенным автопродлением обеспечивает HTTPS.
Отдельно держите в голове две вещи, потеря которых обходится дороже всего: ключ шифрования N8N_ENCRYPTION_KEY и регулярные бэкапы тома PostgreSQL. Дамп базы без ключа не расшифровать, а свежий ключ на восстановленной базе не поможет — эти две вещи бэкапятся и хранятся только вместе. Настройте автоматический дамп с выгрузкой на отдельное хранилище, положите ключ в менеджер секретов — и тогда даже полная потеря сервера означает не катастрофу, а переустановку по инструкции выше с восстановлением из копии.
