Dealownia
Menu
sprawdzono – jak sprawdzamy oferty

n8n na własnym VPS: Docker Compose, Postgres i webhooki

n8n w Dockerze z bazą PostgreSQL, nginx z WebSocketem i HTTPS, poprawny adres webhooków, kopie klucza i bazy oraz co naprawdę pozwala licencja Sustainable Use.

Aplikacje na własnym serwerzezaktualizowano 8 min czytania

Redakcja serwisu Dealownia · ceny i fakty ze stron dostawców, jak sprawdzamy

n8n pod adresem https://n8n.example.pl, z bazą PostgreSQL zamiast domyślnego SQLite, z webhookami dostępnymi z internetu pod właściwym adresem i z kopią, z której da się odtworzyć instancję razem z zapisanymi danymi logowania. Wersja Community jest darmowa i nie ma limitu liczby uruchomień. Na końcu wyjaśniamy, co wolno z nią robić według licencji Sustainable Use, a kiedy rozsądniej zapłacić za n8n Cloud.

Czego potrzebujesz

  • VPS z Ubuntu 24.04 LTS (albo Debianem 12 lub 13) przygotowany jak w poradniku od zera: użytkownik z sudo, ufw, nginx na hoście, Docker z wtyczką Compose.
  • Minimum: 1 vCPU, 2 GB RAM, 20 GB dysku. Dokumentacja n8n podaje przykładowe zapotrzebowanie pojedynczej instancji od 320 MB do 2 GB pamięci i zaznacza, że pamięć jest ważniejsza od procesora; bezczynna instancja zajmuje około 100 MB. Do tego dochodzi Postgres i system. Workflowy przetwarzające duże pliki lub tysiące elementów naraz potrzebują więcej.
  • Subdomenę n8n.example.pl z rekordem A wskazującym serwer.

Na n8n z Postgresem wybierz plan z co najmniej 2 GB RAM.

Jeśli porównujesz plany pod kątem pamięci, zajrzyj do rankingu VPS.

Krok 1. Katalog i sekrety

bash
sudo mkdir -p /opt/apps/n8n && sudo chown deploy:deploy /opt/apps/n8n
cd /opt/apps/n8n
cat > .env <<EOF
N8N_DB_PASSWORD=$(openssl rand -hex 24)
N8N_ENCRYPTION_KEY=$(openssl rand -hex 32)
EOF
chmod 600 .env
mkdir -p backup && sudo chown 1000:1000 backup && sudo chmod 700 backup

N8N_ENCRYPTION_KEY szyfruje zapisane w bazie dane logowania (tokeny API, hasła do skrzynek). Gdy go nie ustawisz, n8n wygeneruje klucz przy pierwszym starcie i zapisze go w katalogu /home/node/.n8n. Ustawienie go jawnie sprawia, że wiesz, gdzie jest i co trzeba skopiować. Zgub klucz, a kopia bazy będzie miała zaszyfrowane dane, których nie odczytasz. Katalog backup należy do UID 1000, bo jako ten użytkownik (node) działa proces w oficjalnym obrazie.

Krok 2. Plik compose.yaml

yaml
services:
  n8n:
    image: n8nio/n8n:latest
    restart: unless-stopped
    ports:
      - "127.0.0.1:5678:5678"
    environment:
      DB_TYPE: postgresdb
      DB_POSTGRESDB_HOST: db
      DB_POSTGRESDB_PORT: 5432
      DB_POSTGRESDB_DATABASE: n8n
      DB_POSTGRESDB_USER: n8n
      DB_POSTGRESDB_PASSWORD: ${N8N_DB_PASSWORD}
      N8N_ENCRYPTION_KEY: ${N8N_ENCRYPTION_KEY}
      N8N_HOST: n8n.example.pl
      N8N_PORT: 5678
      N8N_PROTOCOL: https
      N8N_WEBHOOK_URL: https://n8n.example.pl/
      N8N_PROXY_HOPS: 1
      NODE_ENV: production
      GENERIC_TIMEZONE: Europe/Warsaw
      TZ: Europe/Warsaw
      N8N_ENFORCE_SETTINGS_FILE_PERMISSIONS: "true"
    volumes:
      - n8n_data:/home/node/.n8n
      - ./backup:/backup
    depends_on:
      db:
        condition: service_healthy

  db:
    image: postgres:17-alpine
    restart: unless-stopped
    environment:
      POSTGRES_DB: n8n
      POSTGRES_USER: n8n
      POSTGRES_PASSWORD: ${N8N_DB_PASSWORD}
    volumes:
      - ./data/postgres:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U n8n -d n8n"]
      interval: 10s
      timeout: 5s
      retries: 10

volumes:
  n8n_data:

