Files

2.9 KiB

Caddy Multi-Service Routing

As of Jul 2026, Caddy on Core (netcup) serves 3 subdomains plus static file routes, all with automatic Let's Encrypt TLS.

Active domains

Domain Serves Port upstream
sign.itpropartner.com DocuSeal (reverse proxy) + vehicles.json static 3000
core.itpropartner.com API endpoints (health, vehicles.json, capabilities) Static files
app.itpropartner.com Portal mockups (reverse proxy) 8081

Caddyfile structure

Current config at /etc/caddy/Caddyfile:

sign.itpropartner.com {
    reverse_proxy 127.0.0.1:3000

    @json path /vehicles.json
    handle @json {
        root * /var/www/static
        file_server
        header Access-Control-Allow-Origin "*"
    }
}

core.itpropartner.com {
    header Access-Control-Allow-Origin "*"

    @health path /health
    handle @health {
        respond "OK" 200
    }

    @vehicles path /vehicles.json
    handle @vehicles {
        root * /var/www/static
        file_server
    }

    @capabilities path /capabilities
    handle @capabilities {
        root * /root/portal-mockup
        file_server
    }
}

app.itpropartner.com {
    reverse_proxy 127.0.0.1:8081
}

Adding a new domain

  1. Add A record at SiteGround (or Cloudflare if zone is there) pointing to 152.53.192.33
  2. Add a new block to /etc/caddy/Caddyfile
  3. Run systemctl reload caddy
  4. Wait ~15s for Let's Encrypt cert — first request may take 10-15s

Adding a static file route to an existing domain

Use the handle @name path /path pattern:

domain.com {
    reverse_proxy 127.0.0.1:3000    # existing proxy

    @newfile path /data.json         # new route
    handle @newfile {
        root * /path/to/files
        file_server
        header Access-Control-Allow-Origin "*"
    }
}

Pitfalls

  • File must be readable by caddy user. Caddy runs as the caddy user (not root). Files in /root/ must be world-readable or chmod o+r. Use /var/www/static/ for world-readable static files.
  • Reload vs restart. systemctl reload caddy is preferred — no downtime. Use systemctl restart caddy when the Caddyfile had a parse error that prevented reload.
  • Full restart drops existing connections. After a restart, the 3 domains may each take 5-15s to get their Let's Encrypt certs on first request.
  • Verify with curl localhost. Use curl -s -H "Host: domain.com" http://127.0.0.1:xxx/ to test routing before DNS propagates.
  • Cloudflare Tunnel alternative. If Tailscale Serve or Caddy port conflicts arise (port 443), Cloudflare Tunnel is installed (cloudflared at /usr/local/bin/cloudflared). Auth requires a browser login at the Cloudflare authorization URL. Tunnel doesn't need an open port — it creates outbound connections.
  • Tailscale Serve was stopped to free port 443 for Caddy. The old portal URL via Tailscale (vaultwarden.tailc2f3b0.ts.net/portal) is no longer active. Portal is now at app.itpropartner.com.