🇫🇷 New VPS location: Marseille, where Europe meets Africa and Asia. 50% off 2 months on any Linux VPS plan with BONJOUR50 Deploy in Marseille →

How to Self-Host n8n with Docker on a VPS (Step-by-Step Guide)

Comparison of SaaS and Self-Hosting with laptops, cloud icon, and server stacks on a dark blue background.

Want full control over your n8n automation workflows? This guide shows you how to self-host n8n on a VPS using Docker. Self-hosting ensures your data stays secure, avoids subscription fees, and lets you scale resources as needed. Here’s what you’ll learn:

  • Why n8n and self-hosting make sense: Automate tasks across 400+ apps with a visual workflow editor while keeping sensitive data private.
  • Why VPSus is a great choice: Affordable plans starting at $10/month, fast provisioning, and 17 data center locations (including Atlanta and Los Angeles in the U.S.) for low-latency performance.
  • Step-by-step deployment: From setting up a VPS, installing Docker, configuring DNS/HTTPS, and deploying n8n with PostgreSQL.
âš¡ n8n and PostgreSQL fighting over 1 GB of RAM?
Run both comfortably on KVM2: 2 vCores and 2 GB ECC RAM, Docker-ready, with a free n8n domain for HTTPS in year one
25 GB NVMe  Â·  Full root access  Â·  Unmetered 1 Gbps  Â·  $20/mo

Step 1: Set Up Your VPSus Environment

Getting your VPSus server ready for n8n involves three main steps: provisioning the server, configuring it, and installing Docker. These steps lay the groundwork for a smooth and stable n8n deployment.

Provision a VPSus Server

Start by choosing a VPSus plan that matches your n8n needs. For most workflows, the KVM2-US plan at $20/month is a great choice. It offers 2 vCores, 2 GB RAM, and 25 GB of NVMe storage, which is sufficient for moderate automation tasks, multiple integrations, and several concurrent users without performance hiccups.

If you’re dealing with heavier workloads, such as complex data processing or numerous simultaneous workflows, consider the KVM4-US plan at $40/month. This doubles the resources to 4 vCores and 4 GB RAM, ensuring optimal performance.

To minimize latency, select a U.S. data center location close to your team or primary services. VPSus provides Atlanta for East Coast users and Los Angeles for those on the West Coast. This proximity can significantly improve the responsiveness of time-sensitive automations and webhook triggers.

Plan NameCPURAMNVMe StoragePrice (Per Month)Best For
KVM1-US1 vCore1 GB20 GB$10Testing/Light Use
KVM2-US2 vCores2 GB25 GB$20Typical Workloads
KVM4-US4 vCores4 GB40 GB$40Heavy Workloads

Once you’ve selected your plan and location, click “Get started Now” on the VPSus website. The provisioning process typically takes 2-5 minutes, after which you’ll receive root access credentials to your new server.

Initial VPS Setup and Configuration

After provisioning, connect to your server via SSH using the credentials provided. For macOS or Linux, open Terminal and type:

ssh root@your_server_ip

On Windows, use Windows Terminal (with built-in SSH support) or download PuTTY if you’re on an older version of Windows. If you run into connection problems, double-check the server IP in your VPSus control panel and ensure your firewall allows traffic on port 22.

Once connected, update your system to ensure it’s secure and up-to-date:

apt update && apt upgrade -y

Next, set the appropriate time zone for your operations. For East Coast users:

timedatectl set-timezone America/New_York

For West Coast users:

timedatectl set-timezone America/Los_Angeles

Then, configure the locale for U.S. English settings:

dpkg-reconfigure locales

Select en_US.UTF-8 and set it as the default. This ensures proper formatting for dates, numbers, and currency in your workflows. Verify your settings using:

date
locale

With these configurations complete, you’re ready to install Docker and Docker Compose.

Install Docker and Docker Compose

Docker webpage promoting AI development tools with "Develop AI" headline, buttons for downloading Docker Desktop, and learning about Docker for AI.

Docker simplifies the management, updating, and scaling of your n8n deployment by containerizing it. First, remove any existing Docker installations to avoid conflicts:

apt remove docker docker-engine docker.io containerd runc

