AI Automation

Self-Host n8n on an Ubuntu VPS with a Vietnam IPv4

When a cloud automation platform starts charging per execution, or when you need a webhook URL that stays fixed and trusted, self-hosting n8n on an Ubuntu 24.04 VPS is the move that most teams land on. You get the same visual workflow builder, full root access to the server, and a Linux VPS with a dedicated IPv4 in Vietnam, which matters a lot if your endpoints, partners, or clients are inside Vietnam. This guide walks through the install with Docker, the reverse proxy with automatic SSL, and the settings that keep the service stable under real workload.

Key takeaways

  • Docker and Docker Compose v2 are the fastest supported way to run n8n in production; the official image is docker.n8n.io/n8nio/n8n.
  • n8n stores workflow sources in its own database; by default it uses SQLite, and you can switch to PostgreSQL when the queue mode or multiple instances are needed.
  • Run the container behind an Nginx reverse proxy with a free Let's Encrypt certificate so your webhooks are only reachable over HTTPS.
  • A dedicated IPv4 gives you a stable webhook URL and a clean IP for outbound API calls, which matters for third-party integrations.

Why host n8n yourself instead of using the cloud version

The cloud tiers of n8n are priced per execution. A small team that automates a handful of internal tasks might stay within the free quota, but once you start polling APIs every few minutes or running webhook-driven flows for customers, the cost per 1,000 executions climbs fast and the limits start to bite. Self-hosting removes the execution cap entirely, you pay only for the VPS. On a 2 GB RAM instance you can comfortably run a few dozen active workflows; on 4 GB you can add a separate PostgreSQL container and run the queue mode.

The second reason is data control. With self-hosting, workflow definitions, credentials, and execution logs live on your own server. For a business operating in Vietnam, hosting that data on a VPS inside the country also aligns with local data residency expectations, something a US or EU cloud node does not offer. And because the VPS is a self-managed environment, you decide exactly when to upgrade n8n, which plugins to install, and how long to keep execution history.

Prerequisites

  • An Ubuntu 24.04 VPS with at least 2 GB RAM, 20 GB NVMe disk, and a dedicated IPv4. If you do not have one yet, you can rent a Linux VPS from a Vietnam provider and pick Ubuntu 24.04 as the OS.
  • Root access or a sudo user on the server.
  • A domain name pointing to the server IP, needed for the webhook URLs and HTTPS.
  • Basic familiarity with the command line and Docker.

自托管 n8n 可让你完全控制工作流数据和执行次数,不受云端限制。

Self-hosting n8n gives you full control over your workflow data and execution count, with no cloud-imposed limits.

Step 1 - Installing Docker and Docker Compose

Ubuntu 24.04 ships with Docker in its repositories, but the version can lag behind. Install the official Docker packages so you get the current engine and Docker Compose v2 as a single binary. The official install script is the fastest path, and it works cleanly on a fresh Ubuntu 24.04 box.

curl -fsSL https://get.docker.com | sh
systemctl enable --now docker
docker --version
docker compose version

The first command adds the Docker repository, installs the engine and the CLI, and enables the service. The last two commands confirm the install. You should see Docker version 27.x or newer and Docker Compose version v2.x. If the service is not running, start it manually and check the status.

systemctl status docker

The output should show active (running). If it does, Docker is ready and you can move to the project directory.

Step 2 - Creating the n8n project with Docker Compose

Create a dedicated directory for the n8n data and the compose file. Keeping the data directory separate from the container makes backups trivial and lets you upgrade n8n without touching your workflows.

mkdir -p /opt/n8n-data && cd /opt/n8n-data
nano docker-compose.yml

Paste the following configuration. It runs n8n with SQLite by default, which is fine for a single instance and a few dozen workflows. The N8N_HOST variable sets the public hostname, and the volume keeps all data persistent in /opt/n8n-data.

services:
  n8n:
    image: docker.n8n.io/n8nio/n8n
    restart: unless-stopped
    ports:
      - "127.0.0.1:5678:5678"
    environment:
      - N8N_HOST=n8n.example.com
      - N8N_PROTOCOL=https
      - N8N_PORT=5678
      - N8N_SECURE_COOKIE=false
      - GENERIC_TIMEZONE=Asia/Ho_Chi_Minh
    volumes:
      - /opt/n8n-data:/home/node/.n8n

