Share
english , vps , Ubuntu , n8n
Denys Pulinets
9 9 min read

The Ultimate n8n Docker Setup Guide 2025: Because Zapier is Too Mainstream (And Expensive)

Why You're Actually Reading This (Spoiler: Money)

Let me guess - you just checked Zapier's pricing page and nearly choked on your overpriced artisanal coffee. $69/month for 2,000 tasks? That's more expensive than my entire server infrastructure!

Welcome to the real world, where we self-host our automation tools like proper tech masochists. Today, I'm going to show you how to install n8n using Docker Compose, on self-hosted server with Ubuntu.

But before installation n8n, highly recommend to read article about based configuration of Ubuntu (most likely you will use Ubuntu on self-hosted server).

Ultimate Ubuntu 24.04 VPS Security Setup Guide: How to Not Get Hacked in 2025
Turn your Ubuntu 24.04 from Swiss cheese into Fort Knox! SSH keys, firewalls, and ports that’ll make hackers cry. Server security with actual personality.

Statistical reality check:

💡
Question for the ages: Why pay for someone else's servers when you can suffer with your own?

What the Hell is n8n Anyway?

What the Hell is n8n?

n8n (pronounced "nodemation" - yes, really) is like Zapier's rebellious younger sibling who dropped out of business school to become a developer. It's open-source, self-hostable, and has more nodes than a blockchain evangelist's PowerPoint presentation.

Key differences that actually matter:

  • Self-hosted: Your data stays on YOUR server (revolutionary concept, I know)
  • Fair-code licensed: It's free until you become successful enough to afford it
  • Extendable: You can code your own nodes when the 400+ existing ones inevitably disappoint you
  • No artificial limits: Run 1 million workflows if you want (and if your server doesn't explode)

Prerequisites: Things You'll Need (Besides Patience)

Danny Glover probably can't do this

Before we dive into this technological odyssey, make sure you have:

  1. A VPS or dedicated server - Yes, that Raspberry Pi under your desk won't cut it
  2. Ubuntu 20.04+ or any Linux distro - Because Windows servers are like wearing socks with sandals
  3. Docker and Docker Compose installed - If you don't have these, are you even DevOps-ing?
  4. A domain name - Because accessing services via IP addresses is barbaric
  5. Basic terminal skills - Or at least the ability to copy-paste without breaking things
  6. Coffee - Lots of it. This is going to be a journey.

The Actual Installation: Let's Get Our Hands Dirty

Step 0: Buying domain and vps

Before installation need to buy domain and vps. It is assumed that the server has already been purchased. Domain name you can buy on godaddy, regway or cloudflare. Choose what you like, where is price is cheaper.

Also some hosting providers propose to buy vps+domain. Sometimes have a Great offer like if you buy 12 months vps + free domain name for 1 year or something similar.

After that in panel, you need to Bind domain to ip address of your vps. And create some A Records.

Check if your domain bind use nslookup.

Step 1: Install Docker and Docker Compose

Docker Compose | n8n Docs
Install and run n8n using Docker Compose

According to official documentation n8n, docker install one big command in terminal...

# Remove incompatible or out of date Docker implementations if they exist
for pkg in docker.io docker-doc docker-compose docker-compose-v2 podman-docker containerd runc; do sudo apt-get remove $pkg; done
# Install prereq packages
sudo apt-get update
sudo apt-get install ca-certificates curl
# Download the repo signing key
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc
# Configure the repository
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu $(. /etc/os-release && echo "${UBUNTU_CODENAME:-$VERSION_CODENAME}") stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

# Update and install Docker and Docker Compose
sudo apt-get update
sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

Step 2: Create Your Directory Structure (Or: How to Organize Like an Adult)

First, let's create some folders. Yes, folders. Revolutionary technology from 1981 that we still can't live without:

mkdir traefik_data n8n_data local-files postgres pgadmin_data

Now, let's set permissions because Docker has trust issues:

chmod 600 traefik_data
chmod 777 n8n_data
chmod 777 local-files
chmod 777 pgadmin_data
💡
"But why chmod 777?" you ask. Because sometimes you just want things to work, and security is tomorrow's problem. (Just kidding, we'll fix this later... maybe).

