Back to Blog

Self-Hosting n8n, Supabase, and My Entire Automation Stack on a Hetzner VPS

I was paying about $80/month across various SaaS subscriptions for automation tools and database services. Then I did the math on a Hetzner VPS and realized I could run all of it for about €10/month. So I did.

This post is the technical walkthrough of how I set everything up. If you're comfortable with SSH and Docker, this is maybe a weekend project. If you're not... it's a learning opportunity.

The stack

  • Hetzner Cloud - the VPS provider. European, affordable, fast. Their CPX31 (4 vCPU, 8GB RAM) is more than enough for n8n + Supabase running simultaneously.
  • Terraform - because I don't want to click through a web UI to provision servers. Infrastructure as code or bust.
  • Dokploy - an open-source PaaS (think Vercel/Heroku but self-hosted). Handles Docker deployments, SSL certificates, and reverse proxying via Traefik.
  • n8n - my automation engine.
  • Supabase - my database/auth/storage layer (self-hosted, not the cloud version).

Step 1: Terraform the server

I keep my Terraform files in a private repo. Here's the relevant bit:

terraform {
  required_providers {
    hcloud = {
      source  = "hetznercloud/hcloud"
      version = "~> 1.45"
    }
  }
}

provider "hcloud" {
  token = var.hcloud_token
}

resource "hcloud_ssh_key" "default" {
  name       = "my-ssh-key"
  public_key = file("~/.ssh/id_ed25519.pub")
}

resource "hcloud_server" "automation_node" {
  name        = "automation-node-01"
  image       = "ubuntu-24.04"
  server_type = "cpx31"
  location    = "fsn1"
  ssh_keys    = [hcloud_ssh_key.default.id]
  firewall_ids = [hcloud_firewall.basic.id]
}

resource "hcloud_firewall" "basic" {
  name = "basic-firewall"

  rule {
    direction  = "in"
    protocol   = "tcp"
    port       = "22"
    source_ips = ["0.0.0.0/0", "::/0"]
  }

  rule {
    direction  = "in"
    protocol   = "tcp"
    port       = "80"
    source_ips = ["0.0.0.0/0", "::/0"]
  }

  rule {
    direction  = "in"
    protocol   = "tcp"
    port       = "443"
    source_ips = ["0.0.0.0/0", "::/0"]
  }
}

output "server_ip" {
  value = hcloud_server.automation_node.ipv4_address
}

terraform apply, wait 30 seconds, get an IP. Every time I do this I think about how this used to take days with a hosting provider's support ticket.

Step 2: SSH in and install Dokploy

ssh root@<SERVER_IP>
curl -sSL https://dokploy.com/install.sh | sh

That's it. Dokploy sets up Docker, Traefik, and gives you a web UI at port 3000. I set up my admin account, pointed my domain's DNS to the server IP, and configured the domain in Dokploy's settings. SSL certificates are handled automatically via Let's Encrypt.

I know some people have opinions about piping curl to sh. I read the script first. It's fine.

Step 3: Deploy n8n

In Dokploy, I created a new Compose application with this config:

version: '3.8'

services:
  n8n:
    image: docker.n8n.io/n8nio/n8n
    restart: always
    environment:
      - N8N_HOST=n8n.mydomain.com
      - N8N_PORT=5678
      - N8N_PROTOCOL=https
      - NODE_ENV=production
      - WEBHOOK_URL=https://n8n.mydomain.com/
      - GENERIC_TIMEZONE=America/Sao_Paulo
    volumes:
      - n8n_data:/home/node/.n8n

volumes:
  n8n_data:

Configured the domain in Dokploy, hit deploy. n8n was up and running with SSL in about 2 minutes. No execution limits, no monthly tier anxiety.

Step 4: Deploy Supabase

Supabase is more involved - it's a multi-service beast (PostgreSQL, GoTrue, PostgREST, Realtime, Storage, Studio). I used the official Docker Compose file from the Supabase repo, modified the .env with my own secrets, JWT keys, and database passwords, and created another Compose application in Dokploy.

It took a bit more fiddling to get the routing right - Supabase Studio, the API endpoint, and the auth service all need their own subdomains or paths. But once I figured out the Traefik labels, everything clicked.

The self-hosted Supabase Studio is identical to the cloud version. I still find it slightly surreal that I'm running all of this on a €10/month server.

The result

My monthly infrastructure cost went from ~$80 to ~€10. I have complete control over my data, no execution limits on n8n, and a full Supabase instance for whatever I need. The Terraform files mean I can tear everything down and rebuild it from scratch in under 10 minutes.

Is it more work than using managed services? Yes. Do I have to monitor it myself? Yes. But I'm an engineer. This stuff is fun, and the tradeoff is more than worth it.

If my server ever catches fire, terraform apply and a Docker volume backup gets me back to exactly where I was. That's good enough for me.