If you're building automation workflows, n8n is one of the best open-source tools available. Instead of paying for n8n Cloud, you can run it on your own VPS for free — with your own subdomain, SSL certificate, and a cookie-based authentication layer so only you can access it.

This guide walks through exactly how I set it up on a Hetzner VPS running Ubuntu, with n8n accessible at n8n.yourdomain.com and protected behind a management dashboard login.

What You'll Need

  • A VPS running Ubuntu (I used Hetzner, but any provider works)
  • A domain with DNS managed via Hetzner DNS (or any DNS provider)
  • Node.js and npm installed on the VPS
  • A web server on your main domain (Apache or Nginx) for the auth cookie script

Install n8n on Your VPS

SSH into your VPS and install n8n globally via npm:

npm install -g n8n

Verify it works:

n8n --version

 Run n8n with PM2

PM2 keeps n8n running in the background and restarts it automatically on reboot. Install it:

 npm install -g pm2 

Start n8n, binding it to localhost only so it's not publicly reachable directly:

N8N_HOST=127.0.0.1 N8N_PORT=5678 pm2 start /usr/bin/n8n --name n8n

Important: Use the full path /usr/bin/n8n, not just n8n — otherwise PM2 can't find the binary.

Make PM2 survive server reboots:

pm2 startup # Run the command it prints pm2 save

Verify n8n is running:

pm2 status
curl -s -o /dev/null -w "%{http_code}" http://127.0.0.1:5678
# Should return 200

Point a Subdomain to Your VPS

In your DNS provider, add an A record:

Type Name Value TTL
A n8n YOUR.VPS.IP.ADDRESS 300

Wait a few minutes, then verify it propagated:

nslookup n8n.yourdomain.com 8.8.8.8
# Should return your VPS IP

Install Nginx and Get an SSL Certificate

Install Nginx and Certbot on your VPS:

sudo apt update
sudo apt install nginx certbot python3-certbot-nginx -y

Create a basic Nginx config for the subdomain first (Certbot needs it to exist):

sudo nano /etc/nginx/sites-available/n8n

Paste this minimal config:

 server {
    listen 80;
    server_name n8n.yourdomain.com;
    location / {
        return 200 'ok';
    }
}

 

Enable it and reload:

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


Now get the SSL certificate:

sudo certbot --nginx -d n8n.yourdomain.com

Configure the Full Nginx Reverse Proxy

Now replace the config with the full version that proxies to n8n with WebSocket support and cookie-based authentication:

sudo tee /etc/nginx/sites-available/n8n > /dev/null << 'EOF'
server {
    listen 80;
    server_name n8n.yourdomain.com;
    return 301 https://$host$request_uri;
}

server {
    listen 443 ssl;
    server_name n8n.yourdomain.com;

    ssl_certificate     /etc/letsencrypt/live/n8n.yourdomain.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/n8n.yourdomain.com/privkey.pem;
    include             /etc/letsencrypt/options-ssl-nginx.conf;
    ssl_dhparam         /etc/letsencrypt/ssl-dhparams.pem;

    default_type text/html;

    location / {
        set $allow 0;
        if ($cookie_n8n_access = "YOUR_SECRET_HERE") {
            set $allow 1;
        }
        if ($allow = 0) {
            return 403 '<!doctype html><html><head><meta charset="utf-8"><title>Access Denied</title><style>*{margin:0;padding:0;box-sizing:border-box}body{min-height:100vh;background:#060d18;display:flex;align-items:center;justify-content:center;font-family:system-ui,sans-serif}div{text-align:center;color:#cbd5e1}h1{font-size:3rem;color:#f1f5f9;margin-bottom:.5rem}p{color:rgba(255,255,255,.4);margin-bottom:1.5rem}a{display:inline-block;padding:10px 24px;background:linear-gradient(135deg,#1a3a52,#0e4f6e);color:#fff;border-radius:8px;text-decoration:none}</style></head><body><div><h1>403</h1><p>Access via the management dashboard</p><a href="https://management.yourdomain.com/n8n_auth.php">Go to Dashboard</a></div></body></html>';
        }

        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   Cookie $http_cookie;
        proxy_read_timeout 300s;
    }
}
EOF
 sudo nginx -t && sudo systemctl reload nginx

Generate a strong secret to use in place of YOUR_SECRET_HERE:

openssl rand -hex 32

Create the Auth Cookie Script

The authentication works by setting a shared-secret cookie on your main domain. When you visit n8n, Nginx checks for that cookie. If it's not there, you get the 403 page.

On your main hosting server, create management/n8n_auth.php:

<?php
require_once __DIR__ . '/includes/config.php';
require_once __DIR__ . '/includes/auth.php';
requireLogin(); // Ensures only logged-in users can proceed

const N8N_COOKIE_SECRET = 'YOUR_SECRET_HERE'; // Same secret as Nginx config

setcookie('n8n_access', N8N_COOKIE_SECRET, [
    'expires'  => time() + 8 * 3600,
    'path'     => '/',
    'domain'   => '.yourdomain.com',
    'secure'   => true,
    'httponly' => false,
    'samesite' => 'Lax',
]);

header('Location: https://n8n.yourdomain.com');
exit;

The cookie is set on .yourdomain.com (note the leading dot) so it's shared across all subdomains including n8n.yourdomain.com. It expires after 8 hours.

Add the n8n Button to Your Dashboard

In your management dashboard navbar, link the n8n button to n8n_auth.php rather than directly to the subdomain:

<a href="n8n_auth.php" target="_blank">
    <i class="fas fa-diagram-project"></i> n8n
</a>

This ensures the cookie is always set before the redirect happens.

How It Works

The full flow when you click the n8n button:

  1. You're already logged into the management dashboard
  2. n8n_auth.php runs — verifies your session via requireLogin()
  3. Sets the n8n_access cookie on .yourdomain.com with the shared secret
  4. Redirects you to https://n8n.yourdomain.com
  5. Nginx reads the cookie, matches the secret, and proxies the request to 127.0.0.1:5678
  6. Anyone without the cookie (or with the wrong value) gets the 403 page

This approach avoids the need for n8n's own user management entirely and ties access directly to your existing dashboard authentication.

Why Not Use Nginx auth_request?

The more conventional approach is to use Nginx's auth_request directive, which makes a subrequest to your auth endpoint before allowing access. However, if your main domain is on shared hosting, the hosting server will likely reject HTTP requests originating from your VPS IP with a 421 Misdirected Request error. The cookie-based approach sidesteps this entirely by avoiding any server-to-server communication.

Wrapping Up

You now have n8n running on your own infrastructure, accessible only through your authenticated management dashboard, with SSL, WebSocket support, and automatic restarts. Total ongoing cost: just your VPS. No n8n Cloud subscription needed.