Zapier and Make are great until your workflow bill grows faster than your business. n8n is the open-source alternative you run on your own server: unlimited workflows, no per-execution pricing, and your data never leaves your infrastructure. This guide installs n8n on Ubuntu 24.04 using Docker Compose, secures it behind Nginx with free HTTPS, and covers upgrades, backups, and the errors you will actually hit.
By the end you will have n8n running at https://automate.yourdomain.com, auto-starting on boot, with an encrypted database and a safe upgrade path. Total time: about 30 minutes.
Prerequisites
- A server running Ubuntu 24.04 (22.04 works too) with at least 2 GB RAM and 20 GB disk. A $6–12/month VPS is plenty.
- A user with sudo privileges. Do not run everything as root.
- A domain or subdomain (for example
automate.yourdomain.com) with an A record pointing at your server's IP — needed only for the HTTPS step. n8n works on the raw IP if you skip it. - Basic comfort with the Linux terminal.
Step 1 — Update the system
sudo apt update && sudo apt upgrade -y
This refreshes the package lists and installs pending security updates. A clean, patched base avoids a surprising number of install failures later.
Step 2 — Install Docker the official way
n8n ships as an official Docker image, and Docker Compose is the cleanest way to run it. Install from Docker's own repository so you get current versions, not Ubuntu's stale ones:
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
The first block adds Docker's GPG key and repository; the second installs the engine plus the Compose plugin. Verify both work:
sudo docker --version
sudo docker compose version
Optionally let your user run Docker without sudo, then re-login:
sudo usermod -aG docker $USER
Step 3 — Create the n8n directories
mkdir -p ~/n8n && cd ~/n8n
Everything for n8n lives in one folder: the Compose file, the database, and file storage. Keeping it in your home directory (not /root) means your backup script and your non-root user both work without drama.
Step 4 — Write the docker-compose.yml file
n8n needs a persistent volume for its SQLite database (it stores workflows, credentials, and execution history) and a few environment variables. First, generate a random encryption key — n8n uses it to encrypt credentials stored in the database:
openssl rand -hex 32
Save that output somewhere safe; losing it means losing access to every credential stored in n8n. Now create docker-compose.yml:
nano docker-compose.yml
services:
n8n:
image: docker.n8n.io/n8nio/n8n:latest
container_name: n8n
restart: unless-stopped
ports:
- "5678:5678"
environment:
- N8N_HOST=${SUBDOMAIN:-localhost}
- N8N_PORT=5678
- N8N_PROTOCOL=https
- WEBHOOK_URL=https://${SUBDOMAIN:-localhost}/
- GENERIC_TIMEZONE=Asia/Kolkata
- N8N_ENCRYPTION_KEY=PASTE_YOUR_KEY_HERE
- N8N_BASIC_AUTH_ACTIVE=true
- N8N_BASIC_AUTH_USER=admin
- N8N_BASIC_AUTH_PASSWORD=CHOOSE_A_STRONG_PASSWORD
volumes:
- n8n_data:/home/node/.n8n
volumes:
n8n_data:
What this does:
restart: unless-stopped— n8n comes back automatically after a reboot or a crash.n8n_data— a named Docker volume holding the SQLite database, so destroying the container never deletes your workflows.N8N_ENCRYPTION_KEY— encrypts credentials at rest. Replace with your generated key.N8N_BASIC_AUTH_*— a login gate in front of n8n until you finish setup and create a real owner account.WEBHOOK_URL— tells n8n its public address so webhook URLs it generates are correct. SetSUBDOMAINin a.envfile, or hardcode your domain here.
Security note: the official n8n docs now recommend the instance owner's account over basic auth, but basic auth is still the simplest reliable gate for a fresh install. Create the owner account in the UI right after first login, then remove the basic-auth lines.
Step 5 — Start n8n
cd ~/n8n && docker compose up -d
The -d flag runs the container in the background. Docker pulls the image on first run, which takes a minute or two. Watch the logs to confirm a clean start:
docker compose logs -f n8n
You are looking for Editor is now accessible via without error traces after it. Press Ctrl+C to exit the log view — the container keeps running.
Step 6 — Verify it worked
Check that the process is listening and answering:
curl -s -o /dev/null -w "%{http_code}" http://localhost:5678
A 200 means n8n is up. Now open http://YOUR_SERVER_IP:5678 in a browser, enter the basic-auth credentials, and complete the owner-account setup (name, email, password). You should land on the empty workflow canvas.
Create a quick test workflow to prove execution works end to end: add a Schedule Trigger node set to every minute, connect a Set node that sets hello to world, and hit Test workflow. Green checkmarks mean executions run.
Step 7 — Put it behind Nginx with free HTTPS
Exposing port 5678 directly is fine for testing, but production n8n belongs behind a reverse proxy with HTTPS — webhooks and OAuth credentials break on plain HTTP. Install Nginx and Certbot:
sudo apt install -y nginx certbot python3-certbot-nginx
Create the site config (replace automate.yourdomain.com with your domain):
sudo nano /etc/nginx/sites-available/n8n
server {
listen 80;
server_name automate.yourdomain.com;
location / {
proxy_pass http://127.0.0.1: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_read_timeout 300;
proxy_connect_timeout 300;
proxy_send_timeout 300;
}
}
The Upgrade/Connection headers matter — n8n's editor uses WebSockets, and without them the UI loads but live updates silently break. Enable the site and get the certificate:
sudo ln -s /etc/nginx/sites-available/n8n /etc/nginx/sites-enabled/
sudo nginx -t && sudo systemctl reload nginx
sudo certbot --nginx -d automate.yourdomain.com
Certbot edits the config to add TLS and sets up auto-renewal. Now tighten the Compose file: set N8N_HOST=automate.yourdomain.com (or your .env SUBDOMAIN), keep N8N_PROTOCOL=https, and remove the ports: section so n8n is only reachable through Nginx:
cd ~/n8n && docker compose up -d
Visit https://automate.yourdomain.com — padlock in the address bar, owner login, done.
Step 8 — Back up before you forget
Your workflows live in the n8n_data Docker volume. Back it up with a simple archive:
docker run --rm -v n8n_data:/data -v ~/n8n:/backup ubuntu tar czf /backup/n8n-backup-$(date +%F).tar.gz -C /data .
This spins up a throwaway Ubuntu container that mounts the volume and writes a dated tarball into ~/n8n. Keep the encryption key from Step 4 in a password manager — a backup without its key is useless. Schedule this with cron weekly and copy the tarball off the server.
Step 9 — Upgrade safely
n8n releases weekly; breaking changes happen. The safe upgrade pattern: backup, pull, recreate.
cd ~/n8n
docker compose pull
docker compose up -d
docker image prune -f
After upgrading, open the UI and run one manual execution of your most important workflow. If something broke, the n8n changelog flags breaking changes per version — roll back by pinning the previous image tag in the Compose file and running docker compose up -d again.
Common issues and fixes
"port 5678 is already in use"
Something else grabbed the port. Find it with sudo ss -tlnp | grep 5678 and stop it, or change the host-side port in the Compose file to "8080:5678" (left side is your server's port, right side is n8n's).
"docker: permission denied"
Your user is not in the docker group yet — you ran usermod -aG docker $USER but did not log out and back in. Either re-login or run Compose with sudo until you do.
Editor loads but shows connection errors / blank nodes
Almost always missing WebSocket proxy headers in Nginx. Re-check that proxy_set_header Upgrade and Connection "upgrade" are present in your location block, then sudo nginx -t && sudo systemctl reload nginx.
Webhook URLs show localhost instead of your domain
WEBHOOK_URL was not set when the container started. Update the Compose file (or .env), then docker compose up -d to recreate the container with the corrected value.
"Credentials could not be decrypted"
The encryption key changed between container recreations — usually because it was generated inline instead of being fixed in the Compose file. Restore the original key from your password manager. There is no recovery without it.
Conclusion
You now have a self-hosted automation platform with no per-run pricing: Docker Compose keeps n8n running and auto-starting, Nginx plus Let's Encrypt gives you a proper HTTPS domain, and a weekly volume backup keeps your workflows safe. From here, explore the template library — most common integrations (Gmail, Sheets, Slack, Telegram) work without writing code.
Need n8n, Docker, or a full automation stack set up on your own servers? XpertBees designs, deploys, and maintains self-hosted infrastructure for businesses — get in touch and we will take it from here.



