SSD Nodes Learn Hosting plans →
Посібники Matt ConnorВід Matt Connor · Оновлено 2026-08-27

Як розгорнути n8n на VPS через Docker і HTTPS

Налаштуйте n8n на VPS із Docker Compose, Postgres і reverse proxy. Розберіть пастки WEBHOOK_URL та encryption key і виправте типові помилки.

Що ви створюєте

n8n — це інструмент автоматизації робочих процесів: візуальний редактор, у якому тригер, webhook, розклад або надсилання форми запускає ланцюжок вузлів, що викликають API, змінюють дані та записують їх в інші системи. Він став стандартним засобом інтеграції для робочих процесів з AI-агентами, оскільки взаємодіє з усіма основними постачальниками моделей і базами даних без написання окремого сервісу. Один docker run отримає робочий редактор за дві хвилини. Цей посібник присвячений решті 90%: забезпеченню надійної роботи з Postgres замість стандартного файла SQLite, доступу через HTTPS і, що найчастіше налаштовують неправильно, передаванню webhook URL, до якого зовнішній світ справді може підключитися.

Готовий стек складається з двох контейнерів в одній Docker network: самого n8n і бази даних Postgres, у якій зберігаються його робочі процеси та облікові дані. Reverse proxy на хості завершує TLS і передає запити до n8n через localhost, тому жоден сервіс не доступний з інтернету безпосередньо — лише через цей проксі. Він працює поруч з іншими сервісами з короткого списку self-hosting на 2026 рік.

Передумови та реальні обмеження

Вам потрібен VPS щонайменше з 1 GB RAM. Коли workflows почнуть виконувати реальну роботу, плануйте 2 GB, оскільки executions разом із середовищем виконання Node.js споживають пам’ять. OOM killer, який зупиняє контейнер посеред виконання, — найгірший спосіб виявити це. На початку достатньо одного vCPU.

Якщо на цьому сервері працюватиме ще щось ресурсоємніше, спочатку підберіть конфігурацію під той сервіс. Зазвичай найбільше ресурсів потребує фотобібліотека, а реальні мінімальні вимоги до RAM для PhotoPrism та Immich набагато вищі за вимоги n8n. Те саме стосується медіасервера: Jellyfin разом із frontend для перегляду бібліотеки, наприклад Halcyon, який відтворює формат відеопрокату 90-х, використає доступну RAM і запас ресурсів для transcoding задовго до того, як n8n це помітить.

Вам потрібен домен або піддомен, наприклад n8n.example.com, із A record, що вказує на публічну IP-адресу VPS і доступний до запиту сертифіката. Порти 80 і 443 мають бути відкриті для proxy. Власний порт n8n 5678 не має бути доступним з інтернету. Потрібні Docker Engine і Compose plugin. Якщо docker compose version завершується помилкою docker: 'compose' is not a docker command, у вас стара standalone binary, а plugin має назву sudo apt install docker-compose-plugin.

SQLite підходить для тестування, а для всього важливого використовуйте Postgres

Стандартна база даних n8n — це файл SQLite у /home/node/.n8n/database.sqlite. Для швидкої перевірки цього достатньо: не монтуйте volume, і після першого пересоздання контейнера дані буде втрачено. Це також окремий корисний урок. Причина переходу на Postgres не в максимальній швидкості. SQLite підтримує лише один блокувальний запис, тому екземпляр, який одночасно виконує кілька workflow, або queue mode, який вам зрештою знадобиться, за паралельного виконання видає SQLITE_BUSY: database is locked. У Postgres такого обмеження немає. Його легко резервно копіювати за допомогою pg_dump. Саме Postgres документація n8n рекомендує для сервера, від якого ви залежите. Подальший перехід потребує ручної міграції даних. Тому, якщо цей сервер важливий, одразу використовуйте Postgres.

DNS і firewall

Спочатку налаштуйте 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 зашифрує цим ключем перші облікові дані, його зміна зробить усі облікові дані неможливими для розшифрування. Тому встановіть цей ключ один раз зараз і більше ніколи не змінюйте цей рядок.

Змінні середовища, які визначають роботу webhooks

Чотири змінні визначають, як n8n представляє себе зовнішнім системам. Неправильні значення цих змінних — найчастіша причина звернень до підтримки n8n.

  • N8N_HOST — це публічне ім’я хоста, n8n.example.com. Якщо за проксі залишити значення за замовчуванням localhost, редактор намагається завантажити власний API з localhost у вашому браузері, і це завершується помилкою.
  • N8N_PROTOCOL=https повідомляє n8n, що сервіс працює через TLS. Тому n8n позначає cookie сеансу як Secure і формує URL https://.
  • N8N_PORT=5678 — це порт, на якому n8n приймає з’єднання всередині контейнера. Це не публічний порт: проксі використовує 443.
  • WEBHOOK_URL=https://n8n.example.com/ — змінна, яка найчастіше спричиняє проблеми. n8n формує адреси webhook, які ви вставляєте у Stripe, GitHub або інший зовнішній викликач, на основі цих значень. Якщо змінну не задано або вказано неправильно, n8n використовує N8N_HOST:N8N_PORT і передає вам https://n8n.example.com:5678/webhook/... або, що гірше, http://localhost:5678/webhook/.... Така адреса виводиться без помилки, виглядає правдоподібно, але недоступна з інтернету, тому запити викликачів непомітно не надходять. Укажіть точну публічну базову URL-адресу з кінцевою скісною рискою. Потім переконайтеся, що вузол webhook показує URL без порту.

