What n8n needs from a VPS before Docker
n8n is a Node application inside a container, so the server only has to run Docker well. Two gigabytes of RAM is the practical floor for a handful of workflows; four gigabytes is the comfortable figure once you keep execution history and a Postgres database on the same box.
| Resource | Minimum | Comfortable | Why it moves |
|---|---|---|---|
| RAM | 2 GB | 4 GB and up | Node, the database, and execution data share memory |
| vCPU | 1 | 2 or more | Code and HTTP Request nodes are the heavy ones |
| Disk | 20 GB | 40 GB SSD | Execution history grows with every run |
| OS | Ubuntu 22.04 | Ubuntu 24.04 LTS | Docker's install script supports both |
| DNS | one A record | A record plus a subdomain for staging | Webhooks need a stable public hostname |
The DNS record matters more than people expect. n8n builds the webhook URLs it registers from the hostname and protocol you give it, so a wrong A record produces workflows that save correctly and never fire. Point the record at the server before you start the container.
Install Docker and open only three ports
Connect over SSH and install Docker from its official script rather than the distribution package, because the compose plugin ships with it. Then keep 5678 off the public interface entirely.
- Run
ssh root@your-server-ip, thensudo apt update && sudo apt upgrade -y. - Run
curl -fsSL https://get.docker.com | sudo sh, then check both tools withdocker --versionanddocker compose version. - Allow SSH, HTTP, and HTTPS only:
sudo ufw allow 22/tcp,sudo ufw allow 80/tcp,sudo ufw allow 443/tcp, thensudo ufw enable. - Confirm 5678 is not open with
sudo ufw status. The editor will be reached through Nginx, never directly.
You know this step worked when docker compose version prints a v2 release and ufw status lists three rules. If compose is missing, the older docker-compose binary is a different tool and the file below will not run.
Write the compose file that survives updates
Create /opt/n8n/docker-compose.yml. The three lines that decide whether the install lasts are the named volume, the restart policy, and a fixed encryption key. Everything else is preference.
image: n8nio/n8nwith a tagged release rather thanlatest, so an update is a decision you make.restart: unless-stoppedso the editor returns after a reboot without you logging in.ports: "127.0.0.1:5678:5678"binds the container to the loopback address, which is what lets Nginx own the public port.volumes: n8n_data:/home/node/.n8nkeeps workflows, credentials, and the SQLite database outside the container.N8N_ENCRYPTION_KEYset to a long random string you store somewhere else. Without it, a restored backup cannot decrypt saved credentials.WEBHOOK_URLandN8N_HOSTset to your https hostname, andGENERIC_TIMEZONE=for Indian schedules.Asia/Kolkata
Start it with docker compose up -d from that folder, then read docker compose logs -f n8n until the editor reports it is ready. Open http://127.0.0.1:5678 from an SSH tunnel to confirm the container answers before you involve Nginx.
Put Nginx and a certificate in front of 5678
The editor needs a real hostname and TLS, because most services that call your webhooks refuse plain HTTP. Install Nginx, add a server block that proxies to the loopback port, then let certbot edit that block for you.
In the server block, keep proxy_set_header Host $host;, X-Real-IP, X-Forwarded-For, and X-Forwarded-Proto $scheme, plus the Upgrade and Connection "upgrade" pair so the editor's live updates work. Raise client_max_body_size if your workflows accept file uploads.
Run sudo certbot --nginx -d n8n.example.com, accept the redirect, then change N8N_PROTOCOL to https and WEBHOOK_URL to the https address in the compose file. Recreate the container with docker compose up -d. Reload the site: the padlock appears and the editor loads at your domain, which is the point where the install is genuinely finished.
Webhooks that return 404, and why
A webhook 404 on self-hosted n8n is almost never a firewall problem. Either the workflow is not active, or the URL n8n registered does not match the hostname in WEBHOOK_URL.
- Production URLs only exist while the workflow is active. The test URL works only while the editor is open and you are listening for it.
- Change
WEBHOOK_URLafter the container started and the old hostname stays in the database until you recreate the container. - Behind a proxy, a missing
X-Forwarded-Protomakes n8n think it is serving http and it registers http links. - Test from outside with
curl -i https://n8n.before blaming the calling service.example.com/ webhook/your- path
That last command settles most tickets: a 404 from curl is an n8n routing problem, while a timeout is DNS or the firewall. Email support@webji.services with the exact curl output if the server side is not yours to fix.
Back up and update without losing credentials
Back up the volume, not the container. docker run --rm -v n8n_data:/data -v $(pwd):/backup alpine tar czf /backup/n8n-data.tar.gz -C /data . produces one archive that restores into any host running the same key.
To update, change the image tag in the compose file and run docker compose pull then docker compose up -d. Read the release notes first when the major version changes, because node behaviour and environment variable names do change between majors. Keep the previous tag in a comment so a rollback is one edit.
Store N8N_ENCRYPTION_KEY with the backup archive. A volume restored without the matching key starts cleanly and shows every credential as unreadable, which looks like data loss and is not.
When 2 GB stops being enough
The first sign of undersizing is not a crash. It is executions queuing while the editor still loads, then the container being killed by the kernel out-of-memory handler and restarted by Docker. Check docker stats during a busy period and dmesg | grep -i oom after a restart.
Move to Postgres when several people use the instance or execution history matters, since SQLite locks under concurrent writes. Move to queue mode with Redis and a separate worker container when a single process cannot keep up. Both changes are compose edits, so a 2 GB box that outgrows itself can be resized and restarted rather than rebuilt.
A VPS from WebJi for n8n
We sell VPS servers sized for container workloads, with root access, your choice of Ubuntu, and no panel forced on top. Configurations are quoted by email at support@webji.services before you pay, because RAM and disk decide the price rather than a fixed sticker.
If you would rather not run Docker yourself, managed n8n hosting covers the install, the certificate, and updates. Support is 24/7 by email in Hindi and English, with an average first reply under 60 minutes.
Frequently Asked Questions
Can n8n run on a 2 GB VPS?
Yes, for a small number of workflows. n8n itself idles well under a gigabyte, but Node, SQLite, and execution history share the rest. Plan on 4 GB once you keep long execution history, add Postgres, or run several active workflows with large payloads.
What does the n8n docker-compose file need?
The image, a restart policy, a named volume mounted at /home/node/.n8n, a loopback port binding such as 127.0.0.1:5678:5678, and environment values for N8N_HOST, WEBHOOK_URL, N8N_PROTOCOL and N8N_ENCRYPTION_KEY. The volume and the encryption key are what make backups restorable.
How do I get HTTPS webhooks for self-hosted n8n?
Put Nginx in front of the container, proxy the hostname to 127.0.0.1:5678 with X-Forwarded-Proto set, run certbot --nginx for the domain, then set N8N_PROTOCOL=https and WEBHOOK_URL to the https address and recreate the container.
Why does my n8n webhook return 404?
Either the workflow is not active, so only the test URL exists while the editor listens, or WEBHOOK_URL does not match the hostname the caller used. Recreate the container after changing WEBHOOK_URL, then test with curl to see whether the fault is routing or DNS.
Where does n8n store workflows and credentials on a VPS?
In /home/node/.n8n inside the container, which maps to the named volume you mounted. That folder holds the database, the credential records, and the encryption key reference, so back up the volume and keep N8N_ENCRYPTION_KEY with it.
Should I install n8n with npm or Docker on a VPS?
Docker. The npm route needs a matching Node version on the host and manual service management, and n8n now treats npm installation as a development path. Docker Compose gives you a pinned release, a restart policy, and a volume that survives updates.

