Skip to content

n8n self-hosted: how to host n8n with Docker and Postgres

Self-host n8n in minutes: the official n8n Docker image, a managed Postgres database, working webhooks and automatic HTTPS, from about $9 a month.

Abhishek Jaiswal

6 min Updated

On this page 11 sections

Self-hosting n8n removes the per-execution ceiling of n8n Cloud, and the official n8nio/n8n Docker image makes it a short job: one container, one Postgres database, a public HTTPS address for webhooks.

This guide walks through n8n hosting on Ownkube step by step, with the docker compose equivalent for anyone comparing it to a VPS install.

TL;DR

  • Self-hosted n8n needs three things: the n8nio/n8n image, a Postgres database (the bundled SQLite does not hold up under concurrent executions), and a stable HTTPS URL for webhooks.
  • On Ownkube that is a one-click n8n template or a manual deploy: create a managed Postgres database, deploy the image, set N8N_HOST, N8N_PROTOCOL, WEBHOOK_URL and N8N_ENCRYPTION_KEY.
  • Every app gets an ownkube.app address with automatic TLS, which matters because Stripe, GitHub and Slack refuse plain HTTP callback URLs.
  • Cost: a Spark 1 box at $5 a month plus a database box from $4 a month plus storage at $0.25 per GB. A small n8n install runs for about $10 a month, with unlimited executions. See n8n pricing explained for the comparison with n8n Cloud.

The fastest way: the n8n template

If you want n8n running in one click, the n8n template on the Ownkube Marketplace creates the Postgres database, deploys the official image, wires the connection and generates the encryption key for you. Deploy it, open the hostname and create the owner account.

The rest of this guide is the manual path, which is useful when you want to pin a version, add a custom Dockerfile or understand what the template set up.

What you need before you start

  • The image reference n8nio/n8n:latest, or a pinned version tag if you want reproducible upgrades.
  • A subdomain for the app on ownkube.app, for example automate-yourteam.ownkube.app. Webhook-triggered workflows need a stable URL, so pick it before you build any.
  • A generated encryption key, set explicitly rather than letting n8n generate one on first boot, since a regenerated key invalidates saved credentials.

1. Create a managed Postgres database

n8n supports Postgres as its production-grade database option, and it is the one to use for anything beyond a single-user test instance. Create a database box on Ownkube (from $4 a month plus storage at $0.25 per GB per month) and note the host, port, database name, user, and password.

2. Deploy the n8n Docker image

Create the app from n8nio/n8n:latest, or start from this Dockerfile if you want to pin a version:

FROM n8nio/n8n:1.123.60

Point the app at port 5678, which is what the image listens on by default.

3. Set the environment variables

Terminal window
# Database
DB_TYPE=postgresdb
DB_POSTGRESDB_HOST=<your-postgres-host>
DB_POSTGRESDB_PORT=5432
DB_POSTGRESDB_DATABASE=n8n
DB_POSTGRESDB_USER=<your-postgres-user>
DB_POSTGRESDB_PASSWORD=<your-postgres-password>
# Host and webhooks
N8N_HOST=automate-yourteam.ownkube.app
N8N_PROTOCOL=https
N8N_PORT=5678
WEBHOOK_URL=https://automate-yourteam.ownkube.app/
# Security
N8N_ENCRYPTION_KEY=<a-long-random-string>
GENERIC_TIMEZONE=UTC

Set N8N_HOST, N8N_PROTOCOL, and WEBHOOK_URL to the app’s public address before you build anything that depends on an inbound webhook. n8n bakes the webhook base URL into every workflow’s trigger node, so changing it later means editing each affected workflow rather than a single config change.

4. Keep the app stateless

With DB_TYPE=postgresdb, workflows, executions, and credentials live in Postgres instead of on the container’s disk. The one thing n8n would otherwise keep in /home/node/.n8n is the encryption key it generates on first boot, and a redeploy would lose it. Setting N8N_ENCRYPTION_KEY explicitly (step 3) removes that dependency, so the app can restart or redeploy without invalidating any saved credential.

5. Verify webhooks

The app’s ownkube.app address serves HTTPS from the first deploy, with no DNS to set up. Confirm the app is reachable and that a test webhook round-trips correctly:

Terminal window
curl -I https://automate-yourteam.ownkube.app
# From n8n's UI, use the "Listen for test event" button on a webhook
# trigger node, then send a test request to confirm the URL is public
# and TLS-terminated correctly.
curl -X POST https://automate-yourteam.ownkube.app/webhook-test/<path>

