Skip to main contentSkip to navigation
[email protected]
Client AreaSupport
Hosting Mammoth
HostingMammothYour Data, Our Responsibility
Home
Solutions
Hosting Services
Store
Pricing
About
Blog
API
Contact

Stay Ahead of the Curve

Get the latest insights on cybersecurity, AI innovations, and enterprise data solutions delivered to your inbox.

Hosting Mammoth
HostingMammothEnterprise Solutions

Enterprise-grade data solutions. Hosting, recovery, cybersecurity, and AI-powered services for businesses worldwide.

[email protected]
Sun - Fri, 9:00am - 5:00pm

Services

  • Cloud Hosting
  • Data Recovery
  • Cybersecurity
  • Legal Support
  • MSP Services
  • Web Development
  • AI Services
  • Free Server Migration

Hosting

  • VPS Hosting (NVMe SSD)
  • VDS Hosting (NVMe)
  • Storage VPS (High SSD)
  • GPU Servers
  • Managed Services
  • Cloud Firewall
  • Load Balancer
  • One-Click Apps
  • n8n Hosting
  • Object Storage
  • FAQ

Company

  • Store
  • Pricing
  • About Us
  • Locations
  • Blog
  • Testimonials
  • Contact
  • Affiliate Program
  • White-Label
  • Terms of Service
  • Privacy Policy
  • Browser Cookies
  • SLA

Support

  • Client Area
  • Submit Ticket
  • Knowledge Base
  • Server Status
  • API Documentation

© 2026 Hosting Mammoth. All rights reserved.

Knowledge Base
Getting StartedAccount ManagementVPS HostingGPU ServersStorage VPSCloud FirewallLoad BalancerServer ManagementBilling & PaymentsSupport & TicketsAffiliate ProgramReseller ProgramMarketplace & Appsn8n HostingManaged ServicesServer MigrationAPI & DevelopersSecurityTroubleshootingGlossaryInstall Guides
  1. Home
  2. /
  3. Support
  4. /
  5. Install Guides
  6. /
  7. How To Install N8n Ubuntu
GUIDEInstall Guides

How to Install n8n on Ubuntu 24.04 VPS: Self-Hosted Workflow Automation (Zapier Alternative)

28 min read

How to Install n8n on Ubuntu 24.04 VPS: Self-Hosted Workflow Automation (Zapier Alternative)

Workflow automation has become the glue that holds modern business operations together. Marketing teams sync leads between forms and CRMs. DevOps teams chain alerts into ticket systems. Ecommerce shops reconcile orders, invoices, and shipping labels across a dozen SaaS tools. For years, the default answer has been Zapier or Make (formerly Integromat) -- polished, expensive, and hosted entirely on someone else's infrastructure.

n8n is the self-hosted alternative. It is open-source, source-available under a fair-code license, and runs anywhere you can run Docker. In this tutorial, you will install n8n on a fresh Ubuntu 24.04 VPS using Docker Compose with a production-grade stack: a Postgres database, Redis for queue mode, an Nginx reverse proxy with a free Let's Encrypt TLS certificate, and basic-auth protection. By the end, you will have a public https://n8n.yourdomain.com URL running your first workflow, ready to replace a handful of Zapier tasks without paying per execution.

Want a fast, low-cost VPS for n8n? The CloudCore Starter plan gives you 4 vCPU, 8 GB RAM, and 200 GB NVMe -- more than enough headroom for tens of thousands of monthly workflow executions. Deploy in minutes, keep your automations private, and never pay a per-task bill again.

