TürkiyeVPS

Installing n8n: Setting Up n8n on a VPS with Docker

A step-by-step guide to running your own n8n automation server: installing Docker Engine, the docker compose file, an Nginx reverse proxy, a free SSL certificate, updates and backups.

8 min read

n8n is an open-source tool that lets you connect apps and automate workflows. You build things like writing form submissions to a spreadsheet, sorting incoming emails, or sending a question to an AI model and forwarding the answer to Telegram, all with drag-and-drop nodes. When you run it on your own server instead of the cloud version, your data stays with you and you don't have to deal with limits such as the number of workflows.

In this guide we'll install n8n with Docker on a VPS running Ubuntu 24.04. Here's the setup we'll build:

  1. Docker Engine is installed from Docker's official package repository.
  2. n8n runs from a docker compose file and listens only on 127.0.0.1:5678, which is reachable only from inside the server.
  3. Nginx receives incoming requests from the outside and forwards them to n8n.
  4. Certbot enables HTTPS with a free Let's Encrypt certificate.

1. Prepare the server

Connect via SSH and update packages:

sudo apt update && sudo apt upgrade -y

If this is a new server, we recommend first applying the basic steps from our Linux server security guide (SSH keys, disabling root login, a firewall). Also create an A record in your DNS panel for the subdomain you'll use for n8n, for example n8n.ornek.com → your VPS's IP address. The record may take a few minutes to propagate.

2. Install Docker Engine

The docker.io package in the Ubuntu repositories works too, but for an up-to-date version and the docker compose plugin it's better to use Docker's own repository:

sudo apt install -y ca-certificates curl
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
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] 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

Check the installation:

sudo docker run --rm hello-world
docker compose version

If the hello-world container prints a welcome message and exits, Docker is ready.

You can add your user to the docker group to run commands without sudo (sudo usermod -aG docker $USER). In practice, however, that group is equivalent to root access; in this guide we stick with sudo.

3. Write the docker compose file

Create a folder for n8n and write the compose file into it:

sudo mkdir -p /opt/n8n
cd /opt/n8n
sudo nano compose.yaml

Its contents (replace the domain with your own):

services:
  n8n:
    image: docker.n8n.io/n8nio/n8n
    container_name: n8n
    restart: unless-stopped
    ports:
      - "127.0.0.1:5678:5678"
    environment:
      - N8N_HOST=n8n.ornek.com
      - N8N_PORT=5678
      - N8N_PROTOCOL=https
      - WEBHOOK_URL=https://n8n.ornek.com/
      - N8N_PROXY_HOPS=1
      - GENERIC_TIMEZONE=Europe/Istanbul
      - TZ=Europe/Istanbul
    volumes:
      - n8n_data:/home/node/.n8n

volumes:
  n8n_data:

What the settings mean:

  • 127.0.0.1:5678:5678: n8n is reachable only from inside the server. This matters because ports published by Docker can bypass UFW rules; if you wrote 5678:5678, n8n could end up exposed to the internet despite your firewall.
  • N8N_HOST and N8N_PROTOCOL: needed so n8n builds its own address correctly.
  • WEBHOOK_URL: the address that webhook and form nodes show to the outside world. If you don't set it behind a reverse proxy, webhook URLs appear with a useless value like http://localhost:5678.
  • N8N_PROXY_HOPS=1: tells n8n there's a reverse proxy in front of it, so the visitor's IP is read from the X-Forwarded-For header.
  • GENERIC_TIMEZONE: sets the time zone that Schedule nodes use. If you don't set it, your workflows trigger according to the default time zone rather than Turkish time.
  • The n8n_data volume: workflows, credentials, the SQLite database and the encryption key are stored in /home/node/.n8n. If this volume is lost, everything is lost.

About N8N_SECURE_COOKIE

By default, n8n sends its session cookie only over HTTPS. That's why, if you try to open n8n at an unencrypted address like http://IP:5678, you get a "secure cookie" warning and can't log in. Some guides suggest adding N8N_SECURE_COOKIE=false; this lets your password and session travel across the network in plain text. The right fix is to set up HTTPS with the steps below. Use this variable only for a short local test, and revert it afterwards.

Start n8n:

sudo docker compose up -d
sudo docker compose logs -f

Once you see the line in the logs saying n8n is ready, press Ctrl+C to stop following the logs; the container keeps running. The curl -I http://127.0.0.1:5678 command should return an HTTP response.