Step 3: The Environment File (Where Secrets Go to Die)

Create a .env file with your super-secret configurations:

# Domain configuration section
# Your domain goes here (yes, the one you bought at 3 AM)
DOMAIN_NAME=your-awesome-domain.com

# Subdomains for services !!! IMPORTANT: map your server IP to these subdomains
SUBDOMAIN=n8n
PGADMIN_SUBDOMAIN=pgadmin
ADMINER_SUBDOMAIN=adminer

# Timezone configuration (because time is a social construct)
GENERIC_TIMEZONE=Europe/Moscow

# Email for SSL certificates and PGAdmin login
SSL_EMAIL=your-email@example.com

# Password section (make them strong, unlike your willpower)
# PGAdmin login password
PASSWORD_PGADMIN=ChangeThisOrGetHacked123!

# PostgreSQL password - make it long, like your deployment time
POSTGRES_PASSWORD=SeriouslyChangeThisPassword456!

Here is need to change next parameters: DOMAIN_NAME, SUBDOMAIN, GENERIC_TIMEZONE, SSL_EMAIL, PASSWORD_PGADMIN and POSTGRES_PASSWORD.

💡
Pro tip: If your password is "password123", you deserve whatever happens next.

Step 4: The Docker Compose File (Where the Magic Happens)

Here's the docker-compose.yml that'll either make you a hero or get you fired:

version: "3.7"

