Установка n8n на VPS через Docker и HTTPS
Пошаговое руководство по развертыванию n8n с базой данных Postgres и обратным прокси. Узнайте, как правильно настроить переменную WEBHOOK_URL и избежать ошибок доступа.
Что вы создаете
n8n — это инструмент для автоматизации рабочих процессов: визуальный редактор, в котором триггер, вебхук, расписание или отправка формы запускают цепочку узлов, вызывающих API, преобразующих данные и записывающих их в другие системы. Он стал стандартным связующим звеном для рабочих процессов ИИ-агентов, так как взаимодействует с любым поставщиком моделей и базой данных без необходимости написания собственного сервиса. Один docker run позволяет получить работающий редактор за две минуты. Это руководство посвящено остальным девяноста процентам: обеспечению надежности с помощью Postgres вместо стандартного файла SQLite, доступности по HTTPS и тому, в чем почти все ошибаются — настройке вебхуков так, чтобы они выдавали URL, доступный извне.
Итоговый стек состоит из двух контейнеров в одной сети Docker: самого n8n и базы данных Postgres, хранящей рабочие процессы и учетные данные. Обратный прокси-сервер на хосте выполняет TLS termination и перенаправляет запросы на n8n через localhost, поэтому ни один сервис не выходит в интернет напрямую, минуя прокси. Он размещается вместе с другими сервисами из списка для self-hosting на 2026 год.
Предварительные требования и реальные ограничения
Вам нужен VPS минимум с 1 GB RAM. Планируйте 2 GB, когда рабочие процессы начнут выполнять реальные задачи: сами выполнения и среда выполнения Node.js потребляют память, а остановка контейнера механизмом out-of-memory killer посреди выполнения — плохой способ обнаружить это. Для начала достаточно 1 vCPU.
Если на этом сервере будет работать что-то более ресурсоёмкое, сначала подберите конфигурацию для такого сервиса. Обычно таким сервисом оказывается фотоархив: реальные минимальные требования PhotoPrism и Immich к RAM значительно выше требований n8n.
То же относится к медиасерверу. Сервер Jellyfin и веб-интерфейс для просмотра его библиотеки, например Halcyon, который оформляет библиотеку как видеопрокат из 90-х, потребуют доступную RAM и ресурсы для транскодирования задолго до того, как это заметит n8n.
Вам необходим домен или поддомен, например n8n.example.com, с A-записью, указывающей на публичный IP-адрес VPS, которая должна корректно разрешаться до запроса сертификата. Порты 80 и 443 должны быть открыты для прокси-сервера; собственный порт n8n 5678 не должен быть доступен из интернета. Вам потребуются Docker Engine и плагин Compose; если команда docker compose version выдает ошибку docker: 'compose' is not a docker command, значит, у вас установлена старая автономная версия, а плагин — это sudo apt install docker-compose-plugin.
SQLite подходит для тестирования, Postgres — для рабочих задач
База данных n8n по умолчанию — это файл SQLite, расположенный по пути /home/node/.n8n/database.sqlite. Для ознакомления этого достаточно; если не монтировать том, данные будут потеряны при первом же пересоздании контейнера, что само по себе является полезным уроком. Переход на Postgres нужен не ради прироста скорости, а потому что SQLite использует блокировку записи для одного процесса. В результате при одновременном выполнении нескольких рабочих процессов или при использовании режима очереди, который вам рано или поздно понадобится, возникнет ошибка SQLITE_BUSY: database is locked из-за конкурентного доступа. У Postgres таких ограничений нет, он корректно поддерживает резервное копирование через pg_dump и является стандартом, который подразумевается в документации n8n для серверов, используемых в продакшене. Перенос данных вручную после запуска потребует усилий, поэтому, если этот сервер важен, начинайте работу сразу с Postgres.
DNS и межсетевой экран
Сначала настройте DNS-запись и откройте порты, чтобы на этапе получения сертификата не возникло ошибок из-за того, что имя не разрешается.
dig +short n8n.example.com
curl -s ifconfig.me
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw allow OpenSSH
sudo ufw enableНе открывайте порт 5678. Файл compose привязывает n8n к 127.0.0.1:5678, поэтому доступ к нему возможен только через reverse proxy на хосте, а ufw allow 5678 нарушит эту изоляцию.
Файл Compose
Создайте рабочую директорию и файл docker-compose.yml. Это полный стек: два сервиса, одна изолированная сеть и два именованных тома.
services:
postgres:
image: postgres:16-alpine
restart: unless-stopped
environment:
POSTGRES_USER: n8n
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
POSTGRES_DB: n8n
volumes:
- postgres_data:/var/lib/postgresql/data
networks:
- n8n_net
healthcheck:
test: ["CMD-SHELL", "pg_isready -U n8n -d n8n"]
interval: 10s
timeout: 5s
retries: 5
n8n:
image: docker.n8n.io/n8nio/n8n:2.29.10
restart: unless-stopped
ports:
- "127.0.0.1:5678:5678"
environment:
- N8N_HOST=n8n.example.com
- N8N_PORT=5678
- N8N_PROTOCOL=https
- WEBHOOK_URL=https://n8n.example.com/
- N8N_ENCRYPTION_KEY=${N8N_ENCRYPTION_KEY}
- N8N_PROXY_HOPS=1
- GENERIC_TIMEZONE=Europe/London
- DB_TYPE=postgresdb
- DB_POSTGRESDB_HOST=postgres
- DB_POSTGRESDB_PORT=5432
- DB_POSTGRESDB_DATABASE=n8n
- DB_POSTGRESDB_USER=n8n
- DB_POSTGRESDB_PASSWORD=${POSTGRES_PASSWORD}
volumes:
- n8n_data:/home/node/.n8n
networks:
- n8n_net
depends_on:
postgres:
condition: service_healthy
volumes:
postgres_data:
n8n_data:
networks:
n8n_net:Стоит сразу пояснить несколько принятых решений. DB_POSTGRESDB_HOST=postgres — это имя сервиса, которое Docker использует для разрешения имен в общей сети, в отличие от localhost, которое внутри контейнера n8n указывает на сам n8n. Параметр depends_on с condition: service_healthy предотвращает конфликт при запуске, когда n8n пытается подключиться к Postgres раньше, чем база данных будет готова; без него n8n запускается, не находит базу и завершает работу. Именованный том n8n_data в директории /home/node/.n8n хранит ключ шифрования и, при использовании SQLite, саму базу данных — это единственный каталог, который нельзя терять. Фиксируйте версию образа, никогда не используйте latest; причины этого описаны в разделе об обновлении ниже.
Файл секретов
Никогда не указывайте пароли в файле compose. Разместите их в файле .env рядом с ним, который Compose считывает автоматически, и генерируйте их так, чтобы они были действительно случайными.
printf 'POSTGRES_PASSWORD=%s\n' "$(openssl rand -hex 24)" > .env
printf 'N8N_ENCRYPTION_KEY=%s\n' "$(openssl rand -hex 32)" >> .env
chmod 600 .envПараметр N8N_ENCRYPTION_KEY является здесь самой важной строкой, это ключ, которым шифруются все сохраненные учетные данные. Установите его явно, вместо того чтобы позволять n8n генерировать его самостоятельно, так как значение, которое вы создали, можно записать и восстановить. Как только n8n зашифрует свои первые учетные данные этим ключом, изменение ключа сделает все учетные данные нерасшифровываемыми, поэтому установите его один раз, сейчас, и больше никогда не меняйте эту строку.
Переменные окружения, определяющие работу вебхуков
Четыре переменные определяют, как n8n представляет себя внешнему миру. Ошибки в их настройке — самая частая причина обращений в поддержку n8n.
N8N_HOST— это публичное имя хоста,n8n.example.com. Если оставить значение по умолчаниюlocalhostпри работе за прокси, редактор попытается загрузить собственный API изlocalhostпрямо в вашем браузере, что приведет к ошибке.N8N_PROTOCOL=httpsсообщает n8n, что сервис работает через TLS. В результате n8n помечает сессионную куку какSecureи формирует URL сhttps://.N8N_PORT=5678— это порт, на котором n8n слушает запросы внутри контейнера. Это не публичный порт; публичный порт 443 занят прокси-сервером.WEBHOOK_URL=https://n8n.example.com/— самая коварная переменная. n8n формирует адреса вебхуков, которые вы копируете в Stripe, GitHub или другие внешние сервисы, основываясь на этих значениях. Если переменная не задана или указана неверно, n8n используетN8N_HOST:N8N_PORTи выдаетhttps://n8n.example.com:5678/webhook/...или, что еще хуже,http://localhost:5678/webhook/.... Эти адреса выглядят правдоподобно, не вызывают ошибок при отображении, но недоступны из Интернета, поэтому запросы от внешних систем просто не доходят до сервера. Установите точный публичный базовый URL с косой чертой в конце, а затем убедитесь, что узел вебхука отображает URL без указания порта.
N8N_PROXY_HOPS=1 указывает Express-серверу n8n, что нужно доверять одному прокси-серверу перед ним. Это позволяет функциям ограничения частоты запросов (rate-limiting) и другим механизмам, считывающим IP клиента, видеть реальный адрес, а не адрес прокси. Переменная, которую здесь намеренно не нужно указывать — это N8N_RUNNERS_ENABLED: выполнение задач через task runners (запуск логики Code-node в отдельном изолированном процессе) стало стандартом начиная с версии 1.69 и является обязательным для ветки 2.x, на которой базируется это руководство, поэтому старый механизм включения признан устаревшим. Если вы установите эту переменную сейчас, n8n просто выведет в лог уведомление с требованием удалить её.
Первый запуск
docker compose up -d
docker compose ps
docker compose logs -f n8nУспешный первый запуск завершается строкой Editor is now accessible via:, над которой находится строка n8n ready on ..., port 5678. В docker compose ps должны отображаться оба контейнера Up, при этом postgres будет помечен как (healthy). Если n8n находится в цикле Restarting, изучите логи: почти всегда проблема заключается в подключении к базе данных или правах доступа к томам, описанных ниже.
Использование TLS с обратным прокси-сервером
Сам n8n работает по обычному HTTP на порту 5678; терминацию HTTPS выполняет внешний компонент. Есть два оптимальных варианта.
Если вы уже используете несколько контейнеров, разместите n8n за обратным прокси-сервером Traefik, который автоматически выпускает TLS-сертификаты. С помощью нескольких меток Traefik самостоятельно запросит и обновит сертификат для вас.
Если это единственное приложение на сервере, проще использовать виртуальный хост nginx с сертификатом Let's Encrypt. Воспользуйтесь инструкцией по настройке TLS с помощью Certbot и nginx для Ubuntu 24.04 для получения сертификата, а затем примените следующий блок конфигурации сервера:
server {
listen 443 ssl;
server_name n8n.example.com;
ssl_certificate /etc/letsencrypt/live/n8n.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/n8n.example.com/privkey.pem;
location / {
proxy_pass http://127.0.0.1:5678;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_read_timeout 3600;
client_max_body_size 16m;
}
}Заголовки Upgrade и Connection "upgrade" обязательны. n8n передает обновления о ходе выполнения в редактор через WebSocket, и без этих двух строк страница входа загрузится, но зависнет с сообщением о потере соединения. Параметр proxy_read_timeout 3600 предотвращает принудительное завершение длительных процессов по истечении стандартного тайм-аута nginx в 60 секунд. Заголовок X-Forwarded-Proto $scheme дополняет N8N_PROXY_HOPS=1: он сообщает n8n, что исходный запрос был выполнен по HTTPS, даже если прокси обращается к приложению по обычному HTTP. Это необходимо, чтобы n8n не счел соединение небезопасным и не отклонил собственный cookie.
Ваш первый рабочий процесс: переходим к практике
Откройте https://n8n.example.com/, создайте учетную запись владельца (следующий раздел) и создайте простейший рабочий процесс, который подтвердит работоспособность пути: входящий webhook, HTTP-запрос и исходящий ответ.
- Добавьте узел Webhook. Установите метод
POSTи путь, напримерhello. Он отобразит два URL: Test URL и Production URL. Именно с ними связано большинство жалоб вида «мой webhook не работает». Test URL отвечает на один запрос и только пока вы нажали кнопку Listen for test event; после этого он перестает работать. Production URL отвечает всегда, когда рабочий процесс находится в состоянии Active. - Добавьте после него узел HTTP Request, направленный на любой публичный JSON API. GET-запрос к
https://api.github.com/zenвозвращает строку из одной линии, чего вполне достаточно. - Добавьте узел Respond to Webhook и установите в узле Webhook параметр Respond в значение "Using Respond to Webhook node", чтобы вызывающая сторона получила результат работы узла HTTP.
- Переключите рабочий процесс в состояние Active (в правом верхнем углу) и вызовите его:
curl -X POST https://n8n.example.com/webhook/hello. Вы должны получить обратно строку zen. POST-запрос на входе, вызов API, ответ на выходе — это базовая структура большинства реальных сценариев автоматизации.
Вариант с расписанием заменяет узел Webhook на Schedule Trigger и вызывает конечную точку модели. Использование локально развернутой модели из Ollama, запущенной на том же VPS — это удобный способ настроить ночное создание сводок.
Управление пользователями вместо basic auth
Старые руководства по n8n рекомендуют задать N8N_BASIC_AUTH_ACTIVE=true. В n8n 1.0 эти переменные удалили, и теперь они не работают. Сейчас используется учётная запись владельца: при первой загрузке редактора n8n предлагает создать владельца с email и паролем. Эта проверка обязательна, а анонимный режим отсутствует. Создайте учётную запись сразу после первого запуска, до того как передать кому-либо URL: в период между docker compose up и отправкой первой формы экземпляр может присвоить себе тот, кто первым получит к нему доступ. Дополнительный слой basic auth на reverse proxy — разумная мера защиты, но это второй уровень, а не основная аутентификация. Учётная запись владельца и все остальные функции из этого руководства доступны в бесплатной community edition. Если позже понадобятся дополнительные пользователи с детальными ролями или SSO, перед планированием такой конфигурации ознакомьтесь с материалом какие функции n8n требуют платной лицензии.
Резервное копирование: сначала ключ шифрования, затем база данных
Необходимо создавать резервные копии двух компонентов, и их ценность неравнозначна.
N8N_ENCRYPTION_KEY. Все учетные данные, которые вы храните в n8n, API-токены, пароли от баз данных, OAuth-секреты — всё это зашифровано данным ключом. Рабочие процессы (workflows) в Postgres бесполезны без него: если восстановить базу данных на новом сервере с другим ключом, n8n не сможет расшифровать ни одну учетную запись, и восстановить доступ или сбросить настройки будет невозможно. Ваш файл .env содержит этот ключ; скопируйте его на внешний носитель в день создания, лучше всего — в менеджер паролей. Это самая важная часть резервной копии.
База данных Postgres, содержащая рабочие процессы, историю выполнения и сами зашифрованные учетные данные:
docker compose exec -T postgres pg_dump -U n8n -d n8n \
| gzip > n8n-db-$(date +%F).sql.gzЗапускайте эту команду по расписанию и копируйте дамп за пределы сервера. Для восстановления на новом VPS: запустите стек один раз, чтобы база данных была создана, остановите n8n, загрузите дамп с помощью psql, поместите тот же самый N8N_ENCRYPTION_KEY в .env и запустите n8n. Тот же ключ плюс дамп обеспечивают работоспособность экземпляра; новый ключ означает, что рабочие процессы не смогут использовать ни одну учетную запись.
Обновления: фиксация тега
В файле compose намеренно зафиксирована версия n8nio/n8n:2.29.10, а не latest. n8n выпускает новые минорные версии почти каждую неделю, и иногда они содержат изменения схемы базы данных или поведения узлов. Поэтому использование latest означает, что автоматическое обновление может загрузить сборку, которая выполнит миграцию базы данных сразу после запуска. Фиксируйте версию, читайте примечания к выпуску перед обновлением — n8n указывает там на критические изменения — и выполняйте обновление осознанно:
docker compose exec -T postgres pg_dump -U n8n -d n8n | gzip > pre-upgrade.sql.gz
# edit the image tag in docker-compose.yml, then:
docker compose pull n8n
docker compose up -d n8n
docker compose logs -f n8nЭто особенно важно при переходе между мажорными версиями. Например, в ветке 2.0 по умолчанию изменилось значение N8N_BLOCK_ENV_ACCESS_IN_NODE на true, поэтому любой узел Code, считывающий process.env, без предупреждения теряет доступ, пока вы не вернете настройку обратно на false; тот же релиз ввел строгие проверки прав доступа к файлу настроек. Ознакомьтесь со страницей критических изменений 2.0 перед переходом на новую мажорную версию. n8n автоматически выполняет необходимые миграции базы данных при запуске, именно поэтому создание резервной копии pg_dump перед обновлением является обязательным. Поскольку учетные данные хранятся в зашифрованном виде с использованием ключа в .env, а данные находятся в Postgres, контейнеры являются временными: вы обновляете их путем замены, а откатываетесь назад, фиксируя предыдущий тег и восстанавливая дамп.
Режимы сбоев и соответствующие им сообщения
The requested webhook "POST hello" is not registered. Ошибка 404 при вызове вебхука, чей рабочий процесс не переведён в состояние Active, или при обращении к тестовому пути, когда прослушивание не запущено. Тестовые пути (/webhook-test/...) отвечают только тогда, когда вы нажали «Listen for test event»; производственные пути (/webhook/...) отвечают только при включённом переключателе рабочего процесса. Аналогичная ошибка This webhook is not registered for GET requests. Did you mean to make a POST request? означает, что выбран неверный метод: узел ожидает POST, а вы отправили GET.
URL вебхука содержит :5678 или localhost. Узел отображает https://n8n.example.com:5678/webhook/... или http://localhost:5678/.... Переменная WEBHOOK_URL не задана или указана неверно, поэтому n8n сформировал адрес на основе N8N_HOST:N8N_PORT вместо вашего публичного базового URL. Установите WEBHOOK_URL=https://n8n.example.com/, пересоздайте контейнер с помощью docker compose up -d, и номер порта исчезнет из адреса.
There was a problem loading init data в браузере. Редактор загрузился, но не может связаться с собственным API бэкенда. При работе через прокси это почти всегда означает неверный N8N_HOST или WEBHOOK_URL, отсутствие в прокси заголовков WebSocket Upgrade или несоответствие N8N_PROTOCOL способу вашего подключения. Проверьте четыре публичные переменные и убедитесь, что прокси передаёт Upgrade и Connection.
password authentication failed for user "n8n" в логах, контейнер постоянно перезапускается. Пароль, который передаёт n8n, не совпадает с тем, с которым была инициализирована база данных. Ловушка: Postgres считывает POSTGRES_PASSWORD только при инициализации пустой директории данных. Если вы запустили стек один раз, а затем изменили POSTGRES_PASSWORD в .env, существующий том postgres_data всё ещё хранит старый пароль. Верните исходное значение или, если данные не представляют ценности, выполните docker compose down и docker volume rm для тома postgres, после чего запустите систему заново.
EACCES: permission denied, open '/home/node/.n8n/config' при запуске. n8n работает от имени пользователя node (UID 1000) и не может записать данные в свою директорию конфигурации. Это происходит при монтировании папки хоста (./n8n_data:/home/node/.n8n), владельцем которой является root. Используйте именованный том, как показано выше, или, если вы настаиваете на bind mount, сначала выполните sudo chown -R 1000:1000 ./n8n_data.
Permissions 0644 for n8n settings file /home/node/.n8n/config are too wide. Changing permissions to 0600.. Начиная с версии 2.x, n8n по умолчанию применяет 0600 к файлу настроек и исправляет его при загрузке. Эта строка лога означает, что система уже скорректировала права доступа, что обычно случается после bind mount или восстановления файла из резервной копии с избыточными правами. Никаких действий не требуется; устанавливайте N8N_ENFORCE_SETTINGS_FILE_PERMISSIONS=false только в том случае, если ваша файловая система принципиально не поддерживает права доступа.
Mismatching encryption keys, полная строка сообщения указывает, что ключ шифрования в файле настроек /home/node/.n8n/config не совпадает с N8N_ENCRYPTION_KEY в вашем окружении. Ключ в окружении отличается от того, который n8n записал в том данных при предыдущем запуске. Чаще всего это происходит, если n8n сгенерировал случайный ключ при первом запуске, когда переменная не была задана, а затем вы установили другое значение. Верните исходный ключ в .env или, если у вас действительно нет сохранённых учётных данных, которые нужно сохранить, удалите файл config внутри тома n8n_data и позвольте n8n сгенерировать его заново, приняв тот факт, что существующие учётные данные станут нечитаемыми.
Предупреждение при входе о безопасных cookie: Your n8n server is configured to use a secure cookie, however you are either visiting this via an insecure URL, or using Safari. Вы установили N8N_PROTOCOL=https, но обращаетесь к n8n по обычному HTTP, обычно напрямую по IP и порту, а не через HTTPS-прокси. Обращайтесь к нему через https://n8n.example.com/. Устанавливайте N8N_SECURE_COOKIE=false только в том случае, если вы действительно не можете использовать HTTPS, и никогда не делайте этого на сервере, доступном из Интернета.
Чтобы добавить языковую модель в рабочие процессы, см. создание рабочих процессов с ИИ с использованием Claude и n8n.
FAQ
Стоит ли использовать SQLite или Postgres для n8n?
SQLite (настройка по умолчанию) подходит для ознакомления с n8n и для личного экземпляра, выполняющего один рабочий процесс за раз. Переходите на Postgres для любых критически важных задач: блокировка единственного писателя в SQLite вызывает database is locked при конкурентных запросах, а Postgres корректно резервируется с помощью pg_dump. Миграция в будущем выполняется вручную, поэтому, если сервер важен, начинайте сразу с Postgres.
Почему мои вебхуки n8n не срабатывают?
Почти всегда причина в WEBHOOK_URL. Если переменная не задана или указана неверно, n8n формирует адреса вебхуков на основе N8N_HOST:N8N_PORT, часто включая в них :5678 или localhost. Они выглядят корректно, но недоступны из интернета, поэтому запросы отправителя не доходят до сервера. Установите WEBHOOK_URL=https://n8n.example.com/ и убедитесь, что узел отображает URL без указания порта. Вторая причина — вызов вебхука, рабочий процесс которого не переведён в состояние Active, что возвращает The requested webhook ... is not registered..
Что именно нужно резервировать в n8n?
Две вещи. N8N_ENCRYPTION_KEY из вашего файла .env, так как все сохранённые учётные данные зашифрованы с его помощью, и его потеря делает их навсегда нечитаемыми; скопируйте его с сервера в день создания. И pg_dump базы данных Postgres, содержащий рабочие процессы, историю и учётные данные. Для восстановления требуются оба компонента: тот же ключ и дамп базы.
Как настроить HTTPS для n8n?
n8n работает по обычному HTTP на порту 5678; обратный прокси-сервер перед ним выполняет TLS termination. Привяжите n8n к 127.0.0.1:5678, чтобы доступ к нему имел только прокси, затем используйте Traefik с автоматическими сертификатами или nginx с сертификатом Let's Encrypt. Установите N8N_PROTOCOL=https и WEBHOOK_URL=https://your-host/ и убедитесь, что прокси передаёт заголовки WebSocket Upgrade, иначе редактор зависнет.
Как безопасно обновить n8n?
Закрепите конкретный тег образа вместо latest, сначала сделайте pg_dump, так как n8n автоматически выполняет миграции при запуске, ознакомьтесь с примечаниями к выпуску на предмет критических изменений, затем измените тег и выполните docker compose pull n8n && docker compose up -d n8n. Контейнер является временным объектом, поэтому откат выполняется путём возврата к предыдущему тегу и восстановления дампа, сделанного до обновления.