N8N_PROXY_HOPS=1 повідомляє Express-серверу n8n, що перед ним є один проксі. Завдяки цьому обмеження частоти запитів і всі функції, які визначають IP-адресу клієнта, бачать реальну адресу, а не адресу проксі. Єдина змінна, яку тут навмисно не потрібно задавати, — N8N_RUNNERS_ENABLED. Засоби виконання завдань, у яких n8n запускає логіку 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 із reverse proxy

n8n сам працює через звичайний HTTP на порту 5678; HTTPS завершується на проксі перед ним. Є два прості варіанти.

Якщо ви вже запускаєте кілька контейнерів, розмістіть n8n за reverse proxy Traefik, який автоматично випускає TLS-сертифікати. Для цього достатньо кількох labels: Traefik сам запитає та поновить сертифікат.

Якщо це єдиний застосунок на сервері, простіше налаштувати virtual host nginx із сертифікатом Let’s Encrypt. Скористайтеся налаштуванням TLS для Certbot і nginx в Ubuntu 24.04, щоб отримати сертифікат, а потім використайте цей server block:

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.

Ваш перший workflow: перевіряємо його роботу

Відкрийте https://n8n.example.com/, створіть обліковий запис власника (у наступному розділі) і побудуйте найменший workflow, який підтверджує роботу всього ланцюжка: вхідний webhook, HTTP-виклик і вихідна відповідь.

  1. Додайте вузол Webhook. Встановіть метод POST і шлях на кшталт hello. Вузол показує 2 URL: Test URL і Production URL. Через це часто виникають повідомлення «мій webhook не працює». Test URL приймає 1 виклик і лише після натискання Listen for test event. Після цього URL стає недійсним. Production URL приймає виклики, коли workflow має стан Active.
  2. Після нього додайте вузол HTTP Request і вкажіть будь-який публічний JSON API. GET-запит до https://api.github.com/zen повертає однорядковий рядок, чого достатньо для перевірки.
  3. Додайте вузол Respond to Webhook. Для параметра Respond у вузлі Webhook виберіть «Using Respond to Webhook node», щоб викликач отримав результат роботи HTTP-вузла.
  4. Увімкніть workflow (Active) у правому верхньому куті та виконайте виклик: curl -X POST https://n8n.example.com/webhook/hello. Ви маєте отримати рядок zen у відповіді: POST-запит, API-виклик і вихідна відповідь. Саме так побудована більшість реальних автоматизацій.

У запланованому варіанті вузол Webhook замінюється на Schedule Trigger, а замість нього викликається endpoint моделі. Self-hosted варіант із 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, шифруються в стані спокою за допомогою цього ключа. Робочі процеси в 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 випускає нову minor-версію майже щотижня й інколи змінює схему бази даних або поведінку node між версіями, тому 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

Переходи між major-версіями мають найбільше значення. Наприклад, у лінійці 2.0 значення N8N_BLOCK_ENV_ACCESS_IN_NODE за замовчуванням змінили на true, тому будь-який Code node, який читав process.env, непомітно втрачає доступ, доки ви не повернете значення false; у цьому ж випуску почалася сувора перевірка прав доступу до settings-файлу. Прочитайте сторінку про несумісні зміни у версії 2.0, перш ніж переходити через межу major-версії. n8n автоматично запускає потрібні міграції бази даних під час старту, саме тому попередній pg_dump є обов’язковим. Оскільки облікові дані зберігаються в зашифрованому вигляді за допомогою ключа у .env, а дані — у Postgres, контейнери можна безпечно замінювати: для оновлення замініть їх, а для відкату зафіксуйте попередній тег і відновіть дамп.

Режими відмови та повідомлення, які ви побачите

The requested webhook "POST hello" is not registered. Відповідь 404 з’являється, якщо викликати webhook, workflow якого не має статусу Active, або викликати тестовий шлях, коли ніхто не очікує на подію. Тестові шляхи (/webhook-test/...) відповідають лише після натискання "Listen for test event"; робочі шляхи (/webhook/...) відповідають лише тоді, коли перемикач workflow увімкнено. Сусідній This webhook is not registered for GET requests. Did you mean to make a POST request? означає, що використано неправильний метод: node очікує POST, а ви надіслали GET.

В URL webhook відображається :5678 або localhost. Node показує https://n8n.example.com:5678/webhook/... або http://localhost:5678/.... Змінну WEBHOOK_URL не задано або задано неправильно, тому n8n сформував адресу на основі N8N_HOST:N8N_PORT, а не вашої публічної базової адреси. Задайте WEBHOOK_URL=https://n8n.example.com/, повторно створіть контейнер за допомогою docker compose up -d, і порт зникне.

