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.
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 Name | CPU | RAM | NVMe Storage | Price (Per Month) | Best For |
|---|---|---|---|---|---|
| KVM1-US | 1 vCore | 1 GB | 20 GB | $10 | Testing/Light Use |
| KVM2-US | 2 vCores | 2 GB | 25 GB | $20 | Typical Workloads |
| KVM4-US | 4 vCores | 4 GB | 40 GB | $40 | Heavy 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 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.comto 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

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.