n8n installeren met Docker Compose op een VPS

8 min leestijd·Matthieu|

Zet n8n 2.x op met Docker Compose en PostgreSQL op een VPS. Productieklaar vanaf het begin met vastgezette versies, back-up van de encryptiesleutel, health checks en resourcelimieten.

Deze handleiding installeert n8n 2.12.3 met Docker Compose en PostgreSQL op een VPS. Je hebt een werkende n8n-instantie binnen ongeveer 15 minuten. De configuratie gebruikt vanaf het begin productiestandaarden: vastgezette imageversies, versleutelde credentials, poort alleen gebonden aan localhost, health checks op beide containers en Docker-resourcelimieten. Geen reverse proxy of SSL hier. Dat wordt behandeld in .

Wat heb ik nodig voordat ik n8n installeer?

Je hebt een VPS nodig met Debian 12 of Ubuntu 24.04 en minimaal 4 GB RAM. Docker en Docker Compose (de docker compose-plugin, niet het oude docker-compose-binary) moeten geïnstalleerd zijn. Als Docker nog niet is opgezet, volg dan eerst Docker Compose voor multi-service VPS-deployments.

Controleer of Docker Compose beschikbaar is:

docker compose version

Verwachte output:

Docker Compose version v2.x.x

Als dit commando faalt met docker: 'compose' is not a docker command, heb je het verouderde standalone binary. Installeer de Docker Compose-plugin vanuit de officiële Docker-repository.

Je hebt ook een niet-rootgebruiker nodig met sudo-toegang. Alle commando's in deze handleiding worden als die gebruiker uitgevoerd, niet als root.

Waarom PostgreSQL in plaats van SQLite voor n8n?

PostgreSQL verwerkt gelijktijdige verbindingen, ondersteunt WAL voor crashherstel en werkt met pg_dump voor hot backups terwijl n8n draait. SQLite vergrendelt het hele databasebestand bij elke schrijfactie. Bij gelijktijdige webhook-uitvoeringen veroorzaakt dit timeouts en datacorruptie. Je kunt een SQLite-database niet veilig back-uppen terwijl n8n draait zonder een corrupte kopie te riskeren. Voor alles buiten lokale tests is PostgreSQL de juiste keuze.

Eigenschap SQLite PostgreSQL
Gelijktijdige schrijfacties Single-writer lock Volledig MVCC
Hot backups Onveilig tijdens gebruik pg_dump op elk moment
Crashherstel Handmatige journal-replay Automatische WAL-replay
Schaalbaarheid Enkel proces Connection pooling
n8n-omgevingsvariabele DB_TYPE=sqlite DB_TYPE=postgresdb

Hoe installeer ik n8n met Docker Compose op een VPS?

Maak een projectdirectory, schrijf een .env-bestand met je secrets, schrijf de docker-compose.yml, start de stack en controleer of alles gezond is. Elke stap bevat een verificatie.

De projectdirectory aanmaken

mkdir -p ~/n8n && cd ~/n8n

Het .env-bestand aanmaken

Alle secrets gaan in een .env-bestand. Codeer wachtwoorden of sleutels nooit direct in docker-compose.yml.

Genereer een sterk databasewachtwoord en de n8n-encryptiesleutel:

echo "POSTGRES_PASSWORD=$(openssl rand -base64 32)" >> .env
echo "N8N_ENCRYPTION_KEY=$(openssl rand -hex 32)" >> .env

Voeg nu de overige variabelen toe:

cat >> .env << 'EOF'
# PostgreSQL
POSTGRES_USER=n8n
POSTGRES_DB=n8n

# n8n
N8N_VERSION=2.12.3
N8N_HOST=localhost
N8N_PORT=5678
N8N_PROTOCOL=http
N8N_DIAGNOSTICS_ENABLED=false
GENERIC_TIMEZONE=UTC
EOF

Beperk de bestandsrechten. Alleen jouw gebruiker mag dit bestand lezen:

chmod 600 .env

Verificatie:

ls -la .env

Je zou -rw------- moeten zien. Niemand anders op de server kan je databasewachtwoord of encryptiesleutel lezen.

