n8n Self-Hosted: Deploy Your Own Automation Platform and Skip the Subscription

24.03.2026
10:26

n8n is an open-source workflow automation platform built on the "if this happens, do that" principle. Data scraping, notifications, service synchronization, webhook processing — everything's built visually without coding. Think Zapier or Make, but without monthly bills and with full control over your data.

The cloud version n8n.cloud charges $20-50/month for convenience. Self-hosted on your own server costs €5-15/month for a VPS — the savings are obvious if you plan long-term use. Plus no limits on operations, data privacy, and complete customization freedom.

This guide shows how to deploy n8n on your server in 15 minutes from scratch. SSL certificate, domain name, automatic restart on reboot, security setup — all included. We'll finish with three practical automation scenarios that work immediately after installation.

What You'll Need

Linux Server:
Minimum 1 vCPU / 2 GB RAM / 20 GB disk. This handles 5-10 concurrent workflows comfortably. For active usage, grab 2 vCPU / 4 GB RAM for headroom.

Operating system: Ubuntu 22.04 or 24.04. Instructions written for Ubuntu, but Debian works identically.

Domain Name:
You need a domain or subdomain to access n8n via a clean address like automation.your-domain.com. Register one for €10/year or use an existing domain.

DNS A record should point to your server's IP address. Configure this in your domain panel — add a record automation with value 123.45.67.89 (your IP).

Email for SSL:
Let's Encrypt requires an email when issuing certificates. Used for renewal notifications — any working address works.

SSH Access:
Connection to server via SSH with sudo privileges. If you just created the VPS, credentials usually arrive via email — root login and password or SSH key.

Server Preparation

Connect to your server:

ssh root@123.45.67.89

Update system packages:

apt update && apt upgrade -y

Install Docker — the engine for running containers. n8n will run inside an isolated container, which is cleaner than direct system installation:

apt install -y ca-certificates curl
install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
chmod a+r /etc/apt/keyrings/docker.asc

echo \
  "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu \
  $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
  tee /etc/apt/sources.list.d/docker.list > /dev/null

apt update
apt install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin

Verify Docker installed:

docker --version

Should show something like Docker version 25.0.3, build 4debf41. Version may differ — main thing is the command works without errors.

Enable Docker auto-start on server boot:

systemctl enable docker
systemctl start docker

Deploy n8n via Docker Compose

Create directory where n8n lives with all its dаta:

mkdir -p /opt/n8n
cd /opt/n8n

Create docker-compose.yml file describing how to run n8n:

nano docker-compose.yml

Paste configuration (replace automation.your-domain.com with your actual domain, your@email.com with your email):

version: '3.8'

services:
  n8n:
    image: n8nio/n8n:latest
    container_name: n8n
    restart: unless-stopped
    ports:
      - "5678:5678"
    environment:
      - N8N_HOST=automation.your-domain.com
      - N8N_PORT=5678
      - N8N_PROTOCOL=https
      - NODE_ENV=production
      - WEBHOOK_URL=https://automation.your-domain.com/
      - GENERIC_TIMEZONE=America/New_York
      - N8N_EMAIL_MODE=smtp
      - N8N_SMTP_HOST=smtp.gmail.com
      - N8N_SMTP_PORT=465
      - N8N_SMTP_USER=your@email.com
      - N8N_SMTP_PASS=your-app-password
      - N8N_SMTP_SENDER=your@email.com
      - N8N_SMTP_SSL=true
    volumes:
      - /opt/n8n/dаta:/home/node/.n8n
      - /opt/n8n/files:/files
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.n8n.rule=Host(`automation.your-domain.com`)"
      - "traefik.http.routers.n8n.entrypoints=websecure"
      - "traefik.http.routers.n8n.tls.certresolver=mytlschallenge"
      - "traefik.http.services.n8n.loadbalancer.server.port=5678"

  traefik:
    image: traefik:v2.10
    container_name: traefik
    restart: unless-stopped
    command:
      - "--api.insecure=true"
      - "--providers.docker=true"
      - "--providers.docker.exposedbydefault=false"
      - "--entrypoints.web.address=:80"
      - "--entrypoints.websecure.address=:443"
      - "--certificatesresolvers.mytlschallenge.acme.tlschallenge=true"
      - "--certificatesresolvers.mytlschallenge.acme.email=your@email.com"
      - "--certificatesresolvers.mytlschallenge.acme.storage=/letsencrypt/acme.json"
      - "--entrypoints.web.http.redirections.entrypoint.to=websecure"
      - "--entrypoints.web.http.redirections.entrypoint.scheme=https"
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - /opt/n8n/letsencrypt:/letsencrypt