There was a problem loading init data у браузері. Редактор завантажився, але не може підключитися до власного backend API. За проксі це майже завжди означає неправильні N8N_HOST або WEBHOOK_URL, відсутні в проксі заголовки Upgrade для WebSocket або невідповідність N8N_PROTOCOL способу підключення. Перевірте чотири змінні для публічного доступу та переконайтеся, що проксі передає Upgrade і Connection.

password authentication failed for user "n8n" у журналах, після чого контейнер перезапускається. Пароль, який n8n надсилає базі даних, не збігається з паролем, з яким базу даних було ініціалізовано. Важливий нюанс: Postgres читає POSTGRES_PASSWORD лише під час ініціалізації порожнього каталогу даних. Запустіть stack один раз, потім змініть POSTGRES_PASSWORD у .env, але наявний volume postgres_data для Postgres і далі міститиме старий пароль. Відновіть початкове значення або, якщо збереження даних не потрібне, виконайте docker compose down і docker volume rm для volume Postgres, а потім запустіть stack заново.

EACCES: permission denied, open '/home/node/.n8n/config' під час запуску. n8n працює від імені користувача node (UID 1000) і не може записати дані до свого каталогу конфігурації. Це часто трапляється, якщо каталог на хості підключено через bind mount (./n8n_data:/home/node/.n8n), а власником є root. Використайте іменований volume, показаний вище, або спочатку виконайте sudo chown -R 1000:1000 ./n8n_data, якщо потрібно використати bind mount.

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 записав у свій volume даних під час попереднього запуску. Найчастіше це трапляється, коли під час попереднього запуску змінну не було задано, n8n згенерував випадковий ключ, а згодом ви задали інший. Поверніть початковий ключ у .env або, лише якщо збережені облікові дані вам справді не потрібні, видаліть файл config у volume n8n_data і дозвольте n8n створити його заново. У такому разі наявні облікові дані стануть недоступними для читання.

Повідомлення під час входу про захищені cookies: 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/. Лише якщо HTTPS справді неможливий, задайте N8N_SECURE_COOKIE=false і ніколи не використовуйте це на сервері, доступному з Інтернету.

Щоб додати мовну модель до цих workflow, див. створення AI workflow із Claude і n8n.

FAQ

Чи варто використовувати SQLite або Postgres для n8n?

SQLite (типове сховище) підходить для ознайомлення з n8n і персонального екземпляра, який виконує один workflow за раз. Для всього, від чого ви залежите, перейдіть на Postgres: блокування єдиного записувача в SQLite спричиняє database is locked за паралельного виконання, а Postgres дає змогу коректно створювати резервні копії за допомогою pg_dump. Подальша міграція виконується вручну, тому для важливого сервера одразу використовуйте Postgres.

Чому мої webhook в n8n ніколи не спрацьовують?

Майже завжди причина — WEBHOOK_URL. Якщо значення не задано або воно неправильне, n8n виводить адреси webhook, сформовані на основі N8N_HOST:N8N_PORT, часто з :5678 або localhost у них. Такі адреси виглядають коректними, але недоступні з Інтернету, тому запити від викликачів не надходять. Задайте WEBHOOK_URL=https://n8n.example.com/ і переконайтеся, що node показує URL без порту. Друга причина — виклик webhook, workflow якого не переведено в стан Active. У такому разі повертається The requested webhook ... is not registered.

Що потрібно резервно копіювати в n8n?

Дві речі. N8N_ENCRYPTION_KEY із вашого файла .env, оскільки всі збережені облікові дані шифруються за допомогою нього, а після його втрати їх неможливо розшифрувати. Скопіюйте цей ключ на інший носій у день його створення. Також потрібна pg_dump бази даних Postgres, що містить workflow, історію та облікові дані. Для відновлення потрібні обидва компоненти: той самий ключ і дамп.

Як розмістити n8n за HTTPS?

n8n обслуговує звичайний HTTP на порту 5678, а reverse proxy перед ним завершує TLS. Прив’яжіть n8n до 127.0.0.1:5678, щоб доступ до нього мав лише проксі, а потім використайте Traefik з автоматичним отриманням сертифікатів або nginx із сертифікатом Let's Encrypt. Задайте N8N_PROTOCOL=https і WEBHOOK_URL=https://your-host/ та переконайтеся, що проксі передає заголовки Upgrade для WebSocket. Інакше редактор зависає.

Як безпечно оновити n8n?

Зафіксуйте конкретний тег образу замість latest. Спочатку створіть pg_dump, оскільки n8n автоматично виконує міграції під час запуску. Прочитайте примітки до випуску на предмет несумісних змін, потім змініть тег і виконайте docker compose pull n8n && docker compose up -d n8n. Контейнер можна відтворити, тому для відкату достатньо зафіксувати попередній тег і відновити дамп, створений до оновлення.