Most third-party services that trigger n8n workflows (Stripe, GitHub, Slack, Typeform) require HTTPS callback URLs and reject plain HTTP, so this step matters more for n8n than for a typical web app.

The docker compose equivalent

If you are comparing this to an n8n docker compose install on a VPS, here is the same setup as a compose file. It is what the Ownkube deploy above replaces: the postgres service becomes the managed database box, the n8n service becomes the web deployment, and the reverse proxy, TLS certificate and DNS record are handled by the ownkube.app hostname.

services:
postgres:
image: postgres:17
environment:
POSTGRES_DB: n8n
POSTGRES_USER: n8n
POSTGRES_PASSWORD: change-me
volumes:
- pgdata:/var/lib/postgresql/data
n8n:
image: n8nio/n8n:1.123.60
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: change-me
N8N_HOST: n8n.example.com
N8N_PROTOCOL: https
WEBHOOK_URL: https://n8n.example.com/
N8N_ENCRYPTION_KEY: change-me-too
depends_on:
- postgres
volumes:
pgdata:

What the compose file leaves to you on a VPS: a reverse proxy with a TLS certificate, a DNS record, Postgres backups, OS updates, and restarting the stack when the host reboots. Those are the parts that turn a weekend install into a recurring chore, and they are the parts the managed deploy takes over.

Sizing the deployment

A handful of scheduled workflows that run occasionally is a light workload and fits comfortably on metered pricing, billed per minute.

A busier setup with many active webhook triggers and frequent executions runs closer to constant load, which is a better fit for a flat Spark or Core box so the price does not move with execution volume. You choose per deployment and can switch later without redeploying the underlying image.

If this instance eventually needs to move off shared infrastructure, for example because a workflow now touches data with residency requirements, the same n8nio/n8n image and Dockerfile run unchanged in your own AWS account under Ownkube’s own-cloud option, with the same logs and health checks attached.

For a broader look at self-hosted automation platforms next to managed alternatives, see our comparison of Railway, Render, and Northflank.

FAQ

Does n8n need Postgres, or does SQLite work?

n8n ships with SQLite by default and it works for light single-user use, but the project recommends Postgres for anything with concurrent executions or production reliability expectations. Set DB_TYPE=postgresdb and the matching DB_POSTGRESDB_* variables to use it.

How much does it cost to self-host n8n?

On Ownkube, a Spark 1 box ($5 a month) for the app plus the smallest database box ($4 a month) plus 5 GB of storage ($1.25) comes to about $10 a month with no execution limit. n8n Cloud’s Starter plan is listed at 20 euros a month billed annually for 2,500 executions. The n8n pricing post works through the break-even.

Why do my webhook URLs return the wrong host?

WEBHOOK_URL (and N8N_HOST/N8N_PROTOCOL) must match the app’s public address before you create webhook-triggered workflows. If you change the address later, existing webhook trigger nodes keep the old URL baked in and need to be recreated or manually updated.

What happens if I lose the encryption key?

N8N_ENCRYPTION_KEY decrypts stored credentials. If it changes or is lost, every saved credential in existing workflows stops working and needs to be re-entered. Set it explicitly as an environment variable rather than letting n8n generate one you have not saved.

Can I run n8n without a persistent volume?

Yes, as long as it uses Postgres and N8N_ENCRYPTION_KEY is set explicitly. Without the key, a redeploy resets /home/node/.n8n and n8n generates a new one, which breaks every saved credential.

How do I update a self-hosted n8n?

Change the image tag in the Dockerfile (or the image reference on the deployment) and redeploy. n8n runs its database migrations on start. Pin a specific version rather than latest so an upgrade is a deliberate step you can roll back.

Where Ownkube fits

n8n’s official image needs a real database and a stable public URL to be reliable, and Ownkube Compute covers both without a cloud account to configure first. Deploy the template or the image, attach managed Postgres, set the encryption key, and your webhooks get an HTTPS address from the first deploy. See Ownkube pricing for the per-minute wallet model, from $5 a month. Deploy my first app.

Abhishek Jaiswal · Founder and Engineer

Abhishek Jaiswal is the founder and engineer behind Ownkube, a cloud for personal software. He builds the platform and writes here about cloud cost, migrations, and running production infrastructure in your own AWS account without a DevOps team.

Share

More posts

All posts

Ship my first app in the next five minutes.

Push a repo and get a live URL, with no cloud account or config.

Top up from $5, billed per minute with no subscription.