4. Set up a reverse proxy with Nginx

sudo apt install -y nginx
sudo nano /etc/nginx/sites-available/n8n
server {
    listen 80;
    server_name n8n.ornek.com;

    client_max_body_size 50M;

    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_buffering off;
        proxy_read_timeout 3600s;
    }
}

The Upgrade and Connection headers are for the websocket connection. The n8n editor uses this connection to push results to the browser while a workflow runs; if these lines are missing, the editor shows a "Connection lost" warning and the output of a running workflow never appears. proxy_read_timeout prevents long-running requests from being cut off.

Enable the site:

sudo ln -s /etc/nginx/sites-available/n8n /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx

5. Firewall and SSL

If you use UFW, allow only SSH and web traffic. There's no need to open port 5678:

sudo ufw allow OpenSSH
sudo ufw allow 'Nginx Full'
sudo ufw enable

Get a Let's Encrypt certificate:

sudo apt install -y certbot python3-certbot-nginx
sudo certbot --nginx -d n8n.ornek.com

Certbot adds the HTTPS settings to your Nginx file and sets up automatic renewal. You can now open https://n8n.ornek.com and create your first admin account. Do this right away: as long as the setup page is open, anyone who knows the address could create the owner account before you.

Updating n8n

n8n releases new versions frequently. To update, run these commands in the compose folder:

cd /opt/n8n
sudo docker compose pull
sudo docker compose up -d
sudo docker image prune -f

Because your data lives in the volume, recreating the container doesn't delete your workflows. Still, take a backup before major version upgrades and read the breaking changes section in n8n's release notes. If you want to stay on a specific version, you can add a tag to the image name, such as docker.n8n.io/n8nio/n8n:1.x.y.

Backups

The most important thing is the n8n_data volume. Docker compose prefixes the volume name with the folder name; to see the actual name:

sudo docker volume ls

If the folder is /opt/n8n, the name will most likely be n8n_n8n_data. For a consistent backup, stop n8n briefly and archive the volume:

cd /opt/n8n
sudo docker compose stop
sudo docker run --rm -v n8n_n8n_data:/data -v /opt/n8n:/backup alpine tar czf /backup/n8n-yedek-$(date +%F).tar.gz -C /data .
sudo docker compose start

Copy the archive off the server as well; a backup on the same disk is useless if the disk fails. The config file inside the volume holds n8n's encryption key. Saved credentials (API keys, passwords) are encrypted with this key; without it, you can't use the credentials even if you restore the backup.

If you also want to export your workflows as JSON:

sudo docker exec n8n n8n export:workflow --all --output=/home/node/.n8n/workflows.json

How much RAM do you need?

For a small number of simple workflows, n8n runs with at least 1 GB of RAM, but that's a borderline figure; memory can run short, especially when processing large JSON data or running several workflows at once. 2 GB or more is a comfortable starting point. If you handle large files, many concurrent executions or extra services on the same server such as a local AI model, plan for more. If you don't want to share resources with others, VDS plans offer more predictable performance.

If you'd rather not deal with the installation, take a look at our n8n & AI VPS plans: after payment, our team installs n8n, OpenWebUI, AI Agent or Cloudron on the server, whichever you choose, and hands it over ready to use. If you prefer to install it yourself, the steps in this guide work as-is on any TürkiyeVPS VPS with root access.

Frequently Asked Questions

Can I install n8n without Docker?

Yes, you can also install Node.js and run it with npm install -g n8n. But then you take care of Node.js version compatibility, updates and service management yourself. With Docker, updating takes two commands, and n8n itself recommends the Docker installation.

The editor shows a "Connection lost" warning. Why?

Usually the websocket headers are missing in Nginx. Check that the proxy_http_version 1.1, Upgrade and Connection "upgrade" lines are in the location block, then run sudo nginx -t and sudo systemctl reload nginx.

Webhook URLs show up as localhost. How do I fix it?

Set the WEBHOOK_URL value in the compose file to your domain, ending with /, and recreate the container with sudo docker compose up -d.

Is SQLite enough, or should I use PostgreSQL?

For personal use and small teams, the default SQLite is usually enough. If you keep a lot of execution history or plan to run n8n with multiple processes (queue mode), PostgreSQL is a better fit.

Does n8n start on its own after a server reboot?

Yes. The Docker service starts at boot, and thanks to the restart: unless-stopped setting in the compose file, the n8n container starts again automatically.