Two details here matter. First, the port binds to 127.0.0.1 only. That keeps n8n unreachable from the public internet until Nginx is in front of it. Second, the timezone is set to Vietnam, which makes schedule-triggered workflows fire at the correct local time. If your workflows target another region, change it accordingly.

Step 3 - First launch and verifying n8n

Start the container in the background, then wait a few seconds for the first boot. The first run initializes the SQLite database and generates the encryption key, which can take a couple of minutes on a small VPS.

docker compose up -d
docker compose logs -f --tail=50

The log should end with a line about the editor being ready, typically Editor is now accessible via followed by a URL. Because the port is bound to localhost, you cannot open it in a browser yet. Verify it from inside the server first.

curl -I http://127.0.0.1:5678

An HTTP 200 response confirms n8n is running. Next you set up the reverse proxy so the web interface and the webhooks are reachable over HTTPS.

Step 4 - Setting up Nginx as a reverse proxy with SSL

Install Nginx and Certbot, then create a server block for the n8n domain. The proxy passes requests to the local n8n port and keeps the connection alive for long-running webhook calls.

apt update
apt install -y nginx certbot python3-certbot-nginx
nano /etc/nginx/sites-available/n8n

Use this server block. Replace n8n.example.com with your own domain.

server {
    listen 80;
    server_name n8n.example.com;

    location / {
        proxy_pass http://127.0.0.1:5678;
        proxy_http_version 1.1;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_read_timeout 3600;
    }
}

The Upgrade and Connection headers are required for the n8n webhook editor to work over the proxy, since the editor uses websockets. The long proxy_read_timeout prevents timeouts on workflows that run for more than a minute. Enable the site, test the config, and reload Nginx.

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

Now grab a free Let's Encrypt certificate with the Certbot Nginx plugin, which edits the config automatically and enables HTTPS.

certbot --nginx -d n8n.example.com

At the prompt choose to redirect HTTP to HTTPS. Allow the HTTPS port through the firewall if ufw is active, then verify the site from outside.

ufw allow 'Nginx Full'
curl -I https://n8n.example.com

An HTTP 301 to HTTPS or directly a 200 confirms the proxy and the certificate work. Open the domain in a browser and you should see the n8n setup screen asking you to create the admin account.

Why a dedicated IPv4 matters for self-hosted n8n

The n8n instance you just deployed runs on a server that has its own IPv4 address, not a shared NAT. That distinction matters more than most people expect. A dedicated IPv4 means outbound API calls come from one clean, stable address, which is how services like Telegram, Slack, or Shopify decide whether to trust your requests. It also means your webhook URLs stay fixed, no random port forwarding, no changing public IP on reboot.

For teams whose n8n instance talks to Vietnamese systems, a Vietnam VPS with a dedicated IPv4 puts the automation physically close to those services. Domestic bandwidth of 100 Mbps on a 1 Gbps port keeps webhook latency low when the target system is also in Vietnam. If the target is a local bank API, a government portal, or a domestic e-commerce platform, the Vietnam IP also avoids the geo-blocks that some local services apply to foreign addresses.

Securing the n8n instance beyond the default setup

The default n8n install has no authentication on the editor until you create an account on first access. Getting to that screen fast matters because an exposed editor without login is a public workflow executor. The reverse proxy step above already prevents random internet access until the domain is set up, and the first-run account creation closes the gap. Beyond that, set a strong admin password and enable two-factor authentication in the n8n settings if your workflows touch sensitive credentials.

On the server level, the essentials are the same as for any production box. Keep SSH on a non-default port or use key-only auth, and let ufw allow only 22, 80, and 443. Use snapshots before major n8n upgrades, since a bad migration can corrupt the database. And back up the /opt/n8n-data directory regularly, it contains your workflows, credentials, and execution history.

ufw allow 22/tcp
ufw allow 80/tcp
ufw allow 443/tcp
ufw enable

If you already hardened SSH, these three rules are enough. The n8n port 5678 stays closed to the public, which is exactly what you want.

Scaling n8n: from SQLite to PostgreSQL and queue mode

The SQLite setup works well for a single instance and moderate load, but it has a ceiling. When you hit hundreds of concurrent executions or want to run multiple n8n instances behind a load balancer, switch to PostgreSQL and enable the queue mode. Postgres allows concurrent reads and writes without the file-lock contention that SQLite suffers under parallel workload.

