n8n self-hosted для личного использования
Разворачиваем собственный n8n через Docker Compose: домен, HTTPS, PostgreSQL, безопасность, резервные копии и обновления.
Содержание статьи
- Что получится
- Что понадобится
- 1. Подготавливаем сервер
- 2. Устанавливаем Docker Engine и Docker Compose
- 3. Настраиваем секреты
- 4. Создаём файл Docker Compose
- 5. Настраиваем Caddy и HTTPS
- 6. Запускаем n8n
- 7. Проверяем публичный URL и webhook
- 8. Первый workflow — в отдельной статье
- 9. Настраиваем резервные копии
- 10. Обновляем n8n
- Минимальный чек-лист безопасности
- Частые проблемы
- Caddy не получает сертификат
- Webhook недоступен
- Исчезли credentials
- PostgreSQL не запускается
- Итог
n8n — визуальный конструктор автоматизаций, похожий по идее на Zapier и Make, но работающий на собственном сервере. Это удобно для личных интеграций: можно связать Telegram, почту, календарь, GitHub, базы данных и внешние API, не отдавая все данные стороннему сервису и не оплачивая каждый запуск.
В этой статье развернём n8n на VPS с Linux и Docker Compose. Для хранения данных используем PostgreSQL, а перед n8n поставим Caddy: он автоматически получит и продлит HTTPS-сертификат Let's Encrypt.
После установки можно перейти к практическому продолжению: «Первый workflow в n8n: расписание, проверка данных и уведомление в Telegram».
Инструкция рассчитана на чистый сервер Ubuntu 22.04/24.04 с публичным IPv4-адресом, доменом и SSH-доступом. Команды выполняются от обычного пользователя с правами
sudo.
Что получится
Браузер -- HTTPS :443 --> Caddy -- Docker-сеть --> n8n :5678
└--> PostgreSQL :5432
Наружу будут опубликованы только порты 80 и 443. PostgreSQL и внутренний порт n8n останутся доступны только внутри Docker-сети.
Что понадобится
- VPS с минимум 1 ГБ RAM, лучше 2 ГБ;
- Ubuntu 22.04 или 24.04;
- домен, например
n8n.example.com; - DNS-запись
A, указывающая на IP сервера; - SSH-доступ;
- почтовый адрес для Let's Encrypt.
Если планируются тяжёлые workflow, обработка больших файлов или несколько пользователей, закладывайте больше оперативной памяти.
1. Подготавливаем сервер
Подключитесь по SSH и обновите систему:
ssh deploy@example.com
sudo apt update
sudo apt upgrade -y
Создайте отдельный каталог:
sudo mkdir -p /opt/n8n
sudo chown "$USER":"$USER" /opt/n8n
cd /opt/n8n
Не работайте постоянно под root. Отдельный пользователь с sudo уменьшает последствия ошибки в команде или workflow.
2. Устанавливаем Docker Engine и Docker Compose
На чистом Ubuntu установим Docker из официального репозитория. Сначала удалим конфликтующие пакеты, если они были установлены из стандартного репозитория:
sudo apt update
sudo apt remove -y docker.io docker-doc docker-compose podman-docker containerd runc || true
sudo apt install -y ca-certificates curl
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg \
-o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc
Добавим официальный репозиторий Docker:
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] 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 --version
docker compose version
В этой статье используется современная команда docker compose с пробелом — это Compose plugin v2. Старый отдельный бинарник docker-compose с дефисом встречается в старых инструкциях, но для нового сервера его устанавливать не нужно.
Чтобы запускать Docker без sudo, добавьте пользователя в группу Docker:
sudo usermod -aG docker "$USER"
Выйдите из SSH и подключитесь снова, затем выполните тест:
docker run --rm hello-world
3. Настраиваем секреты
Создайте и откройте /opt/n8n/.env в редакторе vi:
vi /opt/n8n/.env
Добавьте в него:
POSTGRES_USER=n8n
POSTGRES_PASSWORD=придумайте-длинный-пароль
POSTGRES_DB=n8n
N8N_ENCRYPTION_KEY=случайная-строка-минимум-32-символа
N8N_HOST=n8n.example.com
N8N_PROTOCOL=https
N8N_PORT=5678
WEBHOOK_URL=https://n8n.example.com/
GENERIC_TIMEZONE=Europe/Moscow
TZ=Europe/Moscow
Для случайных значений можно использовать:
openssl rand -hex 32
N8N_ENCRYPTION_KEY особенно важен: n8n использует его для шифрования credentials. Если потерять ключ, сохранённые подключения могут стать недоступными. Сохраните его в менеджере паролей и резервной копии.
Ограничьте права:
chmod 600 .env
Не добавляйте .env в Git и не отправляйте его в чаты или тикеты.
4. Создаём файл Docker Compose
Создайте именно файл docker-compose.yml в /opt/n8n:
cd /opt/n8n
vi docker-compose.yml
compose.yml — современное короткое имя, которое тоже понимает Docker Compose, но имя docker-compose.yml привычнее и понятнее для самостоятельного сервера и большинства инструкций.
services:
postgres:
image: postgres:16-alpine
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: 5s
timeout: 5s
retries: 10
networks: [internal]
n8n:
image: docker.n8n.io/n8nio/n8n:1.107.0
restart: unless-stopped
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_HOST: ${N8N_HOST}
N8N_PROTOCOL: ${N8N_PROTOCOL}
N8N_PORT: ${N8N_PORT}
N8N_EDITOR_BASE_URL: https://${N8N_HOST}/
WEBHOOK_URL: ${WEBHOOK_URL}
N8N_ENCRYPTION_KEY: ${N8N_ENCRYPTION_KEY}
GENERIC_TIMEZONE: ${GENERIC_TIMEZONE}
TZ: ${TZ}
depends_on:
postgres:
condition: service_healthy
volumes:
- n8n_data:/home/node/.n8n
networks: [internal]
caddy:
image: caddy:2-alpine
restart: unless-stopped
ports:
- "80:80"
- "443:443"
environment:
N8N_HOST: ${N8N_HOST}
volumes:
- ./Caddyfile:/etc/caddy/Caddyfile:ro
- caddy_data:/data
- caddy_config:/config
depends_on: [n8n]
networks: [internal]
volumes:
postgres_data:
n8n_data:
caddy_data:
caddy_config:
networks:
internal:
Версию n8n лучше фиксировать, как в примере, а не использовать latest: так обновление не произойдёт неожиданно. Перед публикацией статьи версию образа стоит сверить с актуальным changelog n8n.
5. Настраиваем Caddy и HTTPS
Caddy умеет получать сертификаты автоматически. В конфигурации не нужно вручную прописывать URL Let's Encrypt, путь к сертификату или cron для продления: Caddy использует протокол ACME и сам обращается к центру сертификации.
Создайте Caddyfile:
vi Caddyfile
Содержимое:
n8n.example.com {
encode gzip
reverse_proxy n8n:5678
}
Здесь n8n.example.com — не просто имя виртуального хоста. По нему Caddy понимает, для какого домена нужно запросить сертификат, а затем проксировать HTTPS-трафик на контейнер n8n по внутреннему адресу n8n:5678.
Для автоматического выпуска сертификата одновременно должны выполняться условия:
- DNS-запись
Aдомена указывает на публичный IP VPS; - снаружи доступны TCP-порты 80 и 443;
- эти порты не заняты другим reverse proxy;
- домен в
Caddyfileсовпадает с доменом, который открывается в браузере; - сервер может выйти в интернет к ACME-серверам.
Порт 80 нужен не только для перенаправления на HTTPS: центр сертификации может использовать его для HTTP-01-проверки владения доменом. После выпуска сертификата Caddy будет автоматически продлевать его и хранить данные в volume caddy_data.
Если включён UFW, откройте только нужные порты:
Если включён UFW, откройте только нужные порты:
sudo ufw allow OpenSSH
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw enable
sudo ufw status
Не открывайте наружу 5432 и 5678: reverse proxy должен быть единой внешней точкой входа.
6. Запускаем n8n
Перед запуском проверьте итоговую конфигурацию:
docker compose config
Если YAML корректный, запускайте:
docker compose up -d
Состояние и логи:
docker compose ps
docker compose logs -f --tail=100 caddy n8n postgres
Откройте https://n8n.example.com. При первом входе создайте владельца инсталляции и сохраните пароль в менеджере паролей.
7. Проверяем публичный URL и webhook
Внешние webhook-ссылки должны начинаться с:
https://n8n.example.com/
Если n8n показывает http://, имя контейнера или неправильный домен, проверьте:
N8N_HOST;N8N_PROTOCOL=https;N8N_EDITOR_BASE_URL;WEBHOOK_URL;- DNS и сертификат Caddy.
После изменения .env пересоздайте контейнер:
docker compose up -d --force-recreate n8n
Для тестового webhook нужно запустить workflow вручную. Тестовый URL может работать только во время ручного выполнения, а production URL — после активации workflow.
8. Первый workflow — в отдельной статье
После проверки установки можно создать первый workflow. Чтобы не смешивать эксплуатацию сервера с логикой автоматизации, подробный пример вынесен в отдельный материал: там показано создание workflow с расписанием, подготовкой данных, проверкой условий и отправкой уведомления в Telegram.
До его активации не подключайте массовую рассылку, удаление данных или платные API. Сначала выполните workflow вручную на тестовых данных и проверьте каждый результат.
9. Настраиваем резервные копии
Docker volume не заменяет backup. Минимальная схема — регулярный дамп PostgreSQL и хранение копий вне VPS.
Пример ручного дампа:
docker compose exec -T postgres \
pg_dump -U n8n -d n8n -Fc \
> "/var/backups/n8n-$(date +%F-%H%M).dump"
Пароль не стоит встраивать в команду и скрипты в открытом виде. Для автоматизации используйте защищённое окружение или .pgpass с правами 600.
Сохраняйте отдельно:
- дампы PostgreSQL;
.env, включаяN8N_ENCRYPTION_KEY;compose.yml;Caddyfile;- список важных workflow и интеграций.
Периодически проверяйте восстановление на отдельном экземпляре. Backup, из которого ни разу не выполнялось восстановление, не считается проверенным.
10. Обновляем n8n
Перед обновлением:
- изучите changelog;
- сделайте дамп базы;
- сохраните текущую версию образа и конфигурацию;
- убедитесь, что есть план отката;
- по возможности протестируйте обновление отдельно.
При зафиксированной версии:
docker compose pull n8n
docker compose up -d n8n
docker compose logs -f --tail=100 n8n
Не используйте docker compose down -v: флаг -v удалит volumes, включая данные PostgreSQL и n8n.
После обновления проверьте вход, открытие workflow, credentials, тестовый запуск и внешний webhook.
Минимальный чек-лист безопасности
- SSH работает по ключу, парольный вход отключён;
- firewall разрешает только SSH, HTTP и HTTPS;
- PostgreSQL и порт n8n не опубликованы наружу;
.envимеет права600и не попал в Git;N8N_ENCRYPTION_KEYсохранён отдельно и не меняется;- credentials используют минимально необходимые права;
- есть регулярные backup и проверенное восстановление;
- образ n8n обновляется контролируемо;
- тестовые workflow и webhook не оставлены активными;
- сервер и Docker регулярно обновляются.
Частые проблемы
Caddy не получает сертификат
Проверьте DNS, доступность портов и логи:
docker compose logs caddy
sudo ss -tulpn | grep -E ':80|:443'
Webhook недоступен
Проверьте WEBHOOK_URL, N8N_PROTOCOL, DNS и статус workflow. Для тестового webhook ручной запуск должен оставаться активным.
Исчезли credentials
Проверьте, не изменился ли N8N_ENCRYPTION_KEY, не удалён ли volume n8n_data и не был ли создан новый каталог проекта.
PostgreSQL не запускается
Посмотрите логи:
docker compose logs postgres
Пароль в .env не меняет пароль уже созданного пользователя PostgreSQL автоматически. При смене конфигурации учитывайте состояние существующего volume.
Итог
Для личного n8n достаточно связки из Docker Compose, PostgreSQL и Caddy. Надёжность определяют не только команды запуска, но и эксплуатационные детали: постоянный ключ шифрования, HTTPS, закрытая база, резервные копии с проверкой восстановления и контролируемые обновления.
Такой стенд остаётся простым в обслуживании, но не превращается в контейнер, который страшно перезапускать или обновлять.