services:
  traefik:
    image: "traefik"
    restart: always
    command:
      - "--api=true"
      - "--api.insecure=true"
      - "--api.dashboard=true"
      - "--providers.docker=true"
      - "--providers.docker.exposedbydefault=false"
      - "--entrypoints.web.address=:80"
      - "--entrypoints.web.http.redirections.entryPoint.to=websecure"
      - "--entrypoints.web.http.redirections.entrypoint.scheme=https"
      - "--entrypoints.websecure.address=:443"
      - "--certificatesresolvers.mytlschallenge.acme.tlschallenge=true"
      - "--certificatesresolvers.mytlschallenge.acme.email=${SSL_EMAIL}"
      - "--certificatesresolvers.mytlschallenge.acme.storage=/letsencrypt/acme.json"
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./traefik_data:/letsencrypt
      - /var/run/docker.sock:/var/run/docker.sock:ro
      
  n8n:
    image: docker.n8n.io/n8nio/n8n
    restart: always
    depends_on:
      - postgres
    ports:
      - "127.0.0.1:5678:5678"
    labels:
      - traefik.enable=true
      - traefik.http.routers.n8n.rule=Host(`${SUBDOMAIN}.${DOMAIN_NAME}`)
      - traefik.http.routers.n8n.tls=true
      - traefik.http.routers.n8n.entrypoints=web,websecure
      - traefik.http.routers.n8n.tls.certresolver=mytlschallenge
      - traefik.http.middlewares.n8n.headers.SSLRedirect=true
      - traefik.http.middlewares.n8n.headers.STSSeconds=315360000
      - traefik.http.middlewares.n8n.headers.browserXSSFilter=true
      - traefik.http.middlewares.n8n.headers.contentTypeNosniff=true
      - traefik.http.middlewares.n8n.headers.forceSTSHeader=true
      - traefik.http.middlewares.n8n.headers.SSLHost=${DOMAIN_NAME}
      - traefik.http.middlewares.n8n.headers.STSIncludeSubdomains=true
      - traefik.http.middlewares.n8n.headers.STSPreload=true
      - traefik.http.routers.n8n.middlewares=n8n@docker
    environment:
      - N8N_HOST=${SUBDOMAIN}.${DOMAIN_NAME}
      - N8N_PORT=5678
      - N8N_PROTOCOL=https
      - NODE_ENV=production
      - WEBHOOK_URL=https://${SUBDOMAIN}.${DOMAIN_NAME}/
      - GENERIC_TIMEZONE=${GENERIC_TIMEZONE}
      - DB_TYPE=postgresdb
      - DB_TABLE_PREFIX=n8n_
      - DB_POSTGRESDB_DATABASE=n8n
      - DB_POSTGRESDB_HOST=postgres # Container name that links - it even creates DNS!
      - DB_POSTGRESDB_USER=postgres 
      - DB_POSTGRESDB_PASSWORD=${POSTGRES_PASSWORD}
      - EXECUTIONS_DATA_MAX_AGE=168 # Hours to keep executions (7 days)
      - EXECUTIONS_DATA_PRUNE_MAX_COUNT=10000 # Number of executions to keep
      - N8N_DEFAULT_BINARY_DATA_MODE=filesystem # Write binary data to disk
    volumes:
      - ./n8n_data:/home/node/.n8n # Where your project lives
      - ./local-files:/files       # Folder for local files
      
  postgres: # Database container name
    image: postgres
    restart: always
    shm_size: 128mb
    environment:
      - POSTGRES_DB=n8n
      - POSTGRES_USER=postgres
      - POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
    volumes:
      - ./postgres:/var/lib/postgresql/data
    # Uncomment to expose database to the entire internet (don't)
    #ports:
    #  - "5432:5432"
    
  pgadmin:
    image: dpage/pgadmin4
    restart: always
    depends_on:
      - postgres
    volumes:
      - ./pgadmin_data:/var/lib/pgadmin
    environment:
      - PGADMIN_DEFAULT_EMAIL=${SSL_EMAIL}
      - PGADMIN_DEFAULT_PASSWORD=${PASSWORD_PGADMIN}
    labels:
      - traefik.enable=true
      - traefik.http.routers.pgadmin.entrypoints=web,websecure
      - traefik.http.routers.pgadmin.tls=true
      - traefik.http.routers.pgadmin.rule=Host(`${PGADMIN_SUBDOMAIN}.${DOMAIN_NAME}`)
      - traefik.http.routers.pgadmin.tls.certresolver=mytlschallenge
      - traefik.http.services.pgadmin.loadbalancer.server.port=80
      
  adminer:
    image: adminer
    restart: always
    depends_on:
      - postgres
    environment:
      - ADMINER_DEFAULT_SERVER=postgres # Must specify postgres container name (default is 'db')
    labels:
      - traefik.enable=true
      - traefik.http.routers.adminer.entrypoints=web,websecure
      - traefik.http.routers.adminer.tls=true
      - traefik.http.routers.adminer.rule=Host(`${ADMINER_SUBDOMAIN}.${DOMAIN_NAME}`)
      - traefik.http.routers.adminer.tls.certresolver=mytlschallenge
      - traefik.http.routers.adminer.middlewares=adminer
      - traefik.http.services.adminer.loadbalancer.server.port=8080
      # For password-protecting adminer: https://hostingcanada.org/htpasswd-generator/
      # Choose Bcrypt (Apache v2.4+), escape dollars with dollars
      - traefik.http.middlewares.adminer.basicauth.users=user:$$2y$$10$$lLTPhmB7Y/vclWnP5xGw0.rZDqsYVW5C/7oWGpdCqHvhM16hNoDAG

Nothing to touch here. Everything should works fine.

Step 5: Deploy This Masterpiece

Pull the images (because downloading things is still a thing in 2025):

docker compose pull

Launch everything and pray to the Docker gods:

docker compose up -d

What Could Possibly Go Wrong? (Everything)

Common Issues and Their Surprisingly Simple Solutions

1. "Permission denied" errors

  • Symptom: Docker hates you and refuses to write files
  • Solution: sudo chown -R 1000:1000 ./n8n_data (because n8n runs as user 1000, not root)
  • Why this happens: Docker's permission system was designed by someone who enjoys watching people suffer

2. "Cannot connect to database"

  • Symptom: n8n can't find PostgreSQL
  • Solution: Check if postgres container is actually running with docker ps
  • Reality check: 90% of the time, you forgot to wait for PostgreSQL to start

