Автоматизация · 12 минут

Как установить n8n на VPS: домен, HTTPS, база и резервные копии

Чтобы установить n8n на VPS, достаточно подготовить Linux-сервер с Docker Compose, привязать домен, запустить n8n вместе с PostgreSQL и настроить обратный прокси Caddy для HTTPS. После первого запуска важно сохранить ключ шифрования, проверить внешние вебхуки и настроить резервные копии. Ниже — последовательность команд для новой установки, а затем проверка восстановления на отдельном сервере.

Редактор n8n со сценарием обработки данных
Пример сценария с запуском по расписанию в редакторе n8n.

Что понадобится до установки

n8n — платформа автоматизации, которая запускает сценарии по расписанию, по HTTP-запросам и по событиям других приложений. VPS (виртуальный частный сервер) позволяет держать её работающей постоянно. В примере используется Ubuntu 24.04 LTS, выделенный публичный IP-адрес, домен и доступ по SSH (Secure Shell — защищённое удалённое подключение). Для небольшого числа простых сценариев можно ориентироваться, например, на 2 виртуальных CPU, 4 ГБ оперативной памяти и 30 ГБ SSD. Это пример конфигурации, а не универсальный минимум: тяжёлые интеграции, одновременные запуски, обработка файлов и AI-узлы потребляют больше ресурсов.

Потребуются права администратора на VPS, возможность менять DNS-записи (Domain Name System — система доменных имён), установленный Docker Engine с Compose plugin и открытые входящие TCP-порты 80 и 443. Учтите расходы на VPS, домен, хранение резервных копий и, при необходимости, внешнюю базу или мониторинг. Цены зависят от провайдера, диска, трафика и региона. Для self-hosted n8n также нужно проверить условия лицензирования, если автоматизация предоставляется как услуга клиентам.

Выбираем схему размещения

В этой инструкции используются три контейнера: PostgreSQL хранит процессы, пользователей и учётные данные; n8n исполняет сценарии; Caddy принимает внешний трафик, получает сертификат TLS (Transport Layer Security) и передаёт запросы n8n. Порт 5678 остаётся внутри сети Docker. Для простой тестовой установки подходит встроенная SQLite, но для длительной эксплуатации, удобных дампов и роста нагрузки разумнее сразу выбрать PostgreSQL. Переход со SQLite на PostgreSQL позднее требует отдельной миграции данных.

Подготовка VPS, DNS и Docker

Подключитесь к Ubuntu по SSH под пользователем с sudo. Сначала установите обновления и вспомогательные пакеты:

sudo apt update && sudo apt upgrade -y
sudo apt install -y ca-certificates curl openssl

Создайте у регистратора A-запись: имя n8n, значение — публичный IPv4 VPS. Во всех примерах n8n.example.com служит заглушкой и должен быть заменён реальным доменом. При использовании IPv6 настройте AAAA-запись только на адрес, по которому сервер действительно доступен. Проверьте разрешение имени:

getent ahostsv4 n8n.example.com

Разрешите SSH до активации межсетевого экрана; для нестандартного SSH-порта замените профиль OpenSSH нужным правилом. У провайдера VPS могут действовать дополнительные сетевые правила.

sudo ufw allow OpenSSH
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw enable
sudo ufw status

