How I Installed n8n on an Ubuntu VPS: A Complete Guide to Self-Hosting Your Automation Platform
Publication date: September 30, 2025
- #n8n
- #Ubuntu
- #DigitalOcean
As a developer always looking for ways to streamline workflows and automate repetitive tasks, I recently decided to self-host n8n on my own VPS. n8n is an incredible open-source workflow automation tool that rivals services like Zapier and Make, but with the massive advantage of complete data control and no subscription fees. In this comprehensive guide, I'll walk you through exactly how I set up n8n on a subdomain of my portfolio website, vks.gr, using an Ubuntu VPS from DigitalOcean. By the end of this tutorial, you'll have your own n8n instance running securely with HTTPS, ready to automate anything you can imagine.
Why I Chose to Self-Host n8n
Before diving into the technical setup, let me share why self-hosting n8n was a game-changer for me:
- Complete Data Privacy: All workflows and data stay on my server
- No Monthly Fees: One-time VPS cost instead of recurring SaaS subscriptions
- Unlimited Workflows: No restrictions on automation complexity or execution frequency
- Custom Integrations: Freedom to add any custom nodes or modify the source code
I specifically chose DigitalOcean for my VPS because they offer reliable performance, developer-friendly tools, and transparent pricing. Their droplets (VPS instances) are easy to set up, scale effortlessly, and come with a clean, intuitive control panel—perfect for running n8n and other self-hosted apps.
💡 Want to try DigitalOcean yourself? Use my referral link to get started! You’ll receive $200 in free credit over 60 days, and once you spend $25, I’ll earn $25 too—at no extra cost to you. There’s no limit to how much credit you can give or earn through referrals, so feel free to share the love!
Prerequisites
Before we begin, you'll need:
- A VPS running Ubuntu 22.04 or later (I recommend at least 2GB RAM)
- A domain name with DNS management access
- Basic familiarity with Linux command line
- SSH access to your server
- About 30 minutes of your time
Step 1: Initial Server Setup and Security
First, let's secure our fresh VPS. I started by logging into my Ubuntu server and creating a new user instead of using root:
ssh root@YOUR_SERVER_IP
adduser yourusername
usermod -aG sudo yourusername
Configure SSH Key Authentication
Security is paramount, so I immediately set up SSH key authentication. On your local machine, generate an SSH key if you don't have one:
ssh-keygen -t rsa -b 4096
cat ~/.ssh/id_rsa.pub
Copy the public key and add it to your server:
mkdir ~/.ssh
nano ~/.ssh/authorized_keys
# Paste your public key here
chmod 700 ~/.ssh
chmod 600 ~/.ssh/authorized_keys
Set Up UFW Firewall
Ubuntu's Uncomplicated Firewall (UFW) provides essential protection:
sudo apt update
sudo apt install ufw
sudo ufw allow ssh
sudo ufw allow http
sudo ufw allow https
sudo ufw enable
Install Fail2ban for Brute Force Protection
This crucial security tool prevents automated attacks:
sudo apt install fail2ban
sudo systemctl enable fail2ban
sudo systemctl start fail2ban
Step 2: Install Docker and Docker Compose
n8n runs beautifully in Docker, providing isolation and easy management. Here's how I installed Docker on Ubuntu:
# Update package index
sudo apt-get update
# Install prerequisites
sudo apt-get install ca-certificates curl
# Add Docker's official GPG key
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc
# Add Docker repository
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu \
$(. /etc/os-release && echo "${UBUNTU_CODENAME:-$VERSION_CODENAME}") stable" | \
sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
# Install Docker Engine and Docker Compose
sudo apt-get update
sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
# Add your user to docker group (allows running Docker without sudo)
sudo usermod -aG docker ${USER}
su - ${USER}
Verify the installation:
docker --version
docker compose version
Step 3: Set Up n8n with Docker Compose
Now for the exciting part—deploying n8n! I created a dedicated directory for the n8n configuration:
mkdir ~/n8n
cd ~/n8n
nano docker-compose.yml
Here's the production-ready Docker Compose configuration I use:
services:
postgres:
image: postgres:16
restart: always
environment:
POSTGRES_USER: n8n
POSTGRES_PASSWORD: your_secure_db_password_here
POSTGRES_DB: n8n
volumes:
- db_data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U n8n"]
interval: 10s
timeout: 5s
retries: 5
n8n:
image: n8nio/n8n:latest
restart: always
environment:
# 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_db_password_here
# Basic Authentication (initial setup)
N8N_BASIC_AUTH_ACTIVE: true
N8N_BASIC_AUTH_USER: admin
N8N_BASIC_AUTH_PASSWORD: your_secure_admin_password
# n8n Configuration
N8N_HOST: localhost
N8N_PORT: 5678
N8N_PROTOCOL: http
WEBHOOK_URL: http://localhost:5678/
# Execution Configuration
EXECUTIONS_PROCESS: main
N8N_METRICS: true
volumes:
- n8n_data:/home/node/.n8n
ports:
- "5678:5678"
depends_on:
postgres:
condition: service_healthy
volumes:
db_data:
n8n_data:
Important Security Notes:
- Replace
your_secure_db_password_here
with a strong password- Replace
your_secure_admin_password
with another strong password- Consider using environment variables or Docker secrets for production
Start n8n with:
docker compose up -d
You can now access n8n at http://YOUR_SERVER_IP:5678
!
Step 4: Configure Nginx as a Reverse Proxy
To serve n8n on a proper domain with HTTPS, I set up Nginx as a reverse proxy:
sudo apt install -y nginx
sudo systemctl start nginx
sudo systemctl enable nginx
Create the n8n site configuration:
sudo nano /etc/nginx/sites-available/n8n
Add this configuration (replace n8n.yourdomain.com
with your subdomain):
server {
listen 80;
server_name n8n.yourdomain.com www.n8n.yourdomain.com;
# Security headers
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header X-Content-Type-Options "nosniff" always;
location / {
proxy_pass http://localhost: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 (required for n8n)
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
# Timeout settings for long-running workflows
proxy_connect_timeout 300;
proxy_send_timeout 300;
proxy_read_timeout 300;
}
}
Enable the site:
sudo ln -s /etc/nginx/sites-available/n8n /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx
Step 5: Configure DNS
For my setup on n8n.vks.gr
, I added these DNS records through my domain registrar:
-
A Record for n8n subdomain: Name:
n8n
Type:A
Value:YOUR_SERVER_IP
TTL:60
-
A Record for www.n8n subdomain: Name:
www.n8n
Type:A
Value:YOUR_SERVER_IP
TTL:60
DNS propagation usually takes 5–30 minutes.
Step 6: Enable HTTPS with Let's Encrypt
Security is non-negotiable for any web application. I used Certbot to get free SSL certificates:
sudo apt install -y certbot python3-certbot-nginx
sudo certbot --nginx -d n8n.yourdomain.com -d www.n8n.yourdomain.com
Follow the prompts to:
- Enter your email address
- Agree to the terms of service
- Choose whether to redirect HTTP to HTTPS (recommended: yes)
After this, update your Nginx configuration for optimal HTTPS performance:
sudo nano /etc/nginx/sites-available/n8n
Here's the enhanced HTTPS configuration:
# Redirect non-www to www (HTTPS)
server {
listen 443 ssl http2;
server_name n8n.yourdomain.com;
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;
return 301 https://www.n8n.yourdomain.com$request_uri;
}
# Redirect HTTP to HTTPS
server {
listen 80;
server_name n8n.yourdomain.com www.n8n.yourdomain.com;
return 301 https://www.n8n.yourdomain.com$request_uri;
}
# Main server block (www HTTPS only)
server {
listen 443 ssl http2;
server_name www.n8n.yourdomain.com;
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 Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header X-Content-Type-Options "nosniff" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
location / {
proxy_pass http://localhost: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
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
# Extended timeouts for long workflows
proxy_connect_timeout 300;
proxy_send_timeout 300;
proxy_read_timeout 300;
# Buffer settings
proxy_buffering off;
proxy_request_buffering off;
}
}
Reload Nginx:
sudo nginx -t
sudo systemctl reload nginx
Step 7: Update n8n Environment for Production
Now that HTTPS is configured, update your n8n Docker Compose file to reflect the proper webhook URL:
cd ~/n8n
nano docker-compose.yml
Update these environment variables in the n8n service:
N8N_PROTOCOL: https
WEBHOOK_URL: https://www.n8n.yourdomain.com/
N8N_HOST: www.n8n.yourdomain.com
Restart n8n:
docker compose down
docker compose up -d
Step 8: First Login and Configuration
Navigate to https://www.n8n.yourdomain.com
and you'll see the n8n login screen. Use the credentials you set in the Docker Compose file.
On first login, n8n will guide you through:
- Creating your owner account
- Setting up your workspace
- Connecting to external services
Performance Optimization Tips
After running n8n for several months, here are my optimization recommendations:
1. Database Maintenance
Create a maintenance script for PostgreSQL:
nano ~/n8n/db-maintenance.sh
Add the following:
#!/bin/bash
docker exec n8n-postgres-1 psql -U n8n -d n8n -c "VACUUM ANALYZE;"
docker exec n8n-postgres-1 psql -U n8n -d n8n -c "REINDEX DATABASE n8n;"
Make it executable and add to crontab:
chmod +x ~/n8n/db-maintenance.sh
crontab -e
# Add: 0 3 * * 0 /home/yourusername/n8n/db-maintenance.sh
2. Log Rotation
Configure Docker log rotation in /etc/docker/daemon.json
:
{
"log-driver": "json-file",
"log-opts": {
"max-size": "10m",
"max-file": "3"
}
}
3. Monitoring
Set up basic monitoring with Docker stats:
docker stats --no-stream
Consider implementing Prometheus + Grafana for advanced monitoring.
Troubleshooting Common Issues
WebSocket Connection Failed
If you see WebSocket errors, ensure your Nginx configuration includes:
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
Workflows Not Executing
Check the Docker logs:
docker compose logs -f n8n
Common fixes:
- Increase memory limits if needed
- Verify webhook URL is correctly set
- Check firewall rules
SSL Certificate Renewal
Certbot should auto-renew, but you can test renewal with:
sudo certbot renew --dry-run
Security Best Practices
- Regular Updates: Keep n8n and all dependencies updated
docker compose pull docker compose up -d
- Backup Strategy: Implement regular backups
docker compose down tar -czf n8n-backup-$(date +%Y%m%d).tar.gz ~/n8n docker compose up -d
- API Key Management: Use n8n's credential management for API keys
- Network Isolation: Consider using Docker networks to isolate services
- Audit Logs: Enable n8n audit logs for compliance
Conclusion
Setting up n8n on my own VPS was one of the best infrastructure decisions I've made. Not only do I have complete control over my automation workflows, but I'm also saving significantly compared to SaaS alternatives. The setup process, while detailed, is straightforward enough for any developer comfortable with basic Linux administration.
The beauty of self-hosting is that I can create unlimited workflows without worrying about execution limits or monthly fees. If you're considering workflow automation for your projects, I highly recommend giving self-hosted n8n a try.
🚀 Ready to launch your own n8n instance? Get started on DigitalOcean using my referral link! You’ll get $200 in free credit, and I’ll earn $25 once you spend $25—helping me keep this guide free and up to date. Win-win!
Next Steps
Now that you have n8n running, explore:
- Connecting your favorite apps and services
- Creating your first automation workflow
- Setting up custom nodes for specific needs
- Implementing advanced features like error workflows
- Exploring the n8n community for workflow inspiration
Have questions or need help with your n8n setup? Feel free to reach out through my portfolio at vks.gr. Happy automating!
This guide is based on my personal experience setting up n8n for production use. Your specific requirements may vary, so always consider your security and performance needs when deploying any self-hosted solution.