VPS Tutorials
Set Up n8n Automation Workflows on a VPS (2026): A Self-Hosted Zapier Alternative
n8n is an open-source workflow automation tool you can install on your own VPS to replace Zapier. This article walks you through deploying n8n on a VPS with Docker Compose, configuring HTTPS, running your first automation workflow, and connecting DeepSeek AI for intelligent automation.

Honestly, the first time I used Zapier I thought it was really convenient — moving data between a few platforms without writing any code. But after using it for a while, something felt off — the free plan only gives you 100 tasks per month, and a bit more automation uses that up. Upgrade to a paid plan? Starter alone costs $29.99/month, and the team plan is even more expensive.
Then I discovered n8n, an open-source workflow automation tool. Functionally it's similar to Zapier and Make, but the core difference is: you can install it on your own VPS and run as many tasks as you want, with no execution limits.
This article walks you through deploying n8n on a VPS and running your first automation workflow from scratch.
First, a few core advantages of n8n:
No execution limits. Zapier's free plan gives 100 tasks/month, the Starter plan 750 tasks/month, and once you use them up you have to wait or pay more. n8n runs on your own server, so you can run as many as you want. I built an automation that syncs Shopify orders to Google Sheets every night at midnight — tens of thousands of records per month, at zero extra cost.
Your data stays in your hands. Zapier's data passes through their servers, and some companies with data compliance requirements don't dare use it. With n8n, all data stays on your VPS and never passes through a third party.
400+ integrations. n8n supports over 400 services, including the commonly used Slack, Google Sheets, GitHub, Notion, PostgreSQL, and Redis. It also supports Webhooks, so services without a native integration can still connect via API.
Easy to connect AI models. n8n has built-in nodes for OpenAI, Anthropic, and DeepSeek, so you can call large models directly inside your automation workflows.
The downsides, of course, exist too:
- You have to maintain it yourself. You manage the server yourself and troubleshoot problems yourself, unlike Zapier which works out of the box.
- No ready-made app marketplace. Zapier has ready-made templates shared by users; n8n workflows you have to build yourself.
- A slightly higher barrier to entry. You need basic Linux skills and Docker.
Overall, if you're a heavy automation user (thousands to tens of thousands of tasks per month), or you have data privacy requirements, self-hosting n8n is a far more cost-effective choice than Zapier.
n8n itself isn't heavy; it mainly depends on what type of workflows you want to run:
| Use case | Recommended configuration | Estimated monthly cost |
|---|---|---|
| Light use (a few simple workflows) | 1 core / 1GB RAM | $5-10/month |
| Medium use (with Webhooks + scheduled tasks) | 2 cores / 2GB RAM | $10-20/month |
| Heavy use (lots of Webhooks + AI integration) | 2 cores / 4GB RAM | $15-30/month |
My recommendation is to go straight for 2 cores, 2GB. n8n itself only uses a few hundred MB of RAM, but PostgreSQL and Redis also need memory, and if you want to run AI-related workflows (calling DeepSeek or OpenAI), the memory requirements will be higher.
As for the OS, Ubuntu 22.04 or 24.04 is recommended for peace of mind.
SSH into your VPS:
ssh root@你的VPS_IP
If Docker isn't installed on the system yet, run these lines:
# 更新系统
apt update && apt upgrade -y
# 安装 Docker
curl -fsSL https://get.docker.com -o get-docker.sh
sh get-docker.sh
# 验证安装
docker --version
docker compose version
Create a project directory:
mkdir -p /opt/n8n && cd /opt/n8n
Create a docker-compose.yml file:
services:
postgres:
image: postgres:16-alpine
restart: always
environment:
POSTGRES_USER: n8n
POSTGRES_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: n8nio/n8n:latest
restart: always
ports:
- "127.0.0.1:5678:5678"
environment:
N8N_HOST: your-domain.com
N8N_PORT: 5678
N8N_PROTOCOL: https
DB_TYPE: postgresdb
DB_POSTGRESDB_HOST: postgres
DB_POSTGRESDB_PORT: 5432
DB_POSTGRESDB_DATABASE: n8n
DB_POSTGRESDB_USER: n8n
DB_POSTGRESDB_PASSWORD: 改成你自己的密码
N8N_ENCRYPTION_KEY: 用下面命令生成的密钥
WEBHOOK_URL: https://your-domain.com
GENERIC_TIMEZONE: Asia/Shanghai
volumes:
- n8n_data:/home/node/.n8n
depends_on:
postgres:
condition: service_healthy
volumes:
postgres_data:
n8n_data:
A few things to note:
N8N_ENCRYPTION_KEYis critical. If you lose it, the credentials stored in the database can't be decrypted. Generate it with this command:
# 生成 32 位随机密钥
openssl rand -hex 32
Fill the output string into the N8N_ENCRYPTION_KEY position above.
-
The port is bound to
127.0.0.1:5678:5678, meaning n8n only listens locally and isn't directly exposed to the public internet. Later we'll use an Nginx reverse proxy with HTTPS. -
Fill in your domain for
N8N_HOSTandWEBHOOK_URL, otherwise Webhooks won't trigger.
Start it:
cd /opt/n8n
docker compose up -d
Wait a few dozen seconds, then check the logs:
docker compose logs -f n8n
Seeing n8n ready on 0.0.0.0:5678, URL: https://your-domain.com means it started successfully.
Caddy automatically requests and renews SSL certificates, which is much less hassle than Nginx.
# 安装 Caddy
apt install caddy
Create /etc/caddy/Caddyfile:
your-domain.com {
reverse_proxy 127.0.0.1:5678
}
Restart:
systemctl restart caddy
Done. Caddy will automatically request a Let's Encrypt certificate for you, with no manual intervention needed.
server {
listen 80;
server_name your-domain.com;
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl http2;
server_name your-domain.com;
ssl_certificate /etc/letsencrypt/live/your-domain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/your-domain.com/privkey.pem;
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_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Port $server_port;
proxy_buffering off;
proxy_request_buffering off;
}
}
Remember to request an SSL certificate (using certbot).
Visit https://your-domain.com in your browser; the first time it will ask you to create an admin account:
- Password
- Name
After logging in, it's recommended to change a few settings first (avatar in the top right → Settings):
- User Management: if multiple people use it, enable user management
- API: generate an API Token, used later for calling the announcement interface
- External Secrets: if you want to use secret management tools like Vault
Let's do the simplest example: after receiving a Webhook request, write the data to Google Sheets.
- Click the + button in the top right to create a new workflow
- Drag a Webhook node onto the canvas
- Choose the POST method
- Write any path, e.g.
webhook-test - Click "Listen for test event" to get the Webhook URL
- Drag a Google Sheets node
- First connect your Google account (requires OAuth authorization)
- Select the spreadsheet and worksheet
- Choose Append Row as the operation
- Connect the two nodes
- Click Execute Workflow to test
To test, send a POST request with curl:
curl -X POST https://your-domain.com/webhook/webhook-test \
-H "Content-Type: application/json" \
-d '{"name": "测试订单", "amount": 99.99}'
If configured correctly, the data will be written to Google Sheets automatically.
Production environment note: after testing passes, remember to enable the workflow's Production URL and Production Version. Webhooks have two modes; development mode and production mode are separate.
n8n has officially supported the DeepSeek node since version 1.40. If you want your workflows to have AI capabilities, such as auto-replying to emails, summarizing articles, or classifying tickets, you can call the DeepSeek API directly in your workflows.
First get a DeepSeek API Key (register at platform.deepseek.com, top up a few dollars — API calls are very cheap).
Then in n8n:
- Add a DeepSeek node
- Fill in your API Key
- Choose a model (DeepSeek Chat or DeepSeek Reasoner)
- Write your instructions in the Prompt
For example: a workflow that auto-replies to tickets
Webhook(接收工单) → DeepSeek(生成回复) → Email(发送回复)
Every time someone submits a form, the Webhook passes the ticket content to DeepSeek, the AI generates a reply, and then an email is automatically sent to the customer. No human intervention needed throughout.
Running such a workflow on a VPS has no API call limits (you only pay DeepSeek's API fees, a few cents per ten thousand tokens), which is far more cost-effective than Zapier's AI features.
n8n updates very frequently, basically releasing several versions a month. Updating is simple:
cd /opt/n8n
docker compose pull n8n
docker compose up -d n8n
n8n's data is stored in PostgreSQL, and workflow definitions are stored in the n8n_data volume. It's recommended to back up regularly:
# 备份 PostgreSQL
docker exec n8n-postgres-1 pg_dump -U n8n n8n > /backup/n8n-db-$(date +%Y%m%d).sql
# 备份 n8n 配置文件
tar czf /backup/n8n-config-$(date +%Y%m%d).tar.gz /opt/n8n/
My habit is to write a cron job that backs up once every night at midnight.
n8n comes with a built-in health check endpoint: https://your-domain.com/healthz; a 200 response means it's healthy. You can use UptimeRobot or just write a cron script to monitor it.
Webhooks don't receive requests
Check a few places: whether the Nginx/Caddy reverse proxy configuration is correct, whether the WEBHOOK_URL environment variable is set, and whether the firewall allows ports 80/443. Also, n8n's Webhook address needs the /webhook/ prefix.
N8N_ENCRYPTION_KEY is lost
Then it's a tragedy. All the passwords and API Keys stored in your workflows can't be decrypted. You must back up this key, in a password manager or a secure place.
PostgreSQL won't connect
Check the PostgreSQL configuration in docker-compose.yml, especially whether the password and database name are correct. Also note that PostgreSQL takes time to start; the n8n container has depends_on + healthcheck, but sometimes the first PostgreSQL startup initialization is slow, and you may need to manually restart the n8n container.
Not enough memory
Running n8n + PostgreSQL + Redis together, 1GB of RAM is indeed a bit tight. If your VPS doesn't have enough memory, you can shut down some unused services, or just upgrade to a 2GB configuration. You can also use docker stats to check resource usage.
Deploying n8n on a VPS is really just a matter of running a Docker Compose setup. But what you get in return is:
- Unlimited automation executions, no more counting Zapier quotas to get by
- Data completely in your own hands, no worries about third-party platform leaks
- Can connect AI models like DeepSeek, building your own AI automation workflows
- A few hundred dollars a month in self-hosting costs, far cheaper than Zapier's team plan
If you're a heavy automation user, or you're looking for an open-source alternative to Zapier, n8n is worth a try. And running n8n on a VPS doesn't require high specs; a cheap $5-10/month machine is enough, so you can start at basically zero cost.
If you have any questions, feel free to leave a comment.