Install the necessary packages to add Docker’s official repository:

apt install apt-transport-https ca-certificates curl software-properties-common

Add Docker’s GPG key for secure package verification:

curl -fsSL https://download.docker.com/linux/ubuntu/gpg | gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg

Then, add the Docker repository to your system:

echo "deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null

Update your package list and install Docker:

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

To confirm Docker is installed correctly, run:

docker run hello-world

You should see a confirmation message that Docker is working.

The docker-compose-plugin package installed above provides Docker Compose v2, which this guide calls as docker compose (with a space). Verify the installation:

docker compose version

Finally, add your user to the Docker group so you can run commands without using sudo:

usermod -aG docker $USER

Log out and back in for the changes to take effect, or run:

newgrp docker

Your VPSus server is now fully prepared for n8n deployment. The next step is setting up DNS and HTTPS to ensure your n8n instance is accessible and secure.

Step 2: Configure DNS and Set Up HTTPS

Once your server is ready, the next step is connecting your domain and securing it with HTTPS. This ensures your n8n instance is accessible via a user-friendly URL and protected with SSL encryption.

Set Up DNS Records

If you’re using VPSus, a free domain name is included with every KVM plan, which simplifies DNS setup through the control panel.

For external domains, you’ll need to manually create an A record that links your domain to your server’s public IP address. Here’s how to configure the DNS settings through your domain registrar:

  • A record: Point your root domain (e.g., yourdomain.com) to your VPSus server’s IP address.
  • A record: Point your n8n subdomain (e.g., n8n.yourdomain.com) to the same IP address.
  • CNAME record (optional): Redirect www.yourdomain.com to your root domain.

Set the TTL (Time To Live) to 300 seconds (5 minutes) initially. This shorter value speeds up propagation during setup. Once the setup is complete, you can increase it to 3,600 seconds (1 hour) for better performance.

DNS propagation in the United States typically takes 15-30 minutes, but globally, it might take up to 24-48 hours. To check if the DNS records have propagated, run this command:

dig n8n.yourdomain.com

The output should display your server’s IP address. If it doesn’t, wait a bit longer for propagation to finish. Once your DNS records are active, move on to securing your connection with HTTPS.

Enable HTTPS with Let’s Encrypt

Let’s Encrypt offers free SSL certificates, making it easy to secure your n8n instance.

Start by installing Certbot, the official Let’s Encrypt client:

apt install snapd
snap install core; snap refresh core
snap install --classic certbot

To make Certbot available system-wide, create a symbolic link:

ln -s /snap/bin/certbot /usr/bin/certbot

Before generating your SSL certificates, you’ll need to set up Nginx as a reverse proxy for n8n:

apt install nginx
systemctl start nginx
systemctl enable nginx

Create a new Nginx configuration file for your n8n domain:

nano /etc/nginx/sites-available/n8n.yourdomain.com

Add the following configuration:

server {
    listen 80;
    server_name n8n.yourdomain.com;

    location / {
        proxy_pass http://localhost:5678;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        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;
        proxy_cache_bypass $http_upgrade;
    }
}

Enable the site and test the configuration:

ln -s /etc/nginx/sites-available/n8n.yourdomain.com /etc/nginx/sites-enabled/
nginx -t
systemctl reload nginx

Now, generate your SSL certificate using Certbot:

certbot --nginx -d n8n.yourdomain.com

Certbot will automatically update your Nginx configuration to include SSL settings and redirect HTTP traffic to HTTPS. The entire process takes about 30-60 seconds, including domain verification.

To ensure your certificates renew automatically, test the renewal process:

certbot renew --dry-run

If successful, Certbot will handle renewals automatically 30 days before expiration using a systemd timer.

Alternative Option: Cloudflare Tunnel

For an additional security layer, you can use Cloudflare Tunnel instead of exposing HTTPS directly. This method routes traffic through Cloudflare’s network, eliminating the need to open ports 80 or 443 on your server.

Start by installing the Cloudflare daemon:

wget https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64.deb
dpkg -i cloudflared-linux-amd64.deb

Log in to your Cloudflare account and authenticate the daemon:

cloudflared tunnel login

Create a new tunnel for your n8n instance:

