What you'll need
Before you start, make sure you have everything from this list on hand:
- A credit card to rent a VPS (Visa/Mastercard, including cards issued in Ukraine)
- A domain — optional, but recommended for HTTPS. You can grab one on Namecheap from $6/year
- An SSH client: Terminal (macOS/Linux) or PuTTY (Windows). On Windows 10+ you can use the built-in OpenSSH
- 30 minutes of free time
That's fine. The whole guide is built on the copy-and-paste principle. Every command is explained. And if something breaks — there's an FAQ section at the end with the most common errors.
Choose and rent a VPS
A VPS (Virtual Private Server) is your own server in the cloud, running 24/7. That's where n8n will live. Here are the best options:
| Provider | From | Locations | Why it's good |
|---|---|---|---|
| Hetzner | €3.79/mo | Germany, Finland | Best price/performance ratio, built-in Firewall |
| DigitalOcean | $4/mo | Amsterdam, Frankfurt | Simple interface, tons of tutorials |
| Contabo | €4.50/mo | Germany | More resources for the same money |
HAIQ's pick: Hetzner Cloud, plan CX22 — 2 vCPU, 4 GB RAM, 40 GB NVMe for €5.18/mo. Enough for dozens of active workflows.
How to create a server on Hetzner
Sign up at hetzner.cloud, create a new project, and click "Add Server". Pick: region — Falkenstein or Helsinki (closest to Ukraine), OS — Ubuntu 24.04, plan — CX22 or at least CX11 (2 GB RAM). In the SSH Keys section, add your public key (otherwise a password will be emailed to you).
1 vCPU and 1 GB RAM is the minimum for light workflows (up to 10 active). For production with AI nodes and PostgreSQL, go with 2 vCPU and 4 GB RAM. n8n with AI agents eats more memory.
Connect to your server via SSH
Once the server is created, you'll get an IP address (something like 65.108.xx.xx). Open your terminal and connect:
ssh root@65.108.xx.xx
On the first connection, the system will ask "Are you sure you want to continue connecting?" — type yes. Then enter the password (or the connection will happen automatically if you added an SSH key).
First things first — update the system and install some base utilities:
# Update packages
apt update && apt upgrade -y
# Install base utilities
apt install -y curl wget git nano ufw ca-certificates gnupg
Configure the firewall — allow only SSH, HTTP, and HTTPS:
ufw allow 22/tcp # SSH
ufw allow 80/tcp # HTTP
ufw allow 443/tcp # HTTPS
ufw enable
Install Docker
Docker is a tool that lets you run applications in isolated containers. Think of it as a "box" where n8n lives with all its dependencies. You can install it with a single command:
# Install Docker with a single script
curl -fsSL https://get.docker.com | sh
# Verify Docker is working
docker --version
# Should print something like: Docker version 27.x.x
# Verify Docker Compose (already included)
docker compose version
# Docker Compose version v2.x.x
Docker Compose ships inside modern Docker versions — you don't need to install it separately. If docker compose version works, you're good.
Deploy n8n with PostgreSQL
Now we'll create the configuration for n8n. We'll use PostgreSQL instead of the default SQLite, because PostgreSQL handles load better and is more reliable in production.
Create the working directory and folders for data:
# Create the folder for n8n
mkdir -p ~/n8n && cd ~/n8n
# Create data folders
mkdir -p n8n_data postgres_data
# Set the correct permissions for n8n
chown -R 1000:1000 n8n_data
Create the environment variables file at ~/n8n/.env:
# === n8n Configuration ===
N8N_HOST=n8n.yourdomain.com
N8N_PORT=5678
N8N_PROTOCOL=https
WEBHOOK_URL=https://n8n.yourdomain.com/
GENERIC_TIMEZONE=Europe/Kyiv
# Encryption key (SAVE THIS! Without it you can't restore credentials)
# Generate with: openssl rand -hex 16
N8N_ENCRYPTION_KEY=your_32_char_key_here
# === PostgreSQL ===
DB_TYPE=postgresdb
DB_POSTGRESDB_HOST=postgres
DB_POSTGRESDB_PORT=5432
DB_POSTGRESDB_DATABASE=n8n
DB_POSTGRESDB_USER=n8n
DB_POSTGRESDB_PASSWORD=your_strong_db_password
# Disable telemetry (optional)
N8N_DIAGNOSTICS_ENABLED=false
Save your N8N_ENCRYPTION_KEY somewhere safe (password manager, a note on your phone). If you lose this key — every saved credential (API keys, passwords) becomes unreadable, and you'll have to re-enter them all.
Generate an encryption key:
openssl rand -hex 16
# Copy the result into your .env file
Now create the main file — ~/n8n/docker-compose.yml:
services:
postgres:
image: postgres:16
container_name: n8n_postgres
restart: unless-stopped
environment:
POSTGRES_USER: n8n
POSTGRES_PASSWORD: ${DB_POSTGRESDB_PASSWORD}
POSTGRES_DB: n8n
volumes:
- ./postgres_data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U n8n"]
interval: 10s
timeout: 5s
retries: 5
n8n:
image: docker.n8n.io/n8nio/n8n
container_name: n8n
restart: unless-stopped
ports:
- "5678:5678"
env_file:
- .env
depends_on:
postgres:
condition: service_healthy
volumes:
- ./n8n_data:/home/node/.n8n
Start the containers:
# Start containers in the background
docker compose up -d
# Check the status
docker compose ps
# Watch the n8n logs
docker compose logs -f n8n
# Look for the line: "n8n ready on 0.0.0.0, port 5678"
If you see "n8n ready on 0.0.0.0, port 5678" — congrats, n8n is running. For now it's reachable at http://your-ip:5678, but you'll want HTTPS for production.
Connect your own domain
To make n8n available at a clean address (like n8n.yourdomain.com), you need to create a DNS record.
Go to your domain's control panel (Namecheap, Cloudflare, GoDaddy — any registrar) and create an A record:
| Type | Name | Value | TTL |
|---|---|---|---|
| A | n8n | 65.108.xx.xx (your VPS IP) | 300 |
Wait 5–10 minutes for DNS to propagate. You can check with:
dig n8n.yourdomain.com
# Should return your server's IP
HTTPS via Let's Encrypt
HTTPS is required for n8n — without it, OAuth2 integrations (Google Sheets, Gmail, Slack), webhooks, and secure cookies won't work. We'll use Nginx as a reverse proxy plus Let's Encrypt for a free SSL certificate.
Install Nginx and Certbot:
apt install -y nginx certbot python3-certbot-nginx
Create the Nginx config at /etc/nginx/sites-available/n8n:
server {
server_name n8n.yourdomain.com;
location / {
proxy_pass http://localhost:5678;
proxy_http_version 1.1;
# WebSocket support (for the n8n 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;
# Increase the limit for large payloads
client_max_body_size 50m;
}
}
Activate the config and get the certificate:
# Enable the config
ln -s /etc/nginx/sites-available/n8n /etc/nginx/sites-enabled/
nginx -t # Check syntax
systemctl reload nginx
# Get the SSL certificate (replace email and domain)
certbot --nginx -d n8n.yourdomain.com \
--email your@email.com \
--agree-tos \
--non-interactive
Certbot will automatically fetch a certificate from Let's Encrypt, update the Nginx config for HTTPS, and set up automatic renewal every 90 days. n8n is now available at https://n8n.yourdomain.com.
Automated backups
Backups are your insurance. If anything goes wrong, you can restore every workflow and credential in a minute.
Create the backup script at ~/n8n/backup.sh:
#!/bin/bash
# Backup the n8n PostgreSQL database
BACKUP_DIR="/root/n8n/backups"
DATE=$(date +%Y%m%d_%H%M)
mkdir -p $BACKUP_DIR
# Database dump
docker exec n8n_postgres pg_dump -U n8n n8n \
| gzip > $BACKUP_DIR/n8n_db_$DATE.sql.gz
# Backup n8n data (encryption key, custom nodes)
tar -czf $BACKUP_DIR/n8n_data_$DATE.tar.gz \
-C /root/n8n n8n_data .env
# Delete backups older than 30 days
find $BACKUP_DIR -name "*.gz" -mtime +30 -delete
echo "Backup completed: $DATE"
Make the script executable and add it to cron — daily at 3:00 AM:
# Make the script executable
chmod +x ~/n8n/backup.sh
# Add to cron (daily at 3:00 AM)
(crontab -l 2>/dev/null; echo "0 3 * * * /root/n8n/backup.sh") | crontab -
# Verify the cron job was added
crontab -l
Verify everything works
Open https://n8n.yourdomain.com in your browser. You'll see a registration screen — create an account (this is your local account on your own server, not tied to n8n cloud).
Once logged in, run through this quick check:
- Create a test workflow: add a Manual Trigger → Set Node → change some data → hit Execute
- Test a webhook: create a Webhook Trigger, copy the URL, open it in a new tab — you should get a response
- Check the timezone: add a Schedule Trigger and make sure the time matches Europe/Kyiv
- Activate the free license: Settings → Community — click Activate (unlocks additional features)
Your n8n is ready to work. You can now build workflows, wire up Telegram bots, set up automated order processing — and everything else covered in our previous article.
How to update n8n
n8n ships updates regularly — new nodes, AI features, fixes. Updating is trivial:
cd ~/n8n
# Pull the new version and restart
docker compose pull
docker compose up -d
# Check the version
docker compose logs n8n | head -5
Always run a backup first: bash ~/n8n/backup.sh. In rare cases, a new release can ship breaking changes.
Frequently asked questions
How much does a VPS for n8n cost?
From $3–5/mo for light workflows (Hetzner CX11, DigitalOcean Basic). For production with AI and PostgreSQL, we recommend $5–12/mo (2 vCPU, 4 GB RAM). Self-hosted n8n Community Edition is completely free — you only pay for the server.
Do I need to know how to code?
No. The whole install is copy-pasting commands from this guide. And n8n itself is a visual builder — you connect blocks with your mouse, no code required.
Why is HTTPS required?
Without HTTPS, OAuth2 integrations (Google Sheets, Gmail, Slack), external webhooks, and secure cookies won't work. In practice, n8n without HTTPS is only good for local development, not production.
What if n8n doesn't start?
Check the logs: docker compose logs n8n. The most common errors: wrong PostgreSQL password (compare .env and docker-compose.yml), port 5678 is used by another process, or wrong permissions on the n8n_data folder (fix with: chown -R 1000:1000 n8n_data).
How do I migrate n8n to another server?
Copy three things to the new server: the .env file with the same N8N_ENCRYPTION_KEY, the postgres_data folder, and the n8n_data folder. Run docker compose up -d — everything will work as before.