Если Docker ещё не установлен, добавьте его официальный репозиторий для Ubuntu:

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
. /etc/os-release
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu ${UBUNTU_CODENAME:-$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
sudo docker compose version

Далее команды Docker показаны с sudo: членство в группе docker фактически предоставляет привилегированный доступ к серверу. Установка через системные пакеты другой ОС требует адаптации команд.

Создаём каталог и переменные окружения

Размещаем проект в /opt/n8n. Файл .env хранит пароль PostgreSQL и постоянный ключ, которым n8n шифрует сохранённые учётные данные. Утеря ключа может сделать восстановленные credentials нечитаемыми, даже если сама база уцелела.

sudo mkdir -p /opt/n8n
sudo chown "$USER":"$USER" /opt/n8n
cd /opt/n8n
umask 077
cat > .env <<'EOF'
N8N_DOMAIN=n8n.example.com
N8N_VERSION=REPLACE_WITH_VERIFIED_STABLE_TAG
POSTGRES_USER=n8n
POSTGRES_DB=n8n
POSTGRES_PASSWORD=REPLACE_WITH_LONG_RANDOM_PASSWORD
N8N_ENCRYPTION_KEY=REPLACE_WITH_LONG_RANDOM_KEY
GENERIC_TIMEZONE=UTC
EOF
chmod 600 .env

Вместо заглушек задайте два разных случайных секрета. Например, дважды выполните openssl rand -hex 32, скопировав каждый результат в соответствующее поле. Для N8N_VERSION укажите точный тег стабильного образа, выбранный после проверки актуального выпуска и изменений версии. Использование latest облегчает первый запуск, но делает последующие обновления менее предсказуемыми. Важна совместимость всей связки: при будущей модернизации отдельно проверяйте изменения n8n и мажорную версию PostgreSQL.

openssl rand -hex 32
openssl rand -hex 32

Настраиваем Docker Compose и HTTPS

Создайте compose.yaml. Здесь PostgreSQL 18 использует PGDATA=/var/lib/postgresql/data, чтобы файлы базы попадали в подключённый том: это особенно важно из-за изменений расположения каталога данных в 18-й ветке. Если у вас уже существует база PostgreSQL другой основной версии, простой смены тега образа недостаточно — потребуется штатное обновление кластера.

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:
      - pgdata:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U $$POSTGRES_USER -d $$POSTGRES_DB"]
      interval: 10s
      timeout: 5s
      retries: 10
  n8n:
    image: docker.n8n.io/n8nio/n8n:${N8N_VERSION}
    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: ${N8N_DOMAIN}
      N8N_PROTOCOL: https
      N8N_PORT: 5678
      N8N_PROXY_HOPS: 1
      WEBHOOK_URL: https://${N8N_DOMAIN}/
      N8N_EDITOR_BASE_URL: https://${N8N_DOMAIN}/
      GENERIC_TIMEZONE: ${GENERIC_TIMEZONE}
      TZ: ${GENERIC_TIMEZONE}
      EXECUTIONS_DATA_PRUNE: "true"
      EXECUTIONS_DATA_MAX_AGE: 336
    volumes:
      - n8ndata:/home/node/.n8n
  caddy:
    image: caddy:2
    restart: unless-stopped
    depends_on:
      - n8n
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./Caddyfile:/etc/caddy/Caddyfile:ro
      - caddydata:/data
      - caddyconfig:/config
volumes:
  pgdata:
  n8ndata:
  caddydata:
  caddyconfig:

Создайте Caddyfile. Имя домена пишется буквально: Caddyfile не подставляет переменную из .env автоматически.

n8n.example.com {
    reverse_proxy n8n:5678
}

Caddy получает и обновляет сертификат для публичного домена, когда DNS указывает на VPS и порты 80/443 доступны. Внешние посетители подключаются по HTTPS, а n8n и Caddy общаются по внутренней сети контейнеров. PostgreSQL не публикует порт 5432, и n8n не публикует 5678. При наличии другого reverse proxy на 80/443 эту схему нужно адаптировать: два сервиса не смогут одновременно занять одни и те же порты.

Запуск и первые проверки

Убедитесь, что заменили все заглушки и записали Caddyfile. Затем проверьте синтаксис Compose, загрузите образы и запустите стек:

cd /opt/n8n
sudo docker compose config --quiet
sudo docker compose pull
sudo docker compose up -d
sudo docker compose ps
sudo docker compose logs --tail=80 n8n
sudo docker compose logs --tail=80 caddy

Откройте https://n8n.example.com и создайте учётную запись владельца. Проверьте адресную строку и действительность сертификата. Отдельно выполните curl -I https://n8n.example.com — ответ не обязательно будет 200, но ошибки TLS или 502 укажут на проблемы. Если сертификат не выдан, проверьте DNS, доступность 80/443 и логи Caddy. Не размещайте .env в публичной директории и не коммитьте его в Git.

Проверяем вебхуки и запуск по расписанию

Webhook — HTTP-адрес, на который внешняя система отправляет событие. В редакторе n8n создайте workflow с узлом Webhook, выберите GET и путь вроде health-demo. Для тестового URL нажмите Listen for test event и откройте показанный адрес: тестовый endpoint обычно работает, пока редактор ожидает событие. Затем активируйте workflow и запросите Production URL — именно он нужен сервисам, которые будут отправлять события постоянно.

curl -i https://n8n.example.com/webhook/health-demo

Конкретный код ответа зависит от настроек узла и наличия активного workflow. Важнее увидеть исполнение в интерфейсе n8n и отсутствие ошибки маршрутизации. Test URL и Production URL различаются, а до активации сценария production webhook может не работать. Значения WEBHOOK_URL и N8N_PROXY_HOPS помогают формировать правильные внешние адреса за обратным прокси. Для Telegram и других интеграций HTTPS зачастую обязателен, а некоторым сервисам требуется подтверждение webhook или определённый формат ответа.

Для проверки расписания создайте отдельный workflow с Schedule Trigger, установите короткий интервал и посмотрите историю запусков. Часовой пояс определяется настройками самого workflow и переменными окружения экземпляра. Важно, чтобы контейнеры не останавливались, а серверные часы синхронизировались.

Что и как резервировать

Для полного восстановления нужны согласованные данные PostgreSQL, том /home/node/.n8n, файл .env с исходным ключом шифрования и конфигурация Compose/Caddy. PostgreSQL содержит workflows и большую часть прикладных данных. В томе n8n могут находиться настройки и локальные файлы. Если бинарные вложения хранятся отдельно, например во внешнем объектном хранилище, включите его в план резервирования. Обычный экспорт workflows не заменяет резервную копию credentials, истории и ключа.

Создаём согласованную копию

Для небольшого проекта удобно выделить короткое окно обслуживания: остановить n8n, оставить PostgreSQL работающим, получить SQL-дамп, затем архивировать том данных и конфигурацию. Команды запускайте из /opt/n8n. В архив попадут секреты, поэтому храните его только в защищённом месте.

cd /opt/n8n
mkdir -p backups
chmod 700 backups
sudo docker compose stop n8n
set -a; . ./.env; set +a
sudo docker compose exec -T postgres pg_dump -U "$POSTGRES_USER" -d "$POSTGRES_DB" -Fc > backups/n8n.dump
test -s backups/n8n.dump || { echo 'Empty backup'; exit 1; }
sudo docker run --rm -v n8n_n8ndata:/source:ro -v "$PWD/backups":/backup alpine tar -C /source -czf /backup/n8ndata.tar.gz .
tar -czf backups/config.tar.gz .env compose.yaml Caddyfile
sudo docker compose start n8n
sha256sum backups/* > backups/SHA256SUMS

Имя Docker-тома по умолчанию складывается из имени проекта и имени тома; для каталога /opt/n8n это обычно n8n_n8ndata. Перед архивированием проверьте фактическое имя командой sudo docker volume ls. Если имя отличается, подставьте его в команду docker run. После успешной копии убедитесь, что n8n вновь запущен. SQL-дамп не включает внешнее файловое хранилище.

Перенесите архивы на другой сервер или в защищённое объектное хранилище, включите шифрование, ограничьте доступ и установите политику хранения. Локальная папка backups на том же VPS защищает лишь от некоторых ошибок, но не от утраты всего сервера. Автоматизируйте резервирование через системный таймер после проверки сценария и отдельно контролируйте успешное завершение, свободное место и срок последней копии.

Проверяем восстановление на отдельном VPS

Тестовое восстановление выполняйте на другом сервере и другом домене, например n8n-restore.example.com. Не подключайте тестовый экземпляр к рабочим webhook-провайдерам: восстановленные активные сценарии могут повторно отправлять сообщения и обрабатывать реальные данные. Для строгой изоляции сначала закройте внешние исходящие подключения тестового окружения, а затем разрешайте лишь необходимые для проверки.

Установите Docker и Compose на чистом VPS. Перенесите резервные архивы в /opt/n8n-restore, распакуйте конфигурацию, замените домен в .env и Caddyfile на тестовый, но сохраните прежний N8N_ENCRYPTION_KEY и пароль базы. Используйте ту же основную версию PostgreSQL и совместимый тег n8n, что и при создании копии. Для этого примера задайте явное имя Compose-проекта n8nrestore во всех командах.

cd /opt/n8n-restore
tar -xzf config.tar.gz
# Отредактируйте N8N_DOMAIN и Caddyfile для тестового домена
sudo docker compose -p n8nrestore up -d --wait postgres
set -a; . ./.env; set +a
sudo docker compose -p n8nrestore exec -T postgres pg_restore -U "$POSTGRES_USER" -d "$POSTGRES_DB" --clean --if-exists --no-owner --exit-on-error < n8n.dump

Команда восстановления должна завершиться с кодом 0. При ошибке остановитесь и проверьте версии PostgreSQL, содержимое архива и доступ к базе; не запускайте приложение с частично восстановленными данными. Важно восстановить том n8n до запуска приложения:

sudo docker volume create n8nrestore_n8ndata
sudo docker run --rm -v n8nrestore_n8ndata:/target -v "$PWD":/backup:ro alpine sh -c 'cd /target && tar -xzf /backup/n8ndata.tar.gz'
sudo docker compose -p n8nrestore up -d
sudo docker compose -p n8nrestore ps

Убедитесь, что доступны сохранённые workflows, пользователи и credentials, а выбранная тестовая интеграция может расшифровать ранее сохранённый секрет. Не запускайте в тестовой среде реальные платёжные, почтовые или производственные сценарии. По окончании проверки отключите тестовый стек, зафиксируйте результат восстановления и уточните допустимое время простоя и потерю последних данных.

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

Перед обновлением n8n прочитайте изменения целевого релиза и сделайте проверенный бэкап. Измените N8N_VERSION на конкретный совместимый тег, затем выполните:

cd /opt/n8n
sudo docker compose pull n8n
sudo docker compose up -d n8n
sudo docker compose logs --tail=100 n8n

Не повышайте основную версию PostgreSQL простой заменой image: новая версия сервера может не открыть прежний каталог данных. Потребуется отдельная процедура pg_upgrade либо дамп и импорт. Контролируйте загрузку процессора, память, объём диска, рост базы, ошибки запусков и срок действия сертификата. Сохранение только контейнера без постоянных volumes приведёт к потере данных после пересоздания.

Когда потребуется другая архитектура

При высокой параллельности пригодятся queue mode, Redis, выделенные workers и отдельные task runners. В n8n 2.x выполнение кода и настройки task runners требуют особого внимания: перед переходом от простой установки к масштабированию проверяйте требования и параметры именно выбранного релиза. Для крупных файлов нужна отдельная стратегия binary data storage. Если инфраструктура уже использует Nginx или Traefik, отдельный Caddy необязателен. Возможен и управляемый n8n Cloud, если не хочется обслуживать VPS, но контроль среды и условия тарификации будут другими.

Сравнить провайдеров →

Частые вопросы

Можно ли поставить n8n без домена?

Локальный тест возможен по IP или через SSH-туннель. Для публичных вебхуков и нормального HTTPS удобнее домен с корректной DNS-записью и сертификатом.

Хватит ли 2 ГБ памяти?

Иногда хватит для очень лёгких сценариев, но вместе с PostgreSQL, прокси и дополнительными процессами запас может быстро закончиться. Оцените потребление на собственной нагрузке; приведённые 4 ГБ — пример отправной конфигурации.

Почему нельзя просто сохранить compose.yaml?

Это лишь описание контейнеров. Сами workflows и credentials находятся в базе, а ключ шифрования и часть данных — в .env и томе n8n. Для восстановления нужен весь набор.

Почему вебхук выдаёт 404?

Проверьте путь, активность workflow и различие тестового и production URL. Затем проверьте WEBHOOK_URL, DNS, HTTPS и журналы Caddy/n8n.

Нужен ли отдельный PostgreSQL-сервер?

Для небольшого проекта PostgreSQL на том же VPS обычно проще. Отдельная управляемая база полезна, когда нужны независимое масштабирование, управляемые копии или более строгая отказоустойчивость.

Можно ли делать бэкап без остановки n8n?

pg_dump поддерживает онлайн-снимок PostgreSQL. Однако для согласования базы с локальными файлами и исключения изменений между копированиями понадобится продуманная процедура. В статье показан вариант с короткой остановкой самого n8n.

Что делать, если потерян N8N_ENCRYPTION_KEY?

Ищите исходное значение в защищённой копии .env или прежних секретах развёртывания. Смена ключа после восстановления базы не расшифрует старые credentials: их, как правило, придётся вводить повторно. Итоговая проверка установки проста: редактор открывается по HTTPS, активный production webhook принимает запросы, расписание создаёт запуски, PostgreSQL и оба постоянных тома сохраняются при пересоздании контейнеров, а свежая резервная копия успешно восстанавливается на отдельном VPS. Только после такой проверки имеет смысл переносить в систему критичные автоматизации.