cloudflared tunnel create n8n-tunnel

Set up the tunnel configuration file:

nano ~/.cloudflared/config.yml

Add this configuration:

tunnel: n8n-tunnel
credentials-file: /root/.cloudflared/[tunnel-id].json

ingress:
  - hostname: n8n.yourdomain.com
    service: http://localhost:5678
  - service: http_status:404

Next, create a DNS record in Cloudflare that links to your tunnel:

cloudflared tunnel route dns n8n-tunnel n8n.yourdomain.com

Finally, start the tunnel as a system service:

cloudflared service install
systemctl start cloudflared
systemctl enable cloudflared

Using Cloudflare Tunnel eliminates the need for Let’s Encrypt certificates, as Cloudflare manages SSL termination. It also offers DDoS protection and access to traffic analytics through the Cloudflare dashboard.

To confirm your HTTPS setup is working, visit https://n8n.yourdomain.com in your browser and check for the padlock icon next to the URL. Alternatively, you can test the connection using curl:

curl -v https://n8n.yourdomain.com

If the response is successful, your SSL is properly configured, and your domain is securely connected to your VPSus server, ready for n8n deployment.

Step 3: Deploy n8n with Docker Compose and PostgreSQL

n8n website homepage featuring "Flexible AI workflow automation for technical teams" text, lightning bolt graphic, and navigation menu.

After setting up a secure connection, the next step is deploying n8n using Docker Compose and integrating PostgreSQL for efficient data management. Using PostgreSQL instead of the default SQLite ensures better performance, especially for production environments handling over 5,000–10,000 daily executions.

Prepare the Docker Environment

Start by creating a dedicated directory for your deployment files:

mkdir /opt/n8n && cd /opt/n8n

Next, create a .env file to securely store environment variables:

nano .env

Add the following configuration to your .env file:

# PostgreSQL Configuration
POSTGRES_USER=n8n
POSTGRES_PASSWORD=your_secure_password_here
POSTGRES_DB=n8n

# n8n Database Configuration
DB_TYPE=postgresdb
DB_POSTGRESDB_HOST=postgres
DB_POSTGRESDB_PORT=5432
DB_POSTGRESDB_DATABASE=n8n
DB_POSTGRESDB_USER=n8n
DB_POSTGRESDB_PASSWORD=your_secure_password_here
DB_POSTGRESDB_SCHEMA=public

# n8n Security Configuration
N8N_ENCRYPTION_KEY=your_very_long_random_encryption_key_here

# n8n Network Configuration
N8N_HOST=n8n.yourdomain.com
N8N_PROTOCOL=https
WEBHOOK_URL=https://n8n.yourdomain.com/

# n8n Performance Configuration
N8N_RUNNERS_ENABLED=true
N8N_ENFORCE_SETTINGS_FILE_PERMISSIONS=true
GENERIC_TIMEZONE=America/New_York
TZ=America/New_York

Replace the placeholder values with your actual details. Make sure the N8N_ENCRYPTION_KEY is a long, random string (at least 32 characters) to encrypt sensitive credentials. Keep this key safe – losing it means you won’t be able to decrypt stored credentials.

Now, create the docker-compose.yml file:

nano docker-compose.yml

Insert the following configuration:

version: '3.8'

services:
  postgres:
    image: postgres:16-alpine
    container_name: n8n-postgres
    restart: unless-stopped
    env_file:
      - .env
    volumes:
      - postgres_data:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER} -d ${POSTGRES_DB}"]
      interval: 30s
      timeout: 10s
      retries: 5
      start_period: 30s

  n8n:
    image: n8nio/n8n:latest
    container_name: n8n-app
    restart: unless-stopped
    user: "1000:1000"
    env_file:
      - .env
    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: 60s

volumes:
  n8n_data:
  postgres_data:

This setup is designed to ensure PostgreSQL is ready before n8n starts, avoiding connection issues during initialization.

Configure PostgreSQL for n8n

In the provided docker-compose.yml file, PostgreSQL is set up with features suitable for production. Persistent storage is enabled through the postgres_data volume, ensuring that workflows, execution logs, and credentials remain intact across container restarts or updates.