Hoe genereer en back-up ik de n8n-encryptiesleutel?

De N8N_ENCRYPTION_KEY is hierboven gegenereerd met openssl rand -hex 32. Dit produceert een willekeurige sleutel van 32 bytes (64 hexadecimale tekens). n8n gebruikt deze sleutel om alle opgeslagen credentials te versleutelen: API-sleutels, OAuth-tokens, databasewachtwoorden in workflows. Als je deze sleutel verliest, worden alle opgeslagen credentials permanent onleesbaar. Er is geen herstelmechanisme.

Maak nu een back-up van de encryptiesleutel. Kopieer deze naar een wachtwoordmanager of offline kluis:

grep N8N_ENCRYPTION_KEY .env

Bewaar de output op een veilige plek buiten deze server. Doe dit voordat je je eerste credential in n8n toevoegt.

Referentie omgevingsvariabelen

Variabele Doel Voorbeeldwaarde
POSTGRES_USER PostgreSQL-superusernaam n8n
POSTGRES_PASSWORD PostgreSQL-superuserwachtwoord (gegenereerd, 32+ tekens)
POSTGRES_DB Databasenaam n8n
N8N_VERSION Vastgezette n8n-imagetag 2.12.3
N8N_ENCRYPTION_KEY Versleutelt opgeslagen credentials (gegenereerd, 64 hex tekens)
N8N_HOST Host voor de n8n-interface localhost
N8N_PORT Poort voor de n8n-interface 5678
N8N_PROTOCOL HTTP of HTTPS http
N8N_DIAGNOSTICS_ENABLED Telemetrie naar n8n sturen false
GENERIC_TIMEZONE Tijdzone voor cron-triggers UTC

De docker-compose.yml schrijven

cat > docker-compose.yml << 'COMPOSE'
services:
  postgres:
    image: postgres:16-alpine
    restart: unless-stopped
    environment:
      POSTGRES_USER: ${POSTGRES_USER}
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
      POSTGRES_DB: ${POSTGRES_DB}
    volumes:
      - postgres_data:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER} -d ${POSTGRES_DB}"]
      interval: 10s
      timeout: 5s
      retries: 5
      start_period: 10s
    deploy:
      resources:
        limits:
          memory: 512M
          cpus: "1.0"
    security_opt:
      - no-new-privileges:true
    logging:
      driver: json-file
      options:
        max-size: "10m"
        max-file: "3"

  n8n:
    image: docker.n8n.io/n8nio/n8n:${N8N_VERSION}
    restart: unless-stopped
    environment:
      DB_TYPE: postgresdb
      DB_POSTGRESDB_HOST: postgres
      DB_POSTGRESDB_PORT: 5432
      DB_POSTGRESDB_DATABASE: ${POSTGRES_DB}
      DB_POSTGRESDB_USER: ${POSTGRES_USER}
      DB_POSTGRESDB_PASSWORD: ${POSTGRES_PASSWORD}
      N8N_ENCRYPTION_KEY: ${N8N_ENCRYPTION_KEY}
      N8N_HOST: ${N8N_HOST}
      N8N_PORT: ${N8N_PORT}
      N8N_PROTOCOL: ${N8N_PROTOCOL}
      N8N_DIAGNOSTICS_ENABLED: ${N8N_DIAGNOSTICS_ENABLED}
      GENERIC_TIMEZONE: ${GENERIC_TIMEZONE}
    ports:
      - "127.0.0.1:5678:5678"
    volumes:
      - n8n_data:/home/node/.n8n
    depends_on:
      postgres:
        condition: service_healthy
    healthcheck:
      test: ["CMD-SHELL", "wget -qO- http://localhost:5678/healthz || exit 1"]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 30s
    deploy:
      resources:
        limits:
          memory: 2G
          cpus: "2.0"
    security_opt:
      - no-new-privileges:true
    logging:
      driver: json-file
      options:
        max-size: "10m"
        max-file: "3"

volumes:
  postgres_data:
  n8n_data:
COMPOSE