Move the compose file to a multi-container setup with a Postgres service, and point n8n to it using the DB_TYPE=postgresdb environment variables. The n8n docs document the exact variable names, and the change is contained to the compose file plus a docker compose up -d.

docker compose exec n8n n8n export:workflow --all --output=/backup/workflows.json
docker compose down
docker compose up -d

Before the switch, export your workflows from the SQLite-backed instance, as shown above. The export is plain JSON, and importing it back into a Postgres-backed instance preserves all nodes and connections. Credentials are encrypted with the same key, so they survive the move as long as the N8N_ENCRYPTION_KEY environment variable stays the same.

For most self-hosted deployments, Postgres is worth doing from day one even on small hardware. A 2 GB RAM VPS runs both n8n and Postgres without strain, and it removes the migration step later.

How much RAM does self-hosted n8n need

A quiet n8n instance with SQLite idles around 300 MB of RAM. Each active workflow adds a small overhead, and webhook-triggered executions spike memory during the run. On a 2 GB VPS you can run about 20 to 40 workflows comfortably, depending on how often they execute and how heavy the nodes are. Polling triggers every minute cost more than webhook triggers, which only wake on demand.

If you run n8n with Postgres in separate containers, budget an extra 300 MB for the database. At 4 GB RAM the headroom becomes comfortable: you stop thinking about memory and start adding workflows freely. That is the sweet spot for a production self-hosted instance that runs around the clock. If you are still sizing hardware, check our guide on RAM sizing for n8n workflows, which breaks down the numbers by workload type.

Troubleshooting common n8n on Docker issues

Three failures come up repeatedly. The first is the webhook URL showing http instead of https in the editor. That means the N8N_PROTOCOL environment variable is missing or the Nginx proxy headers are not passing X-Forwarded-Proto. Fix the environment variable and the proxy header, then restart the container.

The second is the container restarting in a loop. Check the logs for a database error or a permissions issue on the volume. The n8n container runs as user node with UID 1000, so the host directory must be readable by that UID.

chown -R 1000:1000 /opt/n8n-data
docker compose logs -f

The third is SSL certificate renewal failing. Certbot's timer is installed automatically, so renewal should be hands-off, but a misconfigured DNS record or a blocked port 80 stops the HTTP-01 challenge. Test renewal manually with certbot renew --dry-run and check the DNS A record for the domain.

FAQ

Is self-hosted n8n free?

n8n itself is free under the Sustainable Use License for self-hosted use. You pay only for the VPS that runs it, which removes the per-execution cost of the cloud version entirely.

Can I run n8n on a 2 GB RAM VPS?

Yes. A 2 GB RAM VPS runs n8n with SQLite and handles 20 to 40 active workflows. If you plan heavy usage or want Postgres and the queue mode, 4 GB RAM is the more comfortable choice.

Why use a dedicated IPv4 for n8n webhooks?

A dedicated IPv4 keeps your webhook URL stable and makes outbound API calls come from one trusted address. Third-party services are less likely to block or throttle a consistent IP, and Vietnamese services accept local IPs more readily.

Do I need a domain name for self-hosted n8n?

Not strictly, but strongly recommended. Without a domain you access n8n via the raw IP over HTTP, which many webhook integrations refuse to call. A domain with a free Let's Encrypt certificate makes HTTPS webhooks possible.

How do I update n8n without losing workflows?

Pull the new image and recreate the container. The workflows live in the mounted volume, so they persist across updates. Take a snapshot of the VPS first and export the workflows as a safety net.

Related articles

VPS 自托管 n8n 与越南 IP 要点

自托管 n8n 可以彻底摆脱云端按次计费的限制,工作流数量和处理量只取决于 VPS 配置。使用越南本地的独立 IPv4 部署,能让网络钩子地址稳定,出站请求也更容易被第三方服务信任。安装时先用 Docker 绑定本地端口,再用 Nginx 反向代理并配置免费 SSL 证书,这是最安全的标准做法。数据存储建议直接选用 PostgreSQL,避免后期迁移的麻烦。日常注意备份工作流数据和密钥,升级前先给服务器做快照即可。

Note: This guide is for general reference. Every system and infrastructure has its own specifics, so test each step in a safe environment and consult a qualified engineer before applying it in production.