The DB_POSTGRESDB_HOST=postgres environment variable directs n8n to communicate with PostgreSQL using Docker Compose’s internal network. Additionally, running n8n as a non-root user (user: "1000:1000") enhances security and avoids permission issues with mounted volumes.

Start and Verify the Deployment

Run the following command to launch the containers:

docker compose up -d

Check the status of the containers:

docker compose ps

If any container appears “unhealthy” or keeps restarting, inspect the logs:

docker compose logs -f postgres
docker compose logs -f n8n

PostgreSQL logs should confirm successful database initialization, while n8n logs should indicate a successful database connection and migration with messages like “Database migration completed” and “n8n ready on 0.0.0.0, port 5678.”

Once everything is running, head to https://n8n.yourdomain.com in your browser. During the initial setup, you’ll be prompted to create an owner account: that account is n8n’s login. There is no basic-auth variable to set: since version 1.0, n8n makes user management mandatory and no longer supports BasicAuth (see the n8n 1.0 migration guide), so older guides that add N8N_BASIC_AUTH_* lines to .env no longer protect anything.

Test PostgreSQL Integration

To confirm PostgreSQL is working, create a simple workflow in the n8n interface. For example, use a “Schedule Trigger” or “Manual Trigger” node, save the workflow, and execute it. Then restart the n8n container:

docker compose restart n8n

After the restart, log back into n8n and verify that your test workflow and its execution history are still present. This confirms that PostgreSQL is correctly handling data persistence.

With this setup, your workflows and their execution history live in PostgreSQL on a persistent volume, so they survive container updates and restarts. If execution volume outgrows a single instance later, n8n’s queue mode adds Redis and separate worker processes.

Step 4: Secure, Back Up, and Maintain Your Deployment

Once your deployment is up and running, the next step is ensuring it’s safe, reliable, and ready for long-term use. Here’s how to strengthen your setup and keep it running smoothly.

Strengthen Security for Production

Start by managing credentials carefully. Go beyond the basics – like the authentication credentials in your .env file – and make adjustments to harden security. For instance, change your VPS’s default SSH port from 22 to a custom port, such as 2222. This small tweak can significantly reduce the likelihood of automated brute-force attacks.

Use UFW (Uncomplicated Firewall) to permit only the services you need. For added control, restrict administrative access to specific IPs, especially if your team works from known locations. Here’s an example:

sudo ufw allow from YOUR_OFFICE_IP to any port 2222  # Custom SSH port
sudo ufw allow from YOUR_OFFICE_IP to any port 443   # HTTPS for n8n
sudo ufw deny 5678/tcp   # Block direct access to n8n port
sudo ufw enable

Using webhooks? Services such as Stripe, GitHub or a form tool call your n8n webhooks from their own servers, not from YOUR_OFFICE_IP, so the office-only rule on port 443 would block them. In that case open HTTPS to everyone (sudo ufw allow 443/tcp), keep SSH restricted to your IP, and rely on the n8n owner login to protect the editor.

This setup ensures that n8n is only accessible via HTTPS. Keep in mind that ports published by Docker bypass UFW rules, which is why the docker-compose.yml above binds n8n to 127.0.0.1 only: Nginx (or Cloudflare Tunnel) stays the single way in. To further secure your environment, put a DDoS-filtering layer in front of the server (the Cloudflare Tunnel option above is one way to do it), so malicious traffic is dropped before it can reach n8n.

Make it a habit to rotate encryption keys and passwords every 90 days. For example, the N8N_ENCRYPTION_KEY in your .env file secures stored credentials in your workflows. You can generate a new 32-character random key with:

openssl rand -base64 32

Set Up Backups to Protect Your Data

Daily backups are critical to safeguarding your data. Back up both your PostgreSQL database and n8n data regularly, and store these backups externally. Here’s a sample script:

#!/bin/bash
BACKUP_DIR="/opt/backups"
DATE=$(date +%Y%m%d_%H%M%S)
cd /opt/n8n

# Create backup directory
mkdir -p $BACKUP_DIR

# Backup PostgreSQL database
docker compose exec -T postgres pg_dump -U n8n n8n > $BACKUP_DIR/n8n_db_$DATE.sql

