# /etc/caddy/Caddyfile on **vps2** (169.58.46.181) — the public-facing box.
#
# vps2 serves BOTH environments an external user can reach:
#   thermograph.org         -> prod   (loopback LB on 127.0.0.1:8137 / :8080)
#   beta.thermograph.org    -> beta   (loopback LB on 127.0.0.1:8237 / :8180)
#
# and Centralis at mcp.thermograph.org, which is provisioned separately.
#
# Each domain's A/AAAA record must already point here — Caddy provisions a
# Let's Encrypt cert on first request and auto-renews. Nothing else to do for
# TLS (just make sure ports 80 and 443 are open).
#
# This file was split out of a single deploy/Caddyfile that described both
# boxes' sites at once. That was workable while each box served an unrelated
# set; it stopped being workable when the two ports 8137/8080 started meaning
# "prod on vps2" here and nothing at all on the other box. See Caddyfile.vps1
# for git/dashboard/portfolio.
#
# Thermograph owns thermograph.org's root, so both services run with
# THERMOGRAPH_BASE=/ — pages, assets and API all sit at "/" with no sub-path
# prefix. Backend and frontend are separate containers, each on its own loopback
# port; Caddy path-splits directly to whichever owns a given path, so the
# browser still sees one apparent origin. The enumerated backend list below
# mirrors backend/web/app.py's own routing exactly (a single catch-all proxy to
# frontend for everything else) -- unlike frontend's paths, backend's don't grow
# every time a new static asset filename is added. A gap in this list still just
# degrades to "one extra hop" through backend's own proxy fallback, never a 404.

thermograph.org {
	encode zstd gzip

	@backend_paths path /api/* /digest /discord/interactions

	# Active health check on the same cheap /healthz route each container's own
	# HEALTHCHECK uses (Dockerfile) — so a deploy that's still restarting/booting
	# never gets proxied into (a reload alone has no gate, hop-1 runbook hazard #10).
	# 15s (was 5s): plenty responsive for a process that only restarts on a deploy,
	# and a quarter of the polling load.
	handle @backend_paths {
		reverse_proxy 127.0.0.1:8137 {
			health_uri /healthz
			health_interval 15s
			health_timeout 3s
			health_status 2xx
		}
	}

	handle {
		reverse_proxy 127.0.0.1:8080 {
			health_uri /healthz
			health_interval 15s
			health_timeout 3s
			health_status 2xx
		}
	}

	# Access-log hygiene: the default JSON encoder serializes full request headers,
	# the TLS block, and response headers on every line (measured ~1,133B/line) --
	# strip those with the `filter` format encoder. Also strip the query string from
	# the logged URI: Caddy's default logger records request.uri *including* the
	# query string, so every `?q=<search text>` a visitor typed sat in Loki next to
	# their client IP for the full 30-day retention -- a real privacy leak, not just
	# noise. Bot/crawler skipping stays out of here: `log_skip` needs Caddy >= 2.7
	# and an upgrade is out of scope, so that's handled downstream in Alloy's
	# loki.process "caddy" stage instead (see observability/alloy/config.alloy).
	#
	# The FILENAME is load-bearing now: Alloy attributes each access log to an
	# environment by filename (thermograph.log -> host="prod", beta.log ->
	# host="beta"). One Caddy fronts two environments here, so a single log file
	# would file every beta request under prod. Renaming either file means
	# updating loki.process "caddy" in observability/alloy/config.alloy.
	log {
		output file /var/log/caddy/thermograph.log {
			roll_size 20MiB
			roll_keep 5
		}
		format filter {
			wrap json
			fields {
				request>headers delete
				request>tls delete
				resp_headers delete
				request>uri regexp \?.* ""
			}
		}
	}
}

# Beta — same shape as prod, pointed at beta's loopback LB. It moved here from
# its own box; the DNS A record for beta.thermograph.org must point at vps2.
#
# Deliberately NOT indexed: beta serves the same content as prod at a different
# hostname, which is a duplicate-content problem for search engines and an
# invitation for users to land on a rehearsal environment from a search result.
# The app itself never pings IndexNow from beta (see env-topology.sh's
# TG_POST_DEPLOY), and this header closes the other half.
beta.thermograph.org {
	encode zstd gzip

	header {
		X-Robots-Tag "noindex, nofollow"
	}

	@backend_paths path /api/* /digest /discord/interactions

	handle @backend_paths {
		reverse_proxy 127.0.0.1:8237 {
			health_uri /healthz
			health_interval 15s
			health_timeout 3s
			health_status 2xx
		}
	}

	handle {
		reverse_proxy 127.0.0.1:8180 {
			health_uri /healthz
			health_interval 15s
			health_timeout 3s
			health_status 2xx
		}
	}

	log {
		output file /var/log/caddy/beta.log {
			roll_size 20MiB
			roll_keep 5
		}
		format filter {
			wrap json
			fields {
				request>headers delete
				request>tls delete
				resp_headers delete
				request>uri regexp \?.* ""
			}
		}
	}
}

# Optional: redirect www -> apex. Add the www CNAME/A record first, then
# uncomment.
# www.thermograph.org {
# 	redir https://thermograph.org{uri} permanent
# }