Table of Contents

  • What is n8n?
  • Why Self-Host n8n Instead of Using Zapier or Make?
  • Prerequisites
  • Step 1: Update the System and Install Docker
  • Step 2: Point Your Domain at the VPS
  • Step 3: Create the n8n Project Directory and .env File
  • Step 4: Write the Docker Compose File (n8n + Postgres + Redis)
  • Step 5: Start the Stack
  • Step 6: Configure Nginx Reverse Proxy + TLS
  • Step 7: First Login and Basic-Auth
  • Step 8: Build Your First Workflow with a Webhook Trigger
  • Step 9: Store Credentials Safely
  • Step 10: Install Community Nodes
  • Upgrading n8n
  • Backing Up n8n (Postgres + Encryption Key)
  • Troubleshooting
  • FAQ
  • Next Steps
  • What is n8n?

    n8n -- pronounced "n-eight-n", short for "nodemation" -- is an open-source workflow automation platform. You build automations visually by dragging nodes onto a canvas and connecting them with lines. Each node represents an action: read a row from a Google Sheet, send a Slack message, query a Postgres database, call an arbitrary HTTP API, or run a block of JavaScript or Python. Workflows fire on triggers -- cron schedules, incoming webhooks, new emails, file uploads, database changes, or manual clicks.

    The platform ships with more than 400 built-in integrations covering the SaaS stack most businesses rely on: Slack, Discord, Gmail, Google Drive, Notion, Airtable, HubSpot, Salesforce, Stripe, Shopify, WooCommerce, GitHub, GitLab, Jira, Trello, Asana, Mailchimp, ActiveCampaign, AWS, GCP, Azure, Postgres, MySQL, MongoDB, Redis, and many more. When a native node does not exist, the generic HTTP Request node and Code node let you talk to any REST or GraphQL API and transform the response in JavaScript or Python.

    n8n is source-available under the Sustainable Use License. That means you can self-host it for free for internal business purposes forever. You cannot resell it as a hosted SaaS competitor to n8n Cloud, but for the vast majority of teams that simply want to run workflows, the license is effectively as permissive as MIT. The project has raised tens of millions in venture capital, ships stable releases roughly every two weeks, and has a thriving community with thousands of shared workflow templates.

    Why Self-Host n8n Instead of Using Zapier or Make?

    Zapier and Make are excellent products, but their business model charges per "task" or "operation" -- every single action a workflow takes. At modest scale this gets expensive fast. A workflow that syncs 5,000 contacts per month from a form to a CRM and sends a Slack notification uses 10,000+ tasks. On Zapier's Professional plan that is around $50/month; scale to 100,000 tasks and you are north of $300/month.

    Self-hosting n8n on your own VPS costs a flat monthly fee regardless of volume. But price is only half the story.

    • Unlimited executions for a flat price -- Run 1,000 or 10,000,000 workflow executions per month. Your VPS bill stays the same.
    • Your data stays on your server -- Customer PII, API keys, internal documents, and CRM exports never leave infrastructure you control. Huge wins for GDPR, HIPAA, SOC 2, and any compliance program that flags third-party data processors.
    • No vendor lock-in -- Export any workflow as a JSON file. Move it to another n8n instance in seconds. No proprietary flow format.
    • Run code without sandboxes -- The Code node runs arbitrary JavaScript or Python. Install npm packages. Hit internal APIs on your private network. Mount files. None of this is possible on Zapier.
    • Self-hosted AI, databases, and private APIs -- Connect n8n to a local Ollama instance, an internal Postgres, or a VPN-only Jira without exposing them to the internet.
    • Community nodes -- The registry has thousands of third-party nodes you can install in a single click. If someone built it, you can use it.

    Cost Comparison: Zapier vs. Make vs. Self-Hosted n8n

    ScenarioZapier ProfessionalMake CoreSelf-Hosted n8n (VPS)
    Monthly cost at 10k tasks~$50/mo~$16/moEUR 7.99/mo (flat)
    Monthly cost at 100k tasks~$300/mo~$50/moEUR 7.99/mo (flat)
    Monthly cost at 1M tasks~$1,500/mo~$300/moEUR 19.99/mo (flat)
    Execution timeout30 sec (paid 10 min)40 minUnlimited
    Custom codeLimited JSLimited JSFull JS + Python + npm
    Data residencyUS/EU (theirs)EU (theirs)Your VPS
    Workflow versioningPaid tier onlyBuilt-inGit-native
    Community nodesNot supportedNot supported900+ available
    For teams running more than a few low-volume flows, n8n pays for itself in the first billing cycle.

    Prerequisites

    Before you begin, make sure you have:

    • A VPS running Ubuntu 24.04 LTS with root or sudo access
    • SSH access to the server
    • A domain name (for example yourdomain.com) with DNS you can edit -- we will create an n8n.yourdomain.com subdomain
    • Ports 80 and 443 open in your firewall and on your VPS provider's dashboard
    • At least 2 GB RAM (4 GB+ recommended for queue mode with Redis)
    • At least 20 GB free disk space for Docker images, Postgres data, and workflow execution history
    Recommended Plan: CloudCore Starter
    >
    For a production n8n instance handling a few hundred thousand executions per month comfortably, we recommend the CloudCore Starter plan:
    >
    - 4 vCPU cores
    - 8 GB RAM
    - 200 GB NVMe SSD
    - Unmetered bandwidth
    - Free daily snapshots
    >
    That gives you headroom for n8n, Postgres, Redis, Nginx, and a few side projects on the same server. For higher volumes or multiple worker processes, upgrade to CloudCore Professional at any time.

    Connect to your server via SSH to get started:

    bash
    ssh root@your-server-ip

    Step 1: Update the System and Install Docker

    Start by updating your package index and upgrading installed packages:

    bash
    sudo apt update && sudo apt upgrade -y

    Install Docker and Docker Compose. We will use the official Docker repository so we get the latest stable release with the Compose plugin bundled in.

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

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

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

    Verify both Docker and the Compose plugin are installed:

    bash
    docker --version
    docker compose version

    Expected output:

    text
    Docker version 27.3.1, build ce12230
    Docker Compose version v2.29.7

    If Docker is brand new to you, our full Install Docker on Ubuntu tutorial walks through post-install hardening, the docker group, and log rotation in more detail.

    Step 2: Point Your Domain at the VPS

    n8n needs a real HTTPS URL for webhooks to work reliably. Many SaaS tools (Stripe, GitHub, Shopify, etc.) refuse to send webhooks to HTTP endpoints or IP addresses.

    In your DNS provider (Cloudflare, Namecheap, Gandi, Route 53, etc.), create an A record:

    TypeNameValueTTL
    An8nyour-vps-public-ipAuto / 300
    Propagation usually takes 1-5 minutes. Verify the record resolves:

    bash
    dig +short n8n.yourdomain.com

    You should see your VPS IP address. If not, wait a couple of minutes and try again before continuing -- the Let's Encrypt step depends on this DNS record being live.

    Step 3: Create the n8n Project Directory and .env File

    All configuration will live in a single directory under /opt/n8n. This keeps backups and migrations simple.

    bash
    sudo mkdir -p /opt/n8n
    cd /opt/n8n

    Generate a strong encryption key. n8n uses this to encrypt credentials stored in the database -- if you lose this key, you lose access to every saved credential, so we will back it up later.

    bash
    openssl rand -hex 32

    Copy the output -- a 64-character hex string -- and keep it in a password manager now.

    Create the .env file:

    bash
    sudo nano /opt/n8n/.env

    Paste the following, replacing the placeholder values with your own:

    bash
    # Domain / URL configuration
    N8N_HOST=n8n.yourdomain.com
    N8N_PROTOCOL=https
    N8N_PORT=5678
    WEBHOOK_URL=https://n8n.yourdomain.com/
    GENERIC_TIMEZONE=UTC

    Basic auth (first-line defence before you set up the owner account)

    N8N_BASIC_AUTH_ACTIVE=true N8N_BASIC_AUTH_USER=admin N8N_BASIC_AUTH_PASSWORD=change-me-to-a-long-random-password

    Credential encryption (DO NOT lose this)

    N8N_ENCRYPTION_KEY=paste-your-64-char-hex-key-here

    Postgres

    DB_TYPE=postgresdb DB_POSTGRESDB_HOST=postgres DB_POSTGRESDB_PORT=5432 DB_POSTGRESDB_DATABASE=n8n DB_POSTGRESDB_USER=n8n DB_POSTGRESDB_PASSWORD=another-long-random-password

    Queue mode (Redis)

    EXECUTIONS_MODE=queue QUEUE_BULL_REDIS_HOST=redis QUEUE_BULL_REDIS_PORT=6379

    Keep execution history manageable

    EXECUTIONS_DATA_PRUNE=true EXECUTIONS_DATA_MAX_AGE=336 # hours (= 14 days) EXECUTIONS_DATA_SAVE_ON_ERROR=all EXECUTIONS_DATA_SAVE_ON_SUCCESS=all EXECUTIONS_DATA_SAVE_MANUAL_EXECUTIONS=true

    Misc

    N8N_LOG_LEVEL=info N8N_DIAGNOSTICS_ENABLED=false N8N_VERSION_NOTIFICATIONS_ENABLED=true

    Save (Ctrl+O, Enter) and exit (Ctrl+X).

    Tighten permissions so other users on the box cannot read your secrets:

    bash
    sudo chmod 600 /opt/n8n/.env

    Step 4: Write the Docker Compose File (n8n + Postgres + Redis)

    Create docker-compose.yml in the same directory:

    bash
    sudo nano /opt/n8n/docker-compose.yml

    Paste the following:

    yaml
    services:
      postgres:
        image: postgres:16-alpine
        restart: unless-stopped
        environment:
          POSTGRES_USER: ${DB_POSTGRESDB_USER}
          POSTGRES_PASSWORD: ${DB_POSTGRESDB_PASSWORD}
          POSTGRES_DB: ${DB_POSTGRESDB_DATABASE}
        volumes:
          - postgres_data:/var/lib/postgresql/data
        healthcheck:
          test: ["CMD-SHELL", "pg_isready -U ${DB_POSTGRESDB_USER} -d ${DB_POSTGRESDB_DATABASE}"]
          interval: 10s
          timeout: 5s
          retries: 5

    redis: image: redis:7-alpine restart: unless-stopped command: ["redis-server", "--appendonly", "yes"] volumes: - redis_data:/data healthcheck: test: ["CMD", "redis-cli", "ping"] interval: 10s timeout: 5s retries: 5

    n8n: image: n8nio/n8n:latest restart: unless-stopped depends_on: postgres: condition: service_healthy redis: condition: service_healthy ports: - "127.0.0.1:5678:5678" environment: - N8N_HOST=${N8N_HOST} - N8N_PROTOCOL=${N8N_PROTOCOL} - N8N_PORT=${N8N_PORT} - WEBHOOK_URL=${WEBHOOK_URL} - GENERIC_TIMEZONE=${GENERIC_TIMEZONE} - N8N_BASIC_AUTH_ACTIVE=${N8N_BASIC_AUTH_ACTIVE} - N8N_BASIC_AUTH_USER=${N8N_BASIC_AUTH_USER} - N8N_BASIC_AUTH_PASSWORD=${N8N_BASIC_AUTH_PASSWORD} - N8N_ENCRYPTION_KEY=${N8N_ENCRYPTION_KEY} - DB_TYPE=${DB_TYPE} - DB_POSTGRESDB_HOST=${DB_POSTGRESDB_HOST} - DB_POSTGRESDB_PORT=${DB_POSTGRESDB_PORT} - DB_POSTGRESDB_DATABASE=${DB_POSTGRESDB_DATABASE} - DB_POSTGRESDB_USER=${DB_POSTGRESDB_USER} - DB_POSTGRESDB_PASSWORD=${DB_POSTGRESDB_PASSWORD} - EXECUTIONS_MODE=${EXECUTIONS_MODE} - QUEUE_BULL_REDIS_HOST=${QUEUE_BULL_REDIS_HOST} - QUEUE_BULL_REDIS_PORT=${QUEUE_BULL_REDIS_PORT} - EXECUTIONS_DATA_PRUNE=${EXECUTIONS_DATA_PRUNE} - EXECUTIONS_DATA_MAX_AGE=${EXECUTIONS_DATA_MAX_AGE} - EXECUTIONS_DATA_SAVE_ON_ERROR=${EXECUTIONS_DATA_SAVE_ON_ERROR} - EXECUTIONS_DATA_SAVE_ON_SUCCESS=${EXECUTIONS_DATA_SAVE_ON_SUCCESS} - N8N_LOG_LEVEL=${N8N_LOG_LEVEL} - N8N_DIAGNOSTICS_ENABLED=${N8N_DIAGNOSTICS_ENABLED} volumes: - n8n_data:/home/node/.n8n - ./files:/files

    n8n-worker: image: n8nio/n8n:latest restart: unless-stopped depends_on: - n8n command: worker environment: - N8N_ENCRYPTION_KEY=${N8N_ENCRYPTION_KEY} - DB_TYPE=${DB_TYPE} - DB_POSTGRESDB_HOST=${DB_POSTGRESDB_HOST} - DB_POSTGRESDB_PORT=${DB_POSTGRESDB_PORT} - DB_POSTGRESDB_DATABASE=${DB_POSTGRESDB_DATABASE} - DB_POSTGRESDB_USER=${DB_POSTGRESDB_USER} - DB_POSTGRESDB_PASSWORD=${DB_POSTGRESDB_PASSWORD} - EXECUTIONS_MODE=${EXECUTIONS_MODE} - QUEUE_BULL_REDIS_HOST=${QUEUE_BULL_REDIS_HOST} - QUEUE_BULL_REDIS_PORT=${QUEUE_BULL_REDIS_PORT} - GENERIC_TIMEZONE=${GENERIC_TIMEZONE} volumes: - n8n_data:/home/node/.n8n - ./files:/files

    volumes: postgres_data: redis_data: n8n_data:

    A few design notes on this compose file:

    • Queue mode is on. EXECUTIONS_MODE=queue makes the main n8n container enqueue jobs into Redis; the separate n8n-worker container picks them up. This prevents long-running workflows from blocking the UI and webhook responses, and lets you scale horizontally by adding more n8n-worker replicas later.
    • n8n listens only on localhost. The 127.0.0.1:5678:5678 binding means n8n is not exposed to the public internet directly. Nginx will terminate TLS and proxy to it in the next step.
    • Postgres and Redis have no host ports. They are reachable only on the internal Docker network, which is exactly what we want.
    • Named volumes (postgres_data, redis_data, n8n_data) survive docker compose down. A ./files bind mount is mapped into both n8n and the worker so workflows can read/write shared files.
    Save and exit.

    Step 5: Start the Stack

    Pull the images and start everything in detached mode:

    bash
    cd /opt/n8n
    sudo docker compose up -d

    Expected output (abbreviated):

    text
    [+] Running 4/4
     ✔ Network n8n_default        Created
     ✔ Container n8n-postgres-1   Healthy
     ✔ Container n8n-redis-1      Healthy
     ✔ Container n8n-n8n-1        Started
     ✔ Container n8n-n8n-worker-1 Started

    Check container status:

    bash
    sudo docker compose ps

    All four services (postgres, redis, n8n, n8n-worker) should report running or healthy. Tail the logs to confirm n8n finished booting:

    bash
    sudo docker compose logs -f n8n

    Look for a line like:

    text
    Editor is now accessible via:
    http://localhost:5678

    Press Ctrl+C to stop tailing. n8n is running, but it is only reachable on the VPS itself. Next we expose it to the internet through Nginx.

    Step 6: Configure Nginx Reverse Proxy + TLS

    Install Nginx and Certbot:

    bash
    sudo apt install -y nginx certbot python3-certbot-nginx

    Create the site configuration:

    bash
    sudo nano /etc/nginx/sites-available/n8n

    Paste:

    nginx
    server {
        listen 80;
        listen [::]:80;
        server_name n8n.yourdomain.com;

    # Allow Let's Encrypt HTTP-01 challenge to pass through location /.well-known/acme-challenge/ { root /var/www/html; }

    # Redirect everything else to HTTPS location / { return 301 https://$host$request_uri; } }

    server { listen 443 ssl http2; listen [::]:443 ssl http2; server_name n8n.yourdomain.com;

    # Certbot will fill these in automatically ssl_certificate /etc/letsencrypt/live/n8n.yourdomain.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/n8n.yourdomain.com/privkey.pem; include /etc/letsencrypt/options-ssl-nginx.conf; ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;

    # Security headers add_header X-Content-Type-Options nosniff; add_header X-Frame-Options SAMEORIGIN; add_header Referrer-Policy strict-origin-when-cross-origin;

    # Allow large webhook payloads (file uploads etc.) client_max_body_size 50m;

    location / { proxy_pass http://127.0.0.1:5678; proxy_http_version 1.1;

    proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme;

    # WebSocket support for the editor UI proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade";

    # Long-running workflows can stream responses for a while proxy_read_timeout 3600s; proxy_send_timeout 3600s; proxy_buffering off; } }

    Enable the site, remove the default, and let Certbot handle the certificate:

    bash
    sudo ln -s /etc/nginx/sites-available/n8n /etc/nginx/sites-enabled/
    sudo rm -f /etc/nginx/sites-enabled/default
    sudo certbot --nginx -d n8n.yourdomain.com

    Certbot will prompt for an email, ask you to agree to the ToS, ask about HTTP-to-HTTPS redirect (choose "2: Redirect"), obtain a certificate, and rewrite the Nginx config with the correct paths. Reload Nginx:

    bash
    sudo nginx -t && sudo systemctl reload nginx

    Certbot installs a renewal timer automatically (sudo systemctl list-timers | grep certbot). Your cert will rotate every 60-90 days with zero intervention.

    Open https://n8n.yourdomain.com in a browser. You should be prompted for the basic-auth credentials you set in .env (user admin, whatever password you chose).

    Step 7: First Login and Basic-Auth

    After passing basic-auth, n8n presents the Owner setup screen. This creates the first real user account stored inside n8n's own auth system.

  • Enter your email, a full name, and a strong password.
  • Click Next and fill in (or skip) the survey questions.
  • You land on the empty n8n canvas.
  • A note on layered auth: the basic-auth variables (N8N_BASIC_AUTH_*) provide a first line of defence at the HTTP level, and the n8n owner/user system provides application-level auth and role-based access control. You can disable basic-auth once you have configured the owner account plus additional users, but many admins keep it on as belt-and-braces protection against bots hitting the login page.

    Step 8: Build Your First Workflow with a Webhook Trigger

    Let's build a minimal workflow: a webhook receives a JSON payload, the workflow formats a message, then posts it to an HTTP endpoint (swap the endpoint for a real Slack node later).

  • Click Workflows -> New in the top-left.
  • On the canvas, click the big + button. Choose Trigger, then select Webhook.
  • Configure the Webhook node:
  • - HTTP Method: POST - Path: order-created (n8n will build a full URL from this) - Respond: Immediately
  • Copy the Test URL and Production URL shown in the node panel. The Production URL will look like https://n8n.yourdomain.com/webhook/order-created.
  • Click the + on the right of the Webhook node and add a Set node. Rename it to Build message. Add a single string field:
  • - Name: text - Value: ={{ "New order #" + $json.body.order_id + " from " + $json.body.customer.email }}
  • Connect Build message to a new HTTP Request node (or a Slack node if you want to wire up real credentials later). Point the HTTP Request at https://httpbin.org/post, method POST, body {{ $json }}. This just echoes the payload -- perfect for a first test.
  • Click Save (top right). Name the workflow First webhook demo.
  • Test the webhook with curl from your laptop:

    bash
    curl -X POST https://n8n.yourdomain.com/webhook-test/order-created \
      -H "Content-Type: application/json" \
      -d '{"order_id":"1001","customer":{"email":"[email protected]"}}'

    Back in the n8n editor, click Executions in the left sidebar. You should see the test run, click in, and inspect the data flowing through each node.

    Once the flow behaves as expected, flip the Active toggle in the top right. n8n now listens on the production URL (/webhook/order-created, no -test). Wire that URL into Stripe, Shopify, Typeform, or any tool that sends webhooks, and your automation is live.

    Step 9: Store Credentials Safely

    Every service integration -- Slack, Gmail, Postgres, AWS, OpenAI -- needs credentials. n8n stores them in the database encrypted with the N8N_ENCRYPTION_KEY you generated in Step 3.

    To add one:

  • Click Credentials in the left sidebar, then Add credential.
  • Pick the service (for example Slack OAuth2 API).
  • Fill in the credential form. Some services use API keys; others walk you through an OAuth redirect. For OAuth, n8n automatically uses your public domain -- this is why HTTPS matters, because OAuth providers reject http:// callback URLs.
  • Click Save.
  • Credentials are now available in every workflow. You can reuse a single Slack credential across dozens of nodes without re-entering the token.

    Two security reminders:

    • Rotate keys regularly. If a VPS user account is compromised, assume any non-rotated credential is burned.
    • Back up N8N_ENCRYPTION_KEY separately from the database. The encrypted credential blobs in Postgres are useless without this key. Losing it forces you to re-create every saved credential from scratch.

    Step 10: Install Community Nodes

    The n8n community node registry has hundreds of third-party nodes: OpenAI assistants, Discord slash commands, Supabase storage, ClickUp, SerpApi, and plenty of niche SaaS integrations.

    Because our Docker image runs as the non-root node user, the cleanest install path is via the settings UI:

  • In n8n, click your avatar (bottom-left) -> Settings -> Community nodes.
  • Click Install.
  • Paste the npm package name, for example n8n-nodes-puppeteer.
  • Confirm the license checkbox and click Install.
  • n8n downloads the package, restarts the Node runtime inside the container, and the new node appears in the node picker on the canvas.

    To install community nodes at image-build time instead (useful for Infrastructure-as-Code setups), create a small custom Dockerfile:

    dockerfile
    FROM n8nio/n8n:latest
    USER root
    RUN cd /usr/local/lib/node_modules/n8n && \
        npm install --omit=dev n8n-nodes-puppeteer n8n-nodes-supabase
    USER node

    Point your docker-compose.yml at this image via a build: block and rebuild with docker compose up -d --build.

    Upgrading n8n

    n8n ships a new minor release roughly every two weeks. Staying on :latest works, but for production you should pin a specific tag and upgrade deliberately after reading the release notes.

    Pin the version in docker-compose.yml:

    yaml
    n8n:
        image: n8nio/n8n:1.74.0
      n8n-worker:
        image: n8nio/n8n:1.74.0

    Upgrade procedure:

    bash
    cd /opt/n8n

    1. Back up the database first (see next section)

    2. Pull the new version and recreate

    sudo sed -i 's|n8nio/n8n:1.74.0|n8nio/n8n:1.76.3|g' docker-compose.yml sudo docker compose pull sudo docker compose up -d

    3. Tail logs; watch for "Editor is now accessible" after any DB migration

    sudo docker compose logs -f n8n

    n8n runs any pending database migrations automatically on start. If a migration fails, n8n refuses to boot -- roll back by restoring the Postgres dump from the previous step and pinning the previous tag.

    Backing Up n8n (Postgres + Encryption Key)

    A complete n8n backup has three parts:

  • The Postgres database -- workflows, credentials (encrypted), execution history, users.
  • The encryption key -- without it the credentials in the DB are unreadable.
  • The /opt/n8n directory -- your .env, docker-compose.yml, and any files under ./files.
  • Daily Postgres Dump

    Create /opt/n8n/backup.sh:

    bash
    sudo nano /opt/n8n/backup.sh

    Paste:

    bash
    #!/usr/bin/env bash
    set -euo pipefail

    STAMP=$(date +%F_%H%M) BACKUP_DIR=/opt/n8n/backups mkdir -p "$BACKUP_DIR"

    Dump the database from the running postgres container

    docker compose -f /opt/n8n/docker-compose.yml exec -T postgres \ pg_dump -U n8n -d n8n --format=custom \ > "$BACKUP_DIR/n8n_${STAMP}.pgdump"

    Keep 14 daily dumps, delete older ones

    find "$BACKUP_DIR" -name "n8n_*.pgdump" -mtime +14 -delete

    echo "Backup complete: $BACKUP_DIR/n8n_${STAMP}.pgdump"

    Make it executable and schedule it:

    bash
    sudo chmod +x /opt/n8n/backup.sh
    sudo crontab -e

    Append:

    text
    0 3   * /opt/n8n/backup.sh >> /var/log/n8n-backup.log 2>&1

    At 03:00 daily, Postgres is dumped to /opt/n8n/backups/. For real disaster recovery, sync that folder off-server -- rclone to S3/B2/Wasabi, restic to another VPS, or the snapshot feature of your VPS provider.

    Restoring a Backup

    On a fresh Ubuntu 24.04 VPS, restore these three things:

  • Reinstall Docker (Step 1).
  • Restore /opt/n8n/.env (including the original N8N_ENCRYPTION_KEY) and docker-compose.yml.
  • Start the stack: docker compose up -d.
  • Load the pgdump into the new Postgres container:
  • bash
    # Stop n8n, keep postgres running
    docker compose stop n8n n8n-worker

    Drop and recreate the empty database

    docker compose exec -T postgres psql -U n8n -d postgres -c "DROP DATABASE IF EXISTS n8n;" docker compose exec -T postgres psql -U n8n -d postgres -c "CREATE DATABASE n8n OWNER n8n;"

    Restore

    cat /opt/n8n/backups/n8n_2026-04-16_0300.pgdump | \ docker compose exec -T postgres pg_restore -U n8n -d n8n --no-owner

    Restart n8n

    docker compose start n8n n8n-worker

    Log in: every workflow, user, and credential is back.

    Troubleshooting

    ProblemCauseSolution
    Editor loads but shows "This site can't be reached" after a momentWebSocket blocked by NginxEnsure proxy_set_header Upgrade $http_upgrade; and proxy_set_header Connection "upgrade"; are in your Nginx config. Reload Nginx.
    Webhook returns 404 not-registeredWorkflow not activated, or using the test URL after it expiredToggle the workflow to Active. Use the Production URL (/webhook/...), not the test URL (/webhook-test/...).
    Error: No key found. Please create encryption key in logsMissing or truncated N8N_ENCRYPTION_KEYCheck that .env has the full 64-char hex key and the compose file passes N8N_ENCRYPTION_KEY to both n8n and n8n-worker.
    Workflows queue up but never executeWorker container not running or not reading the Redis queuedocker compose ps; check n8n-worker logs. Verify EXECUTIONS_MODE=queue and QUEUE_BULL_REDIS_HOST=redis are set on the worker.
    Let's Encrypt fails with "Timeout during connect"Port 80 blocked by firewall or providerOpen TCP 80 and 443 on the VPS firewall (sudo ufw allow 80; sudo ufw allow 443) and in the provider control panel.
    getaddrinfo ENOTFOUND postgres in n8n logsPostgres container not yet healthy when n8n startedThe depends_on: condition: service_healthy should prevent this; if it still happens, bump the Postgres healthcheck retries to 10.
    Memory climbs to 100% and OOM kills n8nExecution data retention too longLower EXECUTIONS_DATA_MAX_AGE from 336 hours. For high-volume setups set EXECUTIONS_DATA_SAVE_ON_SUCCESS=none to only keep failures.
    Basic-auth prompt keeps looping in browserPassword has special chars that .env reads as variableWrap the password in single quotes in .env, or escape $ as $$.

    Viewing Logs

    bash
    # All services
    sudo docker compose -f /opt/n8n/docker-compose.yml logs -f

    Just n8n

    sudo docker compose -f /opt/n8n/docker-compose.yml logs -f n8n

    Worker

    sudo docker compose -f /opt/n8n/docker-compose.yml logs -f n8n-worker

    Postgres

    sudo docker compose -f /opt/n8n/docker-compose.yml logs -f postgres

    FAQ

    How many workflows can a single CloudCore Starter VPS handle?

    It depends almost entirely on what each workflow does. A simple webhook-to-Slack flow takes a few hundred milliseconds of CPU. A workflow that hits three APIs, processes JSON in a Code node, and writes to Postgres might take 1-2 seconds. On a 4 vCPU / 8 GB plan, most teams comfortably handle 200,000+ executions per month with the queue-mode setup in this guide, and scale by adding n8n-worker replicas before scaling the VPS itself.

    Do I actually need queue mode and Redis for a small deployment?

    Not strictly. For a handful of workflows with short runtimes, main-mode (no Redis, no worker container) works fine and uses about 400 MB less RAM. But queue mode costs almost nothing on modern hardware, avoids a whole class of issues where a long-running workflow blocks webhook responses, and lets you scale horizontally by adding more worker containers later without any config change. We recommend queue mode from day one on any production deployment.

    Can I run n8n behind Cloudflare?

    Yes, and many users do. Enable Full (Strict) SSL mode in Cloudflare so the edge-to-origin connection is also encrypted. Cloudflare's default WebSocket support is on, which keeps the editor UI responsive. One caveat: set N8N_PROXY_HOPS=1 in your .env so n8n correctly interprets the X-Forwarded-For chain (Cloudflare -> Nginx -> n8n) for rate limiting and audit logs.

    How does n8n compare to Node-RED and Huginn?

    All three are self-hosted workflow automation tools, but they target different audiences.

    Node-RED originated at IBM for wiring IoT devices together. It is JavaScript-first, lightweight, and ships with strong support for MQTT, serial devices, Modbus, and hardware protocols. Best for home automation, industrial IoT, and maker projects.

    Huginn is a Ruby-on-Rails agent system modelled on "tiny programs that check websites and events and act on your behalf". It is ideal for web scraping, RSS processing, and personal automation, with deep support for building custom agents.

    n8n targets business SaaS integration. Its 400+ native nodes for Gmail, Slack, Salesforce, HubSpot, Stripe, Notion, etc. are far richer than either Node-RED or Huginn out of the box. If your automations are "when X happens in SaaS tool A, do Y in SaaS tool B", n8n is the best fit. If they are "when a sensor reports a temperature above 30C, cut power to this relay", Node-RED wins.

    Is n8n really free forever?

    For self-hosted internal business use, yes. n8n's Sustainable Use License permits unlimited internal use (employees, contractors, internal tooling) at no cost. The only thing it prohibits is offering n8n itself as a hosted service to third parties in competition with n8n Cloud. Everything covered in this tutorial -- running automations for your own company -- is 100% free forever on your own VPS.

    Next Steps

    Your n8n instance is installed, TLS-secured, running in queue mode, and backed up. Here are recommended directions to go from here:

    • Wire up real integrations -- Connect Stripe, Shopify, HubSpot, or Gmail. Check the official integrations catalog and start replacing one Zapier task at a time. Every Zap you migrate is a line-item off your SaaS bill.
    • Import workflow templates -- The n8n template library has 1,500+ pre-built workflows. Click Import in the n8n editor, paste a template URL, and adapt the nodes to your credentials.
    • Add a second worker for scale -- Duplicate the n8n-worker service in docker-compose.yml (name it n8n-worker-2), then docker compose up -d. Redis fans jobs out automatically across all workers. Repeat until CPU stops being the bottleneck.
    • Pair n8n with a self-hosted AI stack -- Point n8n's OpenAI-compatible node at a local Ollama instance to run chat, summarisation, and classification flows with zero per-token cost.
    • Add monitoring -- Scrape n8n's Prometheus metrics (set N8N_METRICS=true) into Grafana to track executions per minute, workflow error rate, and queue depth. Alert on queue depth growing faster than the worker can drain it.
    • Secure with 2FA and SSO -- The n8n owner account supports TOTP-based 2FA out of the box. For teams, enable SAML SSO in Settings -> SSO to delegate auth to Okta, Google Workspace, or Azure AD.
    • Read the official docs for deep dives -- The n8n documentation covers environment variables, expression syntax, the Code node, SSO, and the dozens of configuration options not touched in this tutorial.

    Deploy n8n on a Fast, Quiet VPS
    >
    Our CloudCore Starter plan gives you 4 vCPU, 8 GB RAM, and 200 GB NVMe -- tuned for Docker workloads like n8n, Postgres, and Redis side by side. Daily snapshots are free, bandwidth is unmetered, and our support team actually runs these stacks in production.
    >
    Launch Your VPS Now -- Plans from EUR 7.99/month.

    Was this article helpful?

    ← Back to Install GuidesBrowse all categories →

    Still have questions?

    Contact Support →Submit a Ticket