← Все статьи
TOOLS

n8n self-hosted для личного использования

Разворачиваем собственный n8n через Docker Compose: домен, HTTPS, PostgreSQL, безопасность, резервные копии и обновления.

Содержание статьи
  1. Что получится
  2. Что понадобится
  3. 1. Подготавливаем сервер
  4. 2. Устанавливаем Docker Engine и Docker Compose
  5. 3. Настраиваем секреты
  6. 4. Создаём файл Docker Compose
  7. 5. Настраиваем Caddy и HTTPS
  8. 6. Запускаем n8n
  9. 7. Проверяем публичный URL и webhook
  10. 8. Первый workflow — в отдельной статье
  11. 9. Настраиваем резервные копии
  12. 10. Обновляем n8n
  13. Минимальный чек-лист безопасности
  14. Частые проблемы
  15. Caddy не получает сертификат
  16. Webhook недоступен
  17. Исчезли credentials
  18. PostgreSQL не запускается
  19. Итог

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.

Для автоматического выпуска сертификата одновременно должны выполняться условия:

  1. DNS-запись A домена указывает на публичный IP VPS;
  2. снаружи доступны TCP-порты 80 и 443;
  3. эти порты не заняты другим reverse proxy;
  4. домен в Caddyfile совпадает с доменом, который открывается в браузере;
  5. сервер может выйти в интернет к 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

Перед обновлением:

  1. изучите changelog;
  2. сделайте дамп базы;
  3. сохраните текущую версию образа и конфигурацию;
  4. убедитесь, что есть план отката;
  5. по возможности протестируйте обновление отдельно.

При зафиксированной версии:

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, закрытая база, резервные копии с проверкой восстановления и контролируемые обновления.

Такой стенд остаётся простым в обслуживании, но не превращается в контейнер, который страшно перезапускать или обновлять.

Материал подготовил Злой админ