Save file: Ctrl+O, Enter, Ctrl+X.

What's happening: we launch two containers — n8n itself and Traefik (reverse proxy that automatically gets SSL certificate from Let's Encrypt). n8n will be accessible via HTTPS with automatic HTTP redirect.

Important variables:

  • N8N_HOST — your domain
  • WEBHOOK_URL — address for webhooks (same domain with https://)
  • GENERIC_TIMEZONE — timezone, change to yours
  • SMTP settings — for sending notifications (optional, remove if unneeded)

Create data directories:

mkdir -p /opt/n8n/data /opt/n8n/files /opt/n8n/letsencrypt

Launch:

docker compose up -d

Flag -d means background mode. Docker downloads images (takes 1-2 minutes on first run), starts containers, Traefik automatically gets SSL certificate.

Verify everything works:

docker compose ps

Should see two containers with Up status:

NAME                IMAGE               STATUS
n8n                 n8nio/n8n:latest    Up 30 seconds
traefik             traefik:v2.10       Up 30 seconds

Check logs to ensure no errors:

docker compose logs -f n8n

If you see line Editor is now accessible via: https://automation.your-domain.com — you're golden. Press Ctrl+C to exit log view.

First-Time n8n Setup

Open browser and navigate to https://automation.your-domain.com

On first visit, n8n requests owner account creation:

  • Email — your email for login
  • Password — make it strong, this is access to all automations

After registration, you land in n8n interface. Left sidebar shows workflows (empty for now), right side is the canvas for building automations.

Basic Security:

n8n is accessible to anyone who knows the address by default. For extra protection — set up basic authentication at Traefik level or limit access by IP via firewall.

To limit by IP (for example, only from your office):

ufw allow from 123.45.67.89 to any port 443
ufw allow from 98.76.54.32 to any port 443
ufw enable

Replace IP addresses with yours. Verify you won't lock yourself out before enabling firewall.

Environment Variables Configuration

n8n is controlled through environment variables in docker-compose.yml. Here are important ones to know:

For database work:

By default n8n stores data in SQLite file. For production with heavy loads, PostgreSQL is better:

Add to n8n container's environment section:

- DB_TYPE=postgresdb
- DB_POSTGRESDB_HOST=postgres
- DB_POSTGRESDB_PORT=5432
- DB_POSTGRESDB_DATABASE=n8n
- DB_POSTGRESDB_USER=n8n
- DB_POSTGRESDB_PASSWORD=strong-password

And add PostgreSQL service to docker-compose.yml:

  postgres:
    image: postgres:15
    container_name: n8n-postgres
    restart: unless-stopped
    environment:
      - POSTGRES_DB=n8n
      - POSTGRES_USER=n8n
      - POSTGRES_PASSWORD=strong-password
    volumes:
      - /opt/n8n/postgres:/var/lib/postgresql/data

After changes, restart:

docker compose down
docker compose up -d

For external API work:

Many workflows call third-party service APIs. Store API keys in environment variables, not hardcoded in workflows:

- TELEGRAM_BOT_TOKEN=your-bot-token
- OPENAI_API_KEY=your-openai-key
- NOTION_API_KEY=your-notion-key

In workflows, reference via $env.TELEGRAM_BOT_TOKEN instead of hardcoding tokens.

For resource limiting:

If n8n starts consuming all memory on complex workflows:

- N8N_PAYLOAD_SIZE_MAX=16
- EXECUTIONS_DATA_MAX_AGE=168
- EXECUTIONS_DATA_PRUNE=true

First line limits data size passed between nodes (16 MB). Second two auto-delete execution history older than a week.

Three Practical Automation Scenarios

Scenario 1: Telegram Bot for Notifications

Task: receive Telegram notification when someone fills out a website form.

Create new bot via @BotFather in Telegram, get token.

In n8n, create new workflow:

  1. Webhook node — trigger listening for POST requests

    • HTTP Method: POST
    • Path: form-submit
    • Response Mode: Last Node
  2. Telegram node — send message

    • Credential: add bot token
    • Chat ID: your Telegram ID (find via @userinfobot)
    • Text: New submission!\nName: {{$json.name}}\nEmail: {{$json.email}}

Activate workflow. Get webhook URL like:
https://automation.your-domain.com/webhook/form-submit

On website, add form submission to this address:

<form id="contactForm">
  <input name="name" required>
  <input type="email" name="email" required>
  <button type="submit">Submit</button>
</form>

<script>
document.getElementById('contactForm').onsubmit = async (e) => {
  e.preventDefault();
  const data = new FormData(e.target);
  await fetch('https://automation.your-domain.com/webhook/form-submit', {
    method: 'POST',
    headers: {'Content-Type': 'application/json'},
    body: JSON.stringify(Object.fromEntries(data))
  });
  alert('Submitted!');
};
</script>

Now every submission arrives in Telegram instantly.

Scenario 2: Automated Competitor Price Scraping

Task: check competitor's product price daily and log to Google Sheets.

Workflow:

  1. Schedule Trigger — run on schedule

    • Trigger Times: Cron 0 9 * * * (daily at 9 AM)
  2. HTTP Request — scrape page

    • Method: GET
    • URL: https://competitor.com/product/12345
  3. HTML Extract — extract price

    • Selector: .price (CSS selector for price element)
    • Extract: Text
  4. Set — format data

    • Name: price, Value: {{$json.price.replace(/[^0-9]/g, '')}}
    • Name: date, Value: {{$now.format('YYYY-MM-DD')}}
  5. Google Sheets — write to spreadsheet

    • Credential: connect Google account
    • Operation: Append
    • Sheet ID: your sheet ID
    • Range: A:B

Activate — every day at 9 AM price automatically logs to sheet. After a month you see price trends.

Scenario 3: Server File Backup

Task: weekly archive directory and upload to cloud.

Workflow:

  1. Schedule Trigger — every Sunday at 3 AM

    • Cron: 0 3 * * 0
  2. Execute Command — create archive

    • Command: tar -czf /tmp/backup-{{$now.format('YYYY-MM-DD')}}.tar.gz /var/www/html
  3. Read Binary File — read created archive

    • File Path: /tmp/backup-{{$now.format('YYYY-MM-DD')}}.tar.gz
  4. Dropbox / Google Drive — upload to cloud

    • Credential: connect account
    • Operation: Upload
    • File Name: backup-{{$now.format('YYYY-MM-DD')}}.tar.gz
  5. Execute Command — remove temp file

    • Command: rm /tmp/backup-*.tar.gz

Automatic weekly backup without manual intervention.

Maintenance and Backups

n8n Backup:

All n8n data lives in /opt/n8n/data — workflows, credentials, execution history. Copy this directory — save everything.

Simple backup script:

nano /root/backup-n8n.sh
#!/bin/bash
BACKUP_DIR="/root/n8n-backups"
DATE=$(date +%Y-%m-%d-%H%M)

mkdir -p $BACKUP_DIR
tar -czf $BACKUP_DIR/n8n-backup-$DATE.tar.gz /opt/n8n/data

# Remove backups older than 30 days
find $BACKUP_DIR -name "n8n-backup-*.tar.gz" -mtime +30 -delete

Make executable:

chmod +x /root/backup-n8n.sh

Add to crontab for daily run:

crontab -e

Add line:

0 2 * * * /root/backup-n8n.sh

Now every night at 2 AM creates archive with n8n data in /root/n8n-backups.

Updating n8n:

For new features and security fixes, periodically update:

cd /opt/n8n
docker compose pull
docker compose down
docker compose up -d

Command pull downloads latest n8n image version, then restart with new version. All data persists since it's in volumes outside container.

Monitoring Status:

Check status:

docker compose ps

View recent error logs:

docker compose logs --tail=50 n8n

Follow logs in real-time:

docker compose logs -f n8n

Common Issues Solved

n8n won't open in browser:

Verify DNS record configured correctly:

nslookup automation.your-domain.com

Should return your server IP. If not — DNS problem, wait for propagation (up to 24 hours) or check registrar settings.

Check containers are running:

docker compose ps

If status isn't Up — check logs:

docker compose logs traefik
docker compose logs n8n

Webhooks don't trigger:

Ensure WEBHOOK_URL in environment variables is correct — should match N8N_HOST and start with https://.

Verify workflow is activated (Active toggle in upper right corner).

Check webhook path has no leading slash — correct is form-submit, wrong is /form-submit.

Memory errors:

If n8n crashes with jаvascript heap out of memory:

Add to docker-compose.yml in environment section:

- NODE_OPTIONS=--max-old-space-size=2048

Number 2048 = 2 GB RAM for Node.js process. If you have 4 GB on server, can set 3072.

SSL certificate won't issue:

Traefik logs show details:

docker compose logs traefik | grep acme

Common cause — ports 80 or 443 occupied by another process. Check:

ss -tulpn | grep :80
ss -tulpn | grep :443

If nginx or apache is there — stop them before launching n8n.

Another cause — DNS record doesn't point to server. Let's Encrypt verifies domain resolves to IP making the certificate request.

Self-Hosted vs Cloud Version

When to choose self-hosted:

Saves money long-term. Cloud $20-50/month, own VPS €5-15/month. Over a year, difference is €180-420.

Full data control. Everything stored on your server, no third parties access workflows and data flowing through the system.

No execution limits. Cloud basic plan has 5000 executions/month, then extra charges. Self-hosted — unlimited, only limited by server power.

Customization. Can modify code, add custom nodes, integrate with internal services directly.

When to choose cloud:

Don't want to handle administration. Installation, updates, backups, security — all on n8n.cloud shoulders.

Need high availability out of box. Cloud has 99.9% SLA, self-hosted — depends on your setup.

Small workloads. If using couple workflows rarely — paying €15/month for idle VPS may be less attractive than $20/month for cloud with support.

Team collaboration. Cloud makes it easier to set up access for multiple users with different roles.

Conclusion

Self-hosted n8n delivers powerful automation tooling at the cost of a modest VPS. After initial setup, the system runs itself — you just create workflows and get results.

Savings versus cloud version pay back the installation time within 2-3 months. Plus complete freedom — no limits, your data under control, customization for any task.

VPS on THE.Hosting with 2 vCPU / 4 GB RAM / 40 GB NVMe configuration for €10-12/month is perfect for n8n with room to grow. NVMe drives accelerate workflow database operations, and 50+ locations let you choose a server close to your users for minimal webhook latency.

Questions about setup? THE.Hosting support is available 24/7 and helps with server configuration for n8n.

Other articles

24.03.2026
10
Knowledge base / All about domains
.HOST Domain Zone
24.03.2026
9
Knowledge base / All about domains
.TEL Domain Zone
24.03.2026
12
Knowledge base / All about domains
.IO Domain Zone for Technology Services and Infrastructure