All use cases

Local cluster + VPS · WireGuard or Tailscale mesh · mTLS over the link

Home + VPS Hybrid

Private dev cluster at home. Public face on a VPS. One registry drives both.

First deploy: ~2–3 hours including mesh VPN

Why pick this shape

  • Keep secrets, databases, and dev services at home. Expose only what needs to be public.
  • The VPS is just another host in the registry — the only special thing is which side faces the internet.
  • mTLS between local and VPS via Portoser's built-in CA; install_ca_on_hosts.sh distributes trust.

Registry skeleton

Copy, replace IPs and ssh_user, point CADDY_REGISTRY_PATH at it.

hosts:
  mini1:
    ip: 192.168.1.10                # LAN
    arch: arm64-apple
    roles: [infrastructure, vault, databases]
  pi1:
    ip: 192.168.1.51
    arch: arm64-linux
    roles: [internal_services]
  vps:
    ip: 10.10.0.2                    # WireGuard mesh, NOT the public IP
    arch: amd64-linux
    ssh_user: admin
    roles: [public_ingress]

services:
  api-public:
    hostname: api.example.com         # public hostname
    current_host: vps
    deployment_type: docker
    docker_compose: /api/docker-compose.yml
    port: 8443

Bringing it up

sudo tailscale up                          # on every host, both sides
./portoser certs init-ca
./install_ca_on_hosts.sh
./portoser certs generate-all-servers
./portoser certs deploy-servers
./portoser deploy mini1 vault api-backend
./portoser deploy vps caddy-public api-public

Common gotchas

  • The registry IP for the VPS is the mesh IP, not the public IP. Public DNS is a separate concern.
  • mesh VPN becomes load-bearing. If Tailscale or WireGuard is down, deploys to the VPS stop working.
  • Cert renewal matters. ./portoser certs list shows expiry — schedule rotation or it lapses.

Read the full VPS Hybrid walkthrough

Deeper version with more code, more gotchas, and links to operations docs.

Read in docs