Een paar punten om op te letten in dit bestand:

Geen version:-sleutel. Docker Compose V2 negeert deze. Alle concurrerende tutorials bevatten nog steeds version: '3.7' of version: '3.8'. De Compose-specificatie heeft dit veld als verouderd aangemerkt. Het opnemen ervan levert een waarschuwing op bij huidige Docker-versies.

Poort gebonden aan 127.0.0.1. De regel "127.0.0.1:5678:5678" beperkt n8n tot localhost. Dit is een beveiligingsvereiste, geen voorkeur. Docker-poortmappings omzeilen iptables en UFW-regels volledig. Als je 5678:5678 schrijft zonder het 127.0.0.1-prefix, is n8n bereikbaar via internet, zelfs als je firewall poort 5678 blokkeert. Een reverse proxy op dezelfde machine stuurt verkeer door naar localhost:5678 zodra je er een instelt.

security_opt: no-new-privileges:true voorkomt dat processen in de container extra privileges verkrijgen via setuid- of setgid-binaries. Dit is een defense-in-depth-maatregel tegen container-escape-aanvallen.

Logrotatie. Het logging-blok beperkt het JSON-log van elke container tot 3 bestanden van elk 10 MB (maximaal 30 MB per service). Zonder deze instelling groeien Docker-logs totdat je schijf vol is. Op een VPS met beperkte opslag is dit belangrijk.

Health checks op beide services. PostgreSQL gebruikt pg_isready. n8n gebruikt zijn /healthz-endpoint. De depends_on-conditie zorgt ervoor dat n8n pas start nadat PostgreSQL zijn health check heeft doorstaan.

Resourcelimieten. PostgreSQL krijgt 512 MB RAM en 1 CPU. n8n krijgt 2 GB RAM en 2 CPU's. Deze waarden werken goed op een VPS van 4-8 GB. Pas ze aan op basis van je servergrootte en workflowcomplexiteit.

Benoemde volumes. Zowel postgres_data als n8n_data zijn door Docker beheerde benoemde volumes. Docker regelt eigenaarschap en rechten binnen het volume automatisch. Het is niet nodig om hostdirectory's aan te maken of rechten handmatig te corrigeren.

restart: unless-stopped in plaats van restart: always. Beide herstarten na een crash, maar unless-stopped respecteert handmatige docker compose stop-commando's. Met restart: always herstart een handmatig gestopte container als de Docker-daemon herstart (bijvoorbeeld na een systeemupdate).

De stack starten

cd ~/n8n
docker compose up -d

Bekijk de logs tijdens de eerste opstart:

docker compose logs -f

Wacht tot n8n een regel toont met n8n ready on. Druk op Ctrl+C om de logweergave te verlaten.

De installatie verifiëren

Controleer of beide containers draaien en gezond zijn:

docker compose ps

Verwachte output:

NAME       IMAGE                                  ...  STATUS                    PORTS
n8n-n8n-1       docker.n8n.io/n8nio/n8n:2.12.3   ...  Up X minutes (healthy)    127.0.0.1:5678->5678/tcp
n8n-postgres-1  postgres:16-alpine                ...  Up X minutes (healthy)

Let goed op: beide containers tonen (healthy) in de kolom STATUS. Dit bevestigt dat de health checks slagen. Als je (health: starting) ziet, wacht 30 seconden en controleer opnieuw.

Test de n8n-API vanaf de server:

curl -s http://localhost:5678/healthz

Verwachte output:

{"status":"ok"}

Controleer of de poort alleen luistert op localhost, niet op alle interfaces:

ss -tlnp | grep 5678

Je zou 127.0.0.1:5678 in de output moeten zien. Als je 0.0.0.0:5678 ziet, is je poortbinding onjuist. Stop de stack, corrigeer de ports-regel in docker-compose.yml en herstart.

Hoe maak ik het n8n-eigenaarsaccount aan?

Open een SSH-tunnel vanaf je lokale machine om n8n via je browser te benaderen:

ssh -L 5678:127.0.0.1:5678 your-user@your-server-ip

