# ══════════════════════════════════════════════════════════════════════════════ # Caddyfile — Tiger Control Plane # Deployed at: agent.manohargupta.com # # What Caddy does here: # 1. Automatically obtains and renews TLS certificates via Let's Encrypt # 2. Handles HTTPS → HTTP reverse proxy to the Next.js dashboard # 3. Protects certain routes with basic auth (exec, restart, config write) # 4. Sets security headers # # To deploy on your Hetzner VPS: # 1. Install Caddy: apt install caddy # 2. Copy this file: sudo cp Caddyfile /etc/caddy/Caddyfile # 3. Set the basic auth password hash (see instructions below) # 4. Reload: sudo systemctl reload caddy # # ── How to generate the basicauth password hash ────────────────────────────── # Run this on your VPS: # caddy hash-password --plaintext "your-password-here" # Then paste the output as the hash below (the $2a$... string). # ══════════════════════════════════════════════════════════════════════════════ agent.manohargupta.com { # ── TLS ────────────────────────────────────────────────────────────────── # Caddy automatically fetches and renews TLS from Let's Encrypt. # Your VPS must have ports 80 and 443 open for this to work. tls { # Optional: use a specific email for Let's Encrypt notifications # email admin@manohargupta.com } # ── Security headers ───────────────────────────────────────────────────── # These headers protect against common web attacks. # X-Frame-Options prevents your dashboard from being embedded in iframes. # X-Content-Type-Options stops browsers from guessing MIME types. header { X-Frame-Options "SAMEORIGIN" X-Content-Type-Options "nosniff" Referrer-Policy "strict-origin-when-cross-origin" # Remove server info from responses -Server } # ── Protected routes (require basic auth) ──────────────────────────────── # These are the "dangerous" endpoints — exec, restart, config writes. # Basic auth adds a second layer of protection on top of the bridge token. # # Generate hash with: caddy hash-password --plaintext "YOUR_PASSWORD" # Replace "CHANGE_ME_HASH" with the output. @protected path /api/tiger/exec /api/tiger/restart /api/tiger/config basicauth @protected { # Username: tiger # Hash: run `caddy hash-password --plaintext "your-password"` and paste here tiger $2a$14$CHANGE_ME_HASH_GENERATED_BY_CADDY_HASH_PASSWORD_COMMAND } # ── Reverse proxy to Next.js dashboard ─────────────────────────────────── # The dashboard runs on port 3000 (localhost only). # All requests go here by default. reverse_proxy localhost:3000 { # Forward the real client IP to Next.js so logs show the right IP header_up X-Real-IP {remote_host} header_up X-Forwarded-For {remote_host} header_up X-Forwarded-Proto {scheme} # Health check — Caddy verifies the backend is alive before routing health_uri /api/tiger/status health_interval 30s health_timeout 10s } # ── Handle SSE (Server-Sent Events) correctly ──────────────────────────── # SSE is a streaming connection — we must disable buffering. # Without this, Caddy buffers the stream and logs appear with a delay. @sse path /api/tiger/logs handle @sse { reverse_proxy localhost:3000 { header_up X-Real-IP {remote_host} # Flush immediately — critical for streaming flush_interval -1 } } # ── Logging ────────────────────────────────────────────────────────────── log { output file /var/log/caddy/agent.manohargupta.com.log { roll_size 10MB roll_keep 5 } format json } } # ══════════════════════════════════════════════════════════════════════════════ # Tiger Bridge direct access — INTERNAL USE ONLY # The bridge listens on localhost:3456 and is NOT publicly exposed. # All bridge calls go through the Next.js dashboard routes. # # If you ever need to expose the bridge directly (debugging only), # uncomment and use the block below. Remember to set a strong token! # ══════════════════════════════════════════════════════════════════════════════ # bridge.agent.manohargupta.com { # reverse_proxy localhost:3456 # tls { # # email admin@manohargupta.com # } # }