# Backup n8n data volume
docker run --rm -v n8n_n8n_data:/data -v $BACKUP_DIR:/backup alpine tar czf /backup/n8n_data_$DATE.tar.gz -C /data .

# Upload to external storage (example with AWS S3)
aws s3 cp $BACKUP_DIR/n8n_db_$DATE.sql s3://your-backup-bucket/n8n/
aws s3 cp $BACKUP_DIR/n8n_data_$DATE.tar.gz s3://your-backup-bucket/n8n/

# Clean up local backups older than 7 days
find $BACKUP_DIR -name "n8n_*" -mtime +7 -delete

Schedule this script to run daily at 2:00 AM with cron:

0 2 * * * /opt/n8n/backup.sh

Store these backups on a cloud service like AWS S3, Google Cloud Storage, or even a secondary VPS. This setup ensures you can quickly restore your deployment if something goes wrong.

To ensure your backups work when needed, test restoring them monthly. Use a staging environment to practice recovery. This step can save you from prolonged downtime during emergencies.

Routine Maintenance and Monitoring

Maintaining your deployment involves more than just security and backups. Regular updates and monitoring are just as important. Automate system updates and Docker image pulls during low-traffic hours with a script like this:

#!/bin/bash
# Update system packages
sudo apt update && sudo apt upgrade -y

# Pull latest Docker images
cd /opt/n8n
docker compose pull

# Restart containers with new images
docker compose up -d

# Clean up unused Docker resources
docker system prune -f

Schedule this script to run monthly, preferably during a low-traffic period, such as Sunday nights at 3:00 AM if your users are primarily in the US.

For monitoring, use VPSus’s AlwaysOn Access along with external tools. AlwaysOn Access ensures you can manage your VPS even if the operating system becomes unresponsive. Pair this with services like UptimeRobot to monitor your n8n endpoint every five minutes. Set up alerts for:

  • HTTP response time (keep it under 2 seconds)
  • SSL certificate expiration (get notified 30 days before expiry)
  • Disk space usage (alert if usage exceeds 80%)
  • Memory consumption (flag PostgreSQL or n8n containers using over 1.5 GB of RAM)

Review security logs weekly to spot unusual activity. For example:

# Review firewall logs
sudo grep "UFW BLOCK" /var/log/ufw.log | tail -20

# Check n8n container logs for errors
docker compose logs n8n | grep -i error | tail -10

Every quarter, conduct a security audit. Review user accounts, update firewall rules, and rotate API keys for external services. Document any changes and keep an incident response plan handy, complete with team contact information and recovery steps.

Conclusion: Key Takeaways and Next Steps

You’ve set up a complete n8n automation platform on VPSus infrastructure, giving you total control over your workflows while ensuring the reliability and flexibility needed for demanding automation tasks. This setup combines the power of self-hosting with the enterprise-level features required for scaling and performance.

From provisioning your VPSus server to implementing advanced security and backup strategies, you’ve unlocked the key advantages of self-hosting. With a Docker-based n8n deployment, you can integrate with 400+ services and platforms, all while keeping your data securely under your management.

The KVM kernel isolation in your VPSus environment provides a solid base for handling advanced workflows. Features like AlwaysOn Access ensure you can manage your platform even during unexpected system challenges. This robust performance means your n8n instance can handle complex automation tasks without breaking a sweat, setting the stage for smooth scaling as your needs grow.

The containerized Docker setup is a game-changer for deployment and scaling. When it’s time to expand, upgrading your VPS plan is straightforward, with seamless migration and data retention making the process hassle-free.

Your focus on security – using encrypted HTTPS connections and strong configurations – has prepared your deployment for production use. Automated backups protect against data loss, and the monitoring setup ensures potential issues are caught early, keeping your workflows running smoothly. Together, these strategies transform your n8n platform into a reliable, mission-critical tool.

Looking ahead, consider enhancing your setup further. An upstream filtering layer in front of Nginx adds protection against external threats, while automated snapshots through the control panel provide additional recovery options. As your team expands, you can rely on 24/7 support to ensure expert help is always within reach.

Facebook
Twitter
LinkedIn

Table of Contents

Get started today

With VPS.US VPS Hosting you get all the features, tools

Image