# n8n Self-Hosted na Hetzner — Instrukcja Krok po Kroku
Jeśli rozważasz automatyzację firmy i jednocześnie chcesz kontrolować dane, n8n self-hosted jest jednym z najlepszych wyborów. Dla zespołu SMB oznacza to prosty rachunek: niskie koszty infrastruktury, pełna kontrola nad workflow i brak lock-inu na pojedynczym dostawcy SaaS.
Ten przewodnik prowadzi Cię od zera do działającej instancji n8n na Hetzner. Bez skrótów typu "kliknij tutaj i zaufaj". Każdy krok ma uzasadnienie, a na końcu dostajesz checklistę utrzymaniową na pierwsze 30 dni.
## Dla kogo ten setup ma sens
- Dla firm, które chcą trzymać dane na własnej infrastrukturze (RODO, audyt, bezpieczeństwo). - Dla zespołów, które planują więcej niż 2-3 proste automatyzacje. - Dla organizacji, które chcą przewidywalny koszt zamiast rosnących opłat per operacja.
Jeśli masz pojedynczy prosty workflow i zero czasu na utrzymanie, n8n Cloud może być szybszy na start. Jeśli budujesz system na lata, self-host zwykle wygrywa.
## Architektura minimalna (produkcyjna, ale lekka)
W tej instrukcji używamy:
- VPS Hetzner (CPX21 lub CX22) - Ubuntu LTS - Docker + Docker Compose - n8n - PostgreSQL - Nginx (reverse proxy + SSL) - Certbot - Backup bazy przez cron
To jest "minimum sensowne". Nie enterprise, ale stabilny punkt startowy.
## Krok 1: Przygotuj serwer w Hetzner
1. Załóż projekt i utwórz VPS. 2. Region: Falkenstein lub Nuremberg (EU). 3. System: Ubuntu 24.04 LTS. 4. Włącz klucz SSH (nie hasło). 5. Dodaj DNS A record: automation.twojadomena.pl -> IP serwera.
Minimalne parametry: - 2 vCPU - 4 GB RAM - 40 GB dysku
To wystarczy na kilkanaście-kilkadziesiąt workflow SMB, jeśli nie robisz ciężkiego OCR/video.
## Krok 2: Hardenowanie systemu
Po SSH:
```bash sudo apt update && sudo apt upgrade -y sudo apt install -y ufw fail2ban ca-certificates curl gnupg sudo ufw allow OpenSSH sudo ufw allow 80 sudo ufw allow 443 sudo ufw --force enable ```
Dodaj użytkownika technicznego i wyłącz logowanie rootem przez hasło. To zajmuje 10 minut, a oszczędza dużo nerwów.
## Krok 3: Instalacja Docker i Compose
```bash sudo install -m 0755 -d /etc/apt/keyrings curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg echo \ "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] 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 sudo usermod -aG docker $USER ```
Wyloguj i zaloguj się ponownie, żeby grupa docker zadziałała.
## Krok 4: Struktura katalogów
```bash mkdir -p ~/n8n-stack/{n8n,postgres,backups} cd ~/n8n-stack ```
Teraz przygotuj plik .env:
```env DOMAIN=automation.twojadomena.pl POSTGRES_DB=n8n POSTGRES_USER=n8n POSTGRES_PASSWORD=ZMIEN_TO_NA_MOCNE_HASLO N8N_ENCRYPTION_KEY=ZMIEN_TO_NA_DLUGI_LOSOWY_KLUCZ N8N_BASIC_AUTH_USER=admin N8N_BASIC_AUTH_PASSWORD=ZMIEN_TO_NA_MOCNE_HASLO TZ=Europe/Warsaw ```
Najważniejsze: N8N_ENCRYPTION_KEY musi być stały. Jeśli go stracisz, stracisz dostęp do zaszyfrowanych credentiali.
## Krok 5: Docker Compose (n8n + Postgres)
Utwórz docker-compose.yml:
```yaml services: postgres: image: postgres:16-alpine container_name: n8n-postgres restart: unless-stopped environment: - POSTGRES_DB= - POSTGRES_USER= - POSTGRES_PASSWORD= - TZ= volumes: - ./postgres:/var/lib/postgresql/data healthcheck: test: ["CMD-SHELL", "pg_isready -U -d "] interval: 10s timeout: 5s retries: 6
n8n: image: n8nio/n8n:latest container_name: n8n-app restart: unless-stopped depends_on: postgres: condition: service_healthy environment: - DB_TYPE=postgresdb - DB_POSTGRESDB_HOST=postgres - DB_POSTGRESDB_PORT=5432 - DB_POSTGRESDB_DATABASE= - DB_POSTGRESDB_USER= - DB_POSTGRESDB_PASSWORD= - N8N_ENCRYPTION_KEY= - N8N_HOST= - N8N_PROTOCOL=https - WEBHOOK_URL=https:/// - N8N_PORT=5678 - GENERIC_TIMEZONE= - TZ= - N8N_BASIC_AUTH_ACTIVE=true - N8N_BASIC_AUTH_USER= - N8N_BASIC_AUTH_PASSWORD= - N8N_SECURE_COOKIE=true - N8N_EDITOR_BASE_URL=https:/// volumes: - ./n8n:/home/node/.n8n expose: - "5678" ```
Start:
```bash docker compose up -d docker compose logs -f n8n ```
## Krok 6: Reverse proxy Nginx
Instalacja:
```bash sudo apt install -y nginx ```
Konfiguracja /etc/nginx/sites-available/n8n:
```nginx server { listen 80; server_name automation.twojadomena.pl;
location / { proxy_pass http://127.0.0.1:5678; proxy_http_version 1.1; 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-Proto $scheme; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; proxy_read_timeout 3600; } } ```
Aktywacja:
```bash sudo ln -s /etc/nginx/sites-available/n8n /etc/nginx/sites-enabled/n8n sudo nginx -t sudo systemctl reload nginx ```
## Krok 7: SSL z Let's Encrypt
```bash sudo apt install -y certbot python3-certbot-nginx sudo certbot --nginx -d automation.twojadomena.pl ```
Po sukcesie sprawdź automatyczne odnowienie:
```bash sudo systemctl list-timers | grep certbot ```
## Krok 8: Backupy bazy danych
Utwórz skrypt ~/n8n-stack/backup-postgres.sh:
```bash #!/usr/bin/env bash set -euo pipefail
DATE=$(date +%F-%H%M) BACKUP_DIR="$HOME/n8n-stack/backups" mkdir -p "$BACKUP_DIR"
docker exec n8n-postgres pg_dump -U n8n -d n8n > "$BACKUP_DIR/n8n-$DATE.sql" find "$BACKUP_DIR" -type f -name "n8n-*.sql" -mtime +14 -delete ```
Nadaj prawa:
```bash chmod +x ~/n8n-stack/backup-postgres.sh ```
## Krok 9: Cron harmonogram backupów
Otwórz crontab:
```bash crontab -e ```
Dodaj:
```cron 0 /6 /bin/bash $HOME/n8n-stack/backup-postgres.sh >> $HOME/n8n-stack/backups/backup.log 2>&1 30 3 1 docker compose -f $HOME/n8n-stack/docker-compose.yml pull && docker compose -f $HOME/n8n-stack/docker-compose.yml up -d ```
Pierwsza linia: backup co 6 godzin. Druga: cotygodniowy rolling update kontenerów.
## Krok 10: Pierwsze uruchomienie i testy
Wejdź na https://automation.twojadomena.pl, zaloguj się Basic Auth i zrób:
1. Utwórz prosty workflow testowy (Manual Trigger -> Set -> NoOp). 2. Zapisz i uruchom. 3. Sprawdź, czy execution pojawia się poprawnie. 4. Dodaj testowy webhook i wywołaj curl.
Jeśli to działa, masz stabilny fundament.
## Najczęstsze problemy i szybkie diagnozy
Problem: pusta strona po logowaniu Sprawdź N8N_HOST, WEBHOOK_URL, N8N_EDITOR_BASE_URL. Najczęściej URL-e nie zgadzają się z domeną.
Problem: webhook działa lokalnie, nie działa z internetu Sprawdź czy DNS wskazuje poprawne IP oraz czy porty 80/443 są otwarte w UFW.
Problem: credentials "znikają" po restarcie Najczęściej zmienił się N8N_ENCRYPTION_KEY albo volume ./n8n nie jest montowane.
Problem: duże opóźnienia workflow Sprawdź obciążenie CPU/RAM i rozdziel workflow czasochłonne na osobne kolejki.
## Utrzymanie: checklista 30 dni
- Co tydzień: aktualizacja obrazów kontenerów. - Co tydzień: test odtwarzania jednego backupu. - Co tydzień: przegląd execution errors. - Co miesiąc: rotacja haseł Basic Auth. - Co miesiąc: przegląd aktywnych credentials i usunięcie nieużywanych.
Jeśli automatyzacje rosną, dodaj: - zewnętrzny monitoring uptime, - alerty Slack/email na błędy, - oddzielny serwer PostgreSQL przy większym obciążeniu.
## Ile to kosztuje realnie
Przykładowy koszt miesięczny: - VPS Hetzner: 8-16 EUR - Domena: zwykle już posiadasz - SSL: 0 EUR (Let's Encrypt) - n8n: 0 EUR (self-hosted)
To poziom często 3-8x tańszy niż rozbudowane plany automatyzacji SaaS przy rosnącej liczbie operacji.
## Kiedy to robić samodzielnie, a kiedy z partnerem
Samodzielnie: - masz techniczną osobę w zespole, - potrzebujesz 3-10 workflow, - akceptujesz 1-2 dni na setup i testy.
Z partnerem: - chcesz od razu wersję "production-ready" z monitoringiem i polityką backupu, - planujesz workflow krytyczne biznesowo (lead routing, faktury, SLA support), - potrzebujesz szybkiego handoveru dla zespołu.
Jeśli chcesz, możemy pomóc od razu z architekturą i pierwszymi workflow. Zobacz [usługę automatyzacji](/uslugi/automatyzacja) albo [napisz do nas](/kontakt).