Co tu jest ważne:

  • Nazwy zmiennych DB_POSTGRESDB_* pochodzą z dokumentacji baz danych n8n. n8n wspiera PostgreSQL 17 i 18 (16 jeszcze ze względu na zgodność). Bez DB_TYPE n8n używa SQLite – na jedną osobę to wystarcza, ale Postgres łatwiej kopiować w trakcie pracy i lepiej znosi wiele równoległych uruchomień.
  • N8N_WEBHOOK_URL to publiczny adres webhooków. Za reverse proxy n8n nie zgadnie go sam: składa go z N8N_PROTOCOL, N8N_HOST i N8N_PORT i podałby adres z portem 5678. Według dokumentacji n8n (sprawdzonej 11.11.2026) zmienna działa od n8n 2.30; w starszych wersjach nazywa się WEBHOOK_URL, a od 2.35 ta stara nazwa jest przestarzała i n8n zapisuje w logu ostrzeżenie.
  • N8N_PROXY_HOPS: 1 mówi n8n, że przed nim stoi jeden serwer proxy, więc ma ufać nagłówkom X-Forwarded-*.
  • GENERIC_TIMEZONE decyduje o strefie węzła Schedule. Bez niej domyślna strefa to Nowy Jork i zadanie „codziennie o 8:00” ruszy po polskim czasie o 14:00.
  • Wolumen n8n_data zostaje także przy Postgresie – dokumentacja Dockera n8n zaleca go, bo trzyma tam plik ustawień i klucz.
  • Port tylko na 127.0.0.1. Opublikowany port Dockera omija ufw.

latest to bieżące stabilne wydanie. Na serwerze, od którego coś zależy, przypnij konkretny numer wersji z listy wydań i podnoś go świadomie.

bash
docker compose up -d
docker compose ps
docker compose logs -f n8n

Czekasz na komunikat, że edytor jest dostępny pod adresem z N8N_HOST.

Krok 3. nginx z WebSocketem

Edytor n8n odbiera wyniki uruchomień przez połączenie WebSocket, więc proxy musi przekazywać nagłówki Upgrade i Connection. Konfiguracja korzysta ze zmiennej $connection_upgrade z mapy WebSocket. Mapę WebSocket tworzysz raz na serwer (wyjaśnienie w poradniku o reverse proxy); polecenie niżej nic nie zmieni, jeśli plik już istnieje:

bash
[ -f /etc/nginx/conf.d/websocket-map.conf ] || sudo tee /etc/nginx/conf.d/websocket-map.conf >/dev/null <<'EOF'
map $http_upgrade $connection_upgrade {
    default upgrade;
    ''      close;
}
EOF

Plik /etc/nginx/sites-available/n8n.example.pl:

nginx
server {
    listen 80;
    listen [::]:80;
    server_name n8n.example.pl;

    client_max_body_size 16m;

    location / {
        proxy_pass http://127.0.0.1:5678;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection $connection_upgrade;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Host $host;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_read_timeout 300s;
    }
}
bash
sudo ln -s /etc/nginx/sites-available/n8n.example.pl /etc/nginx/sites-enabled/
sudo nginx -t && sudo systemctl reload nginx
sudo certbot --nginx -d n8n.example.pl

client_max_body_size podnosi domyślny limit nginx (1 MB) – webhook z załącznikiem łatwo go przekracza. proxy_read_timeout 300s daje dłuższym workflowom z odpowiedzią „na końcu” czas na zakończenie, zanim nginx zwróci 504. Szczegóły nagłówków i limitów są w poradniku o reverse proxy.

Wejdź na https://n8n.example.pl i załóż konto właściciela. Zrób to od razu – do czasu założenia konta każdy, kto trafi na adres, może je przejąć.

Krok 4. Webhooki

Węzeł Webhook pokazuje dwa adresy:

  • testowy https://n8n.example.pl/webhook-test/... – działa tylko wtedy, gdy w edytorze klikniesz nasłuchiwanie testowego zdarzenia, i tylko dla jednego wywołania;
  • produkcyjny https://n8n.example.pl/webhook/... – działa, gdy workflow jest włączony (opublikowany).

Jeśli adresy w węźle zawierają :5678 albo http://, kontener nie widzi N8N_WEBHOOK_URL – sprawdź docker compose exec n8n env | grep WEBHOOK. Sprawdź z zewnątrz:

bash
curl -i -X POST https://n8n.example.pl/webhook/test-sciezka -H 'Content-Type: application/json' -d '{"ping":1}'

Webhook to publiczny adres, który uruchamia Twój kod. Włącz w węźle uwierzytelnianie (nagłówek z sekretem albo Basic Auth), jeśli wywołujący to obsługuje.

Krok 5. Kopie

Dokumentacja kopii n8n mówi jasno: pełna kopia to katalog .n8n (klucz szyfrujący, ustawienia) i baza Postgres. Eksport workflowów z CLI to dodatek – nie zawiera użytkowników, historii uruchomień, zmiennych ani klucza.

Skrypt /opt/apps/n8n/backup.sh:

bash
#!/usr/bin/env bash
set -euo pipefail
umask 077
cd /opt/apps/n8n
D=$(date +%F)
docker compose exec -T db pg_dump -U n8n -Fc n8n > "backup/n8n-db-$D.dump"
docker compose exec -T n8n n8n export:workflow --backup --output="/backup/workflows-$D/"
docker compose exec -T n8n n8n export:credentials --backup --output="/backup/credentials-$D/"
docker run --rm -v n8n_n8n_data:/src:ro -v "$PWD/backup:/dst" alpine \
  tar -czf "/dst/n8n-home-$D.tar.gz" -C /src .
find backup -mindepth 1 -maxdepth 1 -mtime +7 -exec rm -rf {} +
bash
chmod +x backup.sh && sudo ./backup.sh && sudo ls -lh backup
echo "40 3 * * * root /opt/apps/n8n/backup.sh >>/var/log/n8n-kopia.log 2>&1" | sudo tee /etc/cron.d/n8n-kopia

Skrypt działa z crona roota, bo w katalogu backup piszą dwaj użytkownicy: kontener n8n (UID 1000) i host. Katalog ma prawa 700, a umask 077 chroni pliki tworzone przez skrypt – w kopii jest klucz szyfrujący n8n, więc nikt poza rootem i kontenerem nie powinien jej czytać. Nazwa wolumenu to <nazwa-projektu>_n8n_data; projekt nazywa się jak katalog, więc tutaj n8n_n8n_data (sprawdzisz przez docker volume ls). Eksportowane dane logowania są zaszyfrowane kluczem – bez kopii klucza nie zaimportujesz ich na nowym serwerze. Kopię wyślij poza VPS, np. jak w poradniku o restic i rclone. Przed każdą aktualizacją (docker compose pull && docker compose up -d) uruchom skrypt ręcznie.

Licencja: co wolno, a czego nie

n8n nie jest open source w rozumieniu OSI. Kod jest na licencji Sustainable Use, która pozwala używać i modyfikować oprogramowanie „tylko na własne wewnętrzne potrzeby biznesowe albo do użytku niekomercyjnego lub osobistego”. Pliki z .ee w nazwie (funkcje Enterprise) wymagają osobnej licencji. FAQ licencji rozpisuje to na przykładach.

Wolno między innymi:

  • automatyzować własną firmę i projekty, uczyć się, uruchamiać wiele instancji;
  • budować i utrzymywać automatyzacje dla klientów na swojej instancji i brać za to pieniądze, o ile klienci nie mają dostępu do edytora ani logiki workflowów;
  • używać n8n w tle własnego produktu, w którym użytkownicy uruchamiają przygotowane przez Ciebie automatyzacje.

Nie wolno:

  • hostować n8n jako usługi, w której klienci sami budują workflowy;
  • dawać zewnętrznym użytkownikom edytora ani konfiguracji workflowów w swoim produkcie;
  • robić forka i sprzedawać go jako własne narzędzie do automatyzacji ani white-labelu;
  • używać funkcji Enterprise wymagających klucza bez licencji Enterprise.

W sprawach granicznych n8n odsyła na adres licencyjny podany w FAQ. To streszczenie, nie porada prawna.

Kiedy lepsza chmura

n8n Cloud ma sens, gdy nie chcesz pilnować aktualizacji, kopii i certyfikatów, gdy automatyzacje są krytyczne dla firmy, a nikt nie odpowiada za serwer, albo gdy potrzebujesz funkcji z planów płatnych bez kupowania licencji Enterprise do instancji własnej. Self-hosting wygrywa, gdy masz już VPS, dużo uruchomień (w chmurze plany liczą wykonania) albo dane, które nie mogą opuścić Twojego serwera. Aktualne ceny planów sprawdzaj na stronie n8n.

Najczęstsze problemy

  • Logowanie przez http://adres-ip:5678 nie działa albo wyrzuca błąd ciasteczka. n8n domyślnie ustawia ciasteczko sesji tylko dla HTTPS. Wchodź przez domenę z certyfikatem, nie wyłączaj zabezpieczenia.
  • Edytor co chwilę pokazuje „Connection lost”. Brak nagłówków Upgrade/Connection w nginx albo brak proxy_http_version 1.1. Na nginx z Ubuntu 24.04 (1.24) i Debiana 13 (1.26) domyślne jest jeszcze HTTP/1.0 do backendu.
  • Webhook zwraca 404. Workflow nie jest włączony albo wywołujesz adres /webhook-test/ bez nasłuchiwania w edytorze.
  • Po przeniesieniu na nowy serwer dane logowania nie działają. Inny N8N_ENCRYPTION_KEY. Przywróć stary klucz w .env przed pierwszym startem.
  • Harmonogram rusza o złej godzinie. Brak GENERIC_TIMEZONE albo inna strefa ustawiona w ustawieniach samego workflowu.

Co dalej

Dołóż monitoring – Uptime Kuma sprawdzi, czy edytor i webhook odpowiadają. Jeśli n8n ma wysyłać e-maile, nie stawiaj własnego serwera SMTP; opcje opisuje poradnik o poczcie na domenie. Więcej narzędzi, które zastąpią płatne subskrypcje, znajdziesz w zestawieniu self-hosted alternatyw.

Powiązane poradniki