Open nu http://localhost:5678 in je browser. n8n toont een configuratiescherm bij de eerste toegang. Maak je eigenaarsaccount aan met een sterk wachtwoord. Dit account heeft volledige beheerderstoegang tot n8n.

Sluit na het aanmaken van het account de SSH-tunnel. Laat poort 5678 niet langer getunneld dan nodig. Stel een reverse proxy met SSL in voor reguliere toegang. Zie .

Hoe controleer ik of n8n correct werkt?

Voer na het aanmaken van je account en het sluiten van de SSH-tunnel een laatste reeks controles uit vanaf de server.

Controleer de containergezondheid:

docker compose ps --format "table {{.Name}}\t{{.Status}}"

Beide services moeten (healthy) tonen.

Controleer de n8n-logs op fouten:

docker compose logs n8n --tail 20

Zoek naar ERROR-regels. Een schone opstart toont databasemigratiemeldingen gevolgd door n8n ready on.

Controleer de PostgreSQL-logs:

docker compose logs postgres --tail 10

Je zou database system is ready to accept connections moeten zien.

Controleer het schijfgebruik van je Docker-volumes:

docker system df -v | grep -E "n8n|postgres"

Dit vertelt je hoeveel ruimte n8n en PostgreSQL gebruiken. Controleer dit regelmatig op VPS-instanties met beperkte opslag.

Iets misgegaan?

Container stopt direct. Controleer de logs met docker compose logs n8n. Veelvoorkomende oorzaken: ontbrekend .env-bestand, verkeerd PostgreSQL-wachtwoord, of de encryptiesleutel bevat speciale tekens die de shell-expansie verstoren. Genereer je .env opnieuw indien nodig.

Rechtenfouten. De n8n-container draait als UID 1000. Als je overschakelt van benoemde volumes naar bind mounts, zorg er dan voor dat de hostdirectory eigendom is van UID 1000: sudo chown -R 1000:1000 ./n8n_data.

Health check faalt. n8n heeft bij de eerste start 20-30 seconden nodig terwijl het databasemigraties uitvoert. Als health checks falen, controleer docker compose logs n8n op migratiefouten. De instelling start_period: 30s geeft n8n tijd voordat health checks beginnen.

Kan geen verbinding maken met n8n. De poort is gebonden aan localhost. Je kunt er niet vanaf een andere machine bij zonder SSH-tunnel of reverse proxy. Dit is opzettelijk.

Encryptiesleutel vergeten. Als je N8N_ENCRYPTION_KEY bent kwijtgeraakt en n8n heeft credentials opgeslagen, dan zijn die credentials verloren. Er is geen herstel mogelijk. Daarom bestaat de back-upstap.

Wat moet ik doen na het installeren van n8n?

Deze installatie geeft je een werkende n8n-instantie die alleen bereikbaar is vanaf de server zelf. Voor productiegebruik heb je nog drie dingen nodig:

  1. Reverse proxy met SSL. Stel Nginx of Caddy in voor n8n met een TLS-certificaat. Dit geeft je HTTPS-toegang met een domeinnaam. Zie .

  2. Back-ups. Plan geautomatiseerde back-ups van de PostgreSQL-database en de n8n-encryptiesleutel. Zie .

  3. Updates. Om n8n te updaten, wijzig N8N_VERSION in .env naar de nieuwe versie en voer dan docker compose up -d uit. Docker haalt de nieuwe image op en maakt de container opnieuw aan. Lees altijd de n8n release notes voordat je update.

Voor de hoofdgids over workflowautomatiseringsopties op een VPS, zie .

Voor Docker Compose-basiskennis en het beheren van meerdere services, zie Docker Compose voor multi-service VPS-deployments.


Copyright 2026 Virtua.Cloud. Alle rechten voorbehouden. Deze inhoud is een origineel werk van het Virtua.Cloud-team. Reproductie, herpublicatie of herdistributie zonder schriftelijke toestemming is verboden.

Klaar om het zelf te proberen?

Deploy uw eigen server in seconden. Linux, Windows of FreeBSD.

Bekijk VPS-aanbod