This tutorial guides you through deploying n8n on Hetzner Cloud using Docker Compose, including server selection, secure setup with Caddy for HTTPS, PostgreSQL as the database, encryption, and backups. It's for technical users familiar with n8n who want a reliable, low-cost self-hosted instance without relying on managed services.
Why this matters
Self-hosting n8n on Hetzner Cloud avoids vendor lock-in and high costs of cloud platforms like AWS or DigitalOcean, while providing scalable performance for automations. It solves the common trap of underpowered servers causing workflow failures during peak loads and ensures data sovereignty with encrypted, backed-up storage—all for €5-10 monthly.
Step-by-step
- Create a Hetzner Cloud account at console.hetzner.cloud if you haven't, then add a payment method. In the console, click "Add Project" and name it (e.g., "n8n-prod"). Select the Nuremberg (fsn1) location for lower latency in Europe.
- Deploy a server: Click "Add Server" in your project. Choose CX22 (2 vCPU, 4GB RAM, 40GB SSD) for starters—it's €5.50/month and handles moderate workflows; upgrade to CCX23 (€9/month) if you expect heavy use. Select Ubuntu 22.04 as the OS, add your SSH key under "Security", and deploy. Note the public IP once it's running (takes 1-2 minutes).
- SSH into the server: From your terminal, run
ssh root@YOUR_SERVER_IP. Update packages withapt update && apt upgrade -y. Install Docker and Docker Compose:curl -fsSL https://get.docker.com -o get-docker.sh && sh get-docker.sh && apt install docker-compose -y. Add your user to the Docker group:usermod -aG docker rootand reboot withreboot. - Set up PostgreSQL: Create a directory
mkdir -p ~/n8n && cd ~/n8n. Generate a strong DB password:DB_PASS=$(openssl rand -base64 32). Createdocker-compose.ymlwith this content (use nano or vim):
Replace placeholders likeversion: '3.8' services: postgres: image: postgres:15 restart: always environment: POSTGRES_DB: n8n POSTGRES_USER: n8n POSTGRES_PASSWORD: ${DB_PASS} volumes: - postgres_data:/var/lib/postgresql/data n8n: image: n8nio/n8n:latest restart: always ports: - "5678:5678" environment: DB_TYPE: postgresdb DB_POSTGRESDB_HOST: postgres DB_POSTGRESDB_PORT: 5432 DB_POSTGRESDB_DATABASE: n8n DB_POSTGRESDB_USER: n8n DB_POSTGRESDB_PASSWORD: ${DB_PASS} N8N_BASIC_AUTH_ACTIVE: true N8N_BASIC_AUTH_USER: admin N8N_BASIC_AUTH_PASSWORD: your_strong_password N8N_ENCRYPTION_KEY: your_32_char_encryption_key_here WEBHOOK_URL: https://yourdomain.com/ volumes: - n8n_data:/home/node/.n8n depends_on: - postgres caddy: image: caddy:2-alpine restart: always ports: - "80:80" - "443:443" volumes: -./Caddyfile:/etc/caddy/Caddyfile - caddy_data:/data - caddy_config:/config volumes: postgres_data: n8n_data: caddy_data: caddy_config:your_strong_passwordand generate an encryption key withopenssl rand -base64 24. - Configure Caddy for HTTPS: Create
Caddyfilein ~/n8n:nano Caddyfileand add:
Point a domain (e.g., via Namecheap) A record to your server's IP. For free subdomains, use DuckDNS. Start services:yourdomain.com { reverse_proxy n8n:5678 tls your-email@example.com }docker-compose up -d. Check logs withdocker-compose logs -f; expect Caddy to auto-obtain Let's Encrypt certs on first access. - Set up encryption and security: In docker-compose.yml, ensure
N8N_ENCRYPTION_KEYis set (store it securely, e.g., in Hetzner secrets or env file). For basic auth, access https://yourdomain.com and log in with admin/your_strong_password. Enable queue mode if scaling: AddEXECUTIONS_MODE: queueand a Redis service later. - Implement backups: Install cron:
apt install cron -y. Create a backup scriptnano backup.sh:
Make executable:#!/bin/bash docker-compose exec postgres pg_dump n8n > /backup/n8n-$(date +%Y%m%d).sql tar -czf /backup/n8n-volumes-$(date +%Y%m%d).tar.gz /n8n_data /postgres_datachmod +x backup.sh. Create /backup dir:mkdir /backup. Add to crontab:crontab -eand insert0 2 * * * cd ~/n8n &&./backup.sh && rsync -av /backup/ user@backup-server:/path/for offsite (use Hetzner Storage Box, €3/month). Test with./backup.sh. - Monitor and scale: Install htop:
apt install htop -y. Usedocker statsto watch usage. For costs, CX22 stays under €6/month; add snapshots via Hetzner console for €0.01/GB. Access n8n UI, create a test workflow, and verify persistence in Postgres.
Worked example
A common pattern is automating RSS feeds to Slack notifications. Start with a Cron node set to trigger every hour. Connect to an RSS Feed Read node (type: n8n-nodes-base.rssFeedRead) using your feed URL, like "https://example.com/rss". Filter new items with an IF node (n8n-nodes-base.if) checking publish date. Then, use a Slack node (n8n-nodes-base.slack) to post a formatted message with title, link, and summary via webhook URL from your Slack app. End with an Email node (n8n-nodes-base.emailSend) for backups to your inbox. Deploy this on your Hetzner n8n: It pulls feeds securely over HTTPS, processes via Postgres-stored executions, and scales without downtime—total setup under 5 minutes in the UI.
Common pitfalls
- Server undersized for workflows: Symptom: n8n crashes or slows during complex executions (e.g., API loops). Fix: Monitor with
docker stats; upgrade to CCX23 if CPU >80% average—Hetzner allows instant resizing without downtime. - HTTPS cert fails on first boot: Symptom: Caddy logs show "tls: handshake failure". Fix: Ensure domain DNS propagates (use
dig yourdomain.comto check); restart Caddy withdocker-compose restart caddyafter 5-10 minutes. - Data loss on restarts: Symptom: Workflows vanish after server reboot. Fix: Verify volumes in docker-compose.yml are named and persistent; run
docker volume lsto confirm, and always back up before updates. - Encryption key mismatch: Symptom: Credentials fail to decrypt in nodes like HTTP Request. Fix: Set
N8N_ENCRYPTION_KEYconsistently in env; regenerate only after full export/import via n8n's settings. - Backup script permissions error: Symptom: Cron jobs fail silently. Fix: Run as root, ensure
docker-compose execuses correct paths, and test manually; add logging with> /var/log/backup.log 2>&1to crontab.
Related workflows in the catalog
Explore the n8n catalog for importable starters like "RSS to Slack" or "API Monitoring with Alerts", which pair perfectly with this deployment for quick automation builds. With 14,000+ workflows available, search for "Hetzner integration" to find cloud-specific ones, such as auto-scaling scripts using Hetzner API nodes. Check pages like the official n8n community forum or workflow library at n8n.io/workflows for tailored examples that use your self-hosted setup.