3. "JavaScript heap out of memory"

  • Symptom: Your workflows are too ambitious for your server
  • Solution: Add NODE_OPTIONS=--max-old-space-size=4096 to environment variables
  • Translation: Your $5 VPS wasn't meant for enterprise workloads

4. SSL Certificate failures

  • Symptom: Traefik refuses to get certificates
  • Solution: Make sure your DNS actually points to your server (revolutionary, I know)
  • Pro tip: Let's Encrypt rate limits are real. Don't spam certificate requests.

n8n vs The Competition: A Totally Unbiased Comparison

Zapier: The Corporate Overlord

  • Pros: Works out of the box, great UI, your manager has heard of it
  • Cons: Costs more than your Netflix, Spotify, and therapy subscriptions combined
  • Best for: Companies with more money than technical skills

Make.com (formerly Integromat): The Middle Child

  • Pros: Visual workflow builder, decent pricing
  • Cons: Still not self-hosted, limited by their imagination
  • Best for: People who think flowcharts are the pinnacle of programming

n8n: The Open-Source Hero

  • Pros: Self-hosted, unlimited executions, actually respects your data
  • Cons: Requires actual technical knowledge, no one to blame when it breaks
  • Best for: People who read documentation for fun

Advanced Tips for the Brave

1. Enable Queue Mode for Scale

When your single n8n instance starts sweating:

environment:
  - EXECUTIONS_MODE=queue
  - QUEUE_BULL_REDIS_HOST=redis

2. Backup Your Data (Or Cry Later)

# Backup PostgreSQL
docker exec postgres pg_dump -U postgres n8n > backup.sql

# Backup n8n data
tar -czf n8n_backup.tar.gz ./n8n_data

3. Monitor Everything

Because ignorance is bliss until your server crashes:

  • Set up Prometheus + Grafana
  • Monitor memory usage (it's always memory)
  • Set up alerts for when things inevitably break

Security Considerations (Because We're Not Animals)

  1. Change default passwords - Seriously, do it now
  2. Use environment files - Don't hardcode secrets like a freshman CS student
  3. Restrict access - Not everyone needs to see your automation workflows
  4. Regular updates - Yes, even Docker images need updates
  5. Backup encryption keys - Lose these and your credentials are gone forever

The Uncomfortable Truth About Self-Hosting

Let's be honest for a moment. Self-hosting n8n is like getting a pet - it seems fun until you realize the responsibility. You'll spend nights debugging webhook URLs, mornings fixing SSL certificates, and weekends explaining to your significant other why the server needs more RAM.

But here's the thing: it's worth it. Not just for the money you save (though that's nice), but for the control, the learning experience, and the smug satisfaction of telling Zapier users how much you're NOT paying.

Conclusion: You Made It!

Congratulations! You've just set up n8n with Docker Compose. You're now part of an elite group of people who prefer suffering through self-hosting over paying for convenience.

Your n8n instance should now be available at:

  • n8n: https://n8n.your-domain.com
  • PGAdmin: https://pgadmin.your-domain.com
  • Adminer: https://adminer.your-domain.com

Remember: with great automation comes great responsibility. Don't automate yourself out of a job (unless you have a better one lined up).

FAQ: Questions You're Too Proud to Ask

Q: Is this production-ready? A: As production-ready as any Docker Compose setup can be. Add monitoring, backups, and a therapist on speed dial.

Q: Can I use SQLite instead of PostgreSQL? A: Sure, if you enjoy database corruption and limited concurrent access. PostgreSQL is the adult choice.

Q: Why is my server on fire? A: You probably created an infinite loop in your workflow. We've all been there.

Q: Should I use this for my Fortune 500 company? A: Only if you enjoy explaining open-source software to compliance officers.


Found this guide helpful? Share it with someone who's still paying for Zapier. Found it unhelpful? Well, you get what you pay for.

Remember: automation is meant to save time, not create new and exciting ways to waste it. Use responsibly.

Полезное изображение

Перед тем как уйти...

Надеюсь, эта статья была полезной. Если есть желание и возможность, то проект можно поддержать через Юмани.