Blog · WebJi® India

Install n8n on a VPS

Quick answer: Install n8n on a VPS with Docker Compose: run the official Docker script, write a compose file that mounts /home/node/.n8n as a volume, put Nginx in front of port 5678, and issue a certificate with certbot. You know it worked when the editor opens over https and a test webhook reaches it.
✓ In business since 2005✓ INR + GST billing✓ 24/7 Email Support — avg reply < 60 min
Modern data center corridor in India with rows of server racks under cool blue-white lighting — install n8n on vps

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.

ResourceMinimumComfortableWhy it moves
RAM2 GB4 GB and upNode, the database, and execution data share memory
vCPU12 or moreCode and HTTP Request nodes are the heavy ones
Disk20 GB40 GB SSDExecution history grows with every run
OSUbuntu 22.04Ubuntu 24.04 LTSDocker's install script supports both
DNSone A recordA record plus a subdomain for stagingWebhooks 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.

  1. Run ssh root@your-server-ip, then sudo apt update && sudo apt upgrade -y.
  2. Run curl -fsSL https://get.docker.com | sudo sh, then check both tools with docker --version and docker compose version.
  3. Allow SSH, HTTP, and HTTPS only: sudo ufw allow 22/tcp, sudo ufw allow 80/tcp, sudo ufw allow 443/tcp, then sudo ufw enable.
  4. 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/n8n with a tagged release rather than latest, so an update is a decision you make.
  • restart: unless-stopped so 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/.n8n keeps workflows, credentials, and the SQLite database outside the container.
  • N8N_ENCRYPTION_KEY set to a long random string you store somewhere else. Without it, a restored backup cannot decrypt saved credentials.
  • WEBHOOK_URL and N8N_HOST set to your https hostname, and GENERIC_TIMEZONE=Asia/Kolkata for Indian schedules.

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_URL after the container started and the old hostname stays in the database until you recreate the container.
  • Behind a proxy, a missing X-Forwarded-Proto makes n8n think it is serving http and it registers http links.
  • Test from outside with curl -i https://n8n.example.com/webhook/your-path before blaming the calling service.

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.

Need help with this?

WebJi® support does it for you — free. Talk to our Jaipur team →