June 2026
·4 min read
Deploy n8n to Linode with Docker and Nginx
A step-by-step guide to self-hosting n8n on a Linode VPS with Docker, an Nginx reverse proxy, and a free Let's Encrypt TLS certificate.
n8n is an open-source workflow automation tool — think Zapier, but self-hosted, free, and with no node limits. In this guide we'll deploy it on the cheapest Linode plan ($5/mo Nanode 1 GB) using Docker Compose, put it behind Nginx with a free TLS certificate, and make it survive reboots automatically.
Total cost: $5/month.
What we'll build
- Ubuntu 22.04 VPS on Linode (Nanode 1 GB)
- Docker + Docker Compose running n8n
- Nginx as a reverse proxy
- Free TLS via Let's Encrypt / Certbot
- Auto-restart on reboot
Prerequisites
- A Linode account — sign up at linode.com
- A domain or subdomain you control (e.g.
n8n.yourdomain.com) - SSH key pair on your local machine (
~/.ssh/id_rsa/id_rsa.pub)
Step 1 — Create a Nanode on Linode
The Nanode 1 GB is Linode's cheapest plan at $5/month — 1 vCPU, 1 GB RAM, 25 GB SSD. It's enough for personal automations and small teams.
- Log in to cloud.linode.com.
- Click Create → Linode.
- Choose these options:
| Setting | Value |
|---|---|
| Image | Ubuntu 22.04 LTS |
| Region | Closest to you |
| Plan | Shared CPU → Nanode 1 GB ($5/mo) |
| Linode Label | n8n-server |
| Root Password | Set a strong password |
| SSH Keys | Add your public key |
- Click Create Linode and wait about 60 seconds until the status shows Running.
- Copy the IPv4 address from the dashboard — you'll need it in every step.
Point your subdomain at the server now so DNS propagates while you work:
# Add this A record in your DNS provider / registrar
n8n.yourdomain.com A YOUR_LINODE_IPStep 2 — SSH into your server
ssh root@YOUR_LINODE_IPIf you added your SSH key during creation you'll log straight in. Otherwise use the root password you set.
Step 3 — Create a non-root user
Running everything as root is a security risk. Create a deploy user with sudo access.
adduser deploy
usermod -aG sudo deployCopy your SSH key to the new user so you can log in as deploy:
rsync --archive --chown=deploy:deploy ~/.ssh /home/deploySwitch to the new user:
su - deployStep 4 — Update the system and configure the firewall
sudo apt update && sudo apt upgrade -yEnable UFW and open only the ports we need:
sudo ufw allow OpenSSH
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw --force enable
sudo ufw statusExpected output:
To Action From
-- ------ ----
OpenSSH ALLOW Anywhere
80/tcp ALLOW Anywhere
443/tcp ALLOW AnywhereStep 5 — Install Docker and Docker Compose
# Install Docker via the official convenience script
curl -fsSL https://get.docker.com | sudo sh
# Add your user to the docker group (no sudo needed for docker commands)
sudo usermod -aG docker $USER
newgrp docker
# Verify both tools are present
docker --version
docker compose versionYou should see something like:
Docker version 26.1.3, build b72abbb
Docker Compose version v2.27.1Step 6 — Set up the n8n directory and environment file
Create a dedicated directory for n8n:
mkdir -p ~/n8n && cd ~/n8nCreate the environment file that Docker Compose will read. This keeps all secrets out of the Compose file itself.
nano ~/n8n/.envPaste the following — replace every CHANGE_THIS value before saving:
# Domain
N8N_HOST=n8n.yourdomain.com
WEBHOOK_URL=https://n8n.yourdomain.com/
# Basic auth — change these!
N8N_BASIC_AUTH_USER=admin
N8N_BASIC_AUTH_PASSWORD=CHANGE_THIS_STRONG_PASSWORD
# Encryption key — generate one: openssl rand -hex 32
N8N_ENCRYPTION_KEY=CHANGE_THIS_32_CHAR_HEX_KEY
# Timezone
GENERIC_TIMEZONE=Asia/Manila
TZ=Asia/ManilaTo generate the encryption key without leaving the terminal:
openssl rand -hex 32Copy the output and paste it as N8N_ENCRYPTION_KEY in the .env file.
Step 7 — Create the Docker Compose file
nano ~/n8n/docker-compose.ymlPaste this:
services:
n8n:
image: n8nio/n8n:latest
container_name: n8n
restart: unless-stopped
ports:
- "127.0.0.1:5678:5678"
environment:
- N8N_HOST=${N8N_HOST}
- N8N_PORT=5678
- N8N_PROTOCOL=https
- NODE_ENV=production
- WEBHOOK_URL=${WEBHOOK_URL}
- N8N_BASIC_AUTH_ACTIVE=true
- N8N_BASIC_AUTH_USER=${N8N_BASIC_AUTH_USER}
- N8N_BASIC_AUTH_PASSWORD=${N8N_BASIC_AUTH_PASSWORD}
- N8N_ENCRYPTION_KEY=${N8N_ENCRYPTION_KEY}
- GENERIC_TIMEZONE=${GENERIC_TIMEZONE}
- TZ=${TZ}
volumes:
- n8n_data:/home/node/.n8n
volumes:
n8n_data:Note the 127.0.0.1:5678:5678 binding — this exposes n8n only to localhost, not to
the open internet. Nginx (Step 8) handles all public traffic over HTTPS.
Start n8n:
cd ~/n8n
docker compose up -dCheck it's running:
docker compose ps
docker compose logs --tail 30Look for this line in the logs — it means n8n started successfully:
Editor is now accessible via: http://localhost:5678Step 8 — Install Nginx
sudo apt install -y nginxCreate a server block for n8n:
sudo nano /etc/nginx/sites-available/n8nPaste the following — replace n8n.yourdomain.com with your actual subdomain:
server {
listen 80;
server_name n8n.yourdomain.com;
location / {
proxy_pass http://127.0.0.1:5678;
proxy_http_version 1.1;
# WebSocket support — required for n8n's live editor
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_read_timeout 300s;
proxy_send_timeout 300s;
client_max_body_size 50m;
}
}Enable the site and reload Nginx:
sudo ln -s /etc/nginx/sites-available/n8n /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginxThe nginx -t command must print syntax is ok before you reload.
Step 9 — Add a free TLS certificate with Certbot
sudo apt install -y certbot python3-certbot-nginxObtain and install the certificate:
sudo certbot --nginx -d n8n.yourdomain.comCertbot will:
- Verify you own the domain (DNS must have propagated from Step 1)
- Issue a Let's Encrypt certificate
- Automatically rewrite your Nginx config to serve HTTPS
- Set up a cron job to renew the cert every 60 days
Test auto-renewal:
sudo certbot renew --dry-runIf the dry run passes, your certificate will renew automatically forever.
Step 10 — Verify the deployment
Open your browser and go to https://n8n.yourdomain.com. You should see the n8n login
screen. Log in with the N8N_BASIC_AUTH_USER and N8N_BASIC_AUTH_PASSWORD you set in
Step 6.
Test that webhooks work end-to-end:
- Click + New Workflow → add a Webhook node
- Set the method to GET and click Listen for test event
- Copy the test URL and run:
curl -u admin:YOUR_PASSWORD "https://n8n.yourdomain.com/webhook-test/YOUR_PATH"You should see Workflow was started in the n8n editor.
Step 11 — Enable auto-restart on reboot
Docker's restart: unless-stopped policy (set in the Compose file) handles this
automatically. Verify Docker itself starts on boot:
sudo systemctl enable docker
sudo systemctl status dockerTo confirm, reboot and check:
sudo reboot
# Wait ~30 seconds then SSH back in
ssh deploy@YOUR_LINODE_IP
docker psn8n should be listed as Up X seconds.
Upgrading n8n
Pull the latest image and recreate the container. Your data (workflows, credentials) are
stored in the n8n_data Docker volume and survive upgrades.
cd ~/n8n
docker compose pull
docker compose up -dTroubleshooting
502 Bad Gateway
n8n hasn't started yet or crashed. Check:
docker compose logs --tail 50Common cause: wrong N8N_ENCRYPTION_KEY format — it must be a hex string, not a
plaintext passphrase. Regenerate with openssl rand -hex 32.
Certbot fails: "Could not resolve host"
DNS hasn't propagated yet. Check propagation with:
dig n8n.yourdomain.com +shortIt should return your Linode IP. Wait 5–30 minutes and retry.
Webhook calls time out from external services
Confirm WEBHOOK_URL in .env ends with a trailing slash:
WEBHOOK_URL=https://n8n.yourdomain.com/Then recreate the container:
cd ~/n8n && docker compose up -d --force-recreateForgot the basic-auth password
Edit ~/n8n/.env, change N8N_BASIC_AUTH_PASSWORD, then:
cd ~/n8n && docker compose up -d --force-recreateYou now have a production-ready n8n instance running on the cheapest Linode plan for $5/month — fully encrypted, auto-restarting, and with persistent storage so no data is lost on upgrades or reboots.