# The loopback LB bridge's own config — NOT the host Caddy (that one still
# terminates TLS for thermograph.org and proxies to 127.0.0.1:8137 exactly as
# before; it needs no change for the stack cutover).
#
# This Caddy runs as a PLAIN container (deploy-stack.sh manages it) because
# only plain containers can bind a specific host IP: Swarm port configs
# publish on 0.0.0.0 (routing mesh or host mode alike), which would expose
# the plaintext app un-fronted — hazard #6. It joins the stack's attachable
# overlay and proxies to the service VIPs; Swarm's VIP round-robins across
# however many web replicas the autoscaler is running, so this bridge never
# needs to know the replica count.

{
	auto_https off
	admin off

	# WITHOUT THIS, EVERY OAUTH REDIRECT URI THE BACKEND BUILDS IS http://.
	#
	# There are two Caddy hops in front of the app: the HOST Caddy terminates TLS
	# and sets X-Forwarded-Proto: https, then proxies to 127.0.0.1:8137 over plain
	# HTTP; this LB is the second hop. Caddy only preserves an incoming
	# X-Forwarded-* header when the immediate peer is a TRUSTED proxy — otherwise
	# it overwrites the header with the scheme of the connection it just received,
	# which here is http. So the app saw http:// no matter how the user arrived.
	#
	# accounts/oauth.py:_redirect_uri builds the callback from x-forwarded-proto,
	# and that URI must match what is registered in the provider's console.
	# Discord tolerates the http:// form; GOOGLE REJECTS a non-HTTPS redirect URI
	# for a web client outright, so Google sign-in could not work at all until
	# this was fixed — independently of whether the credentials were configured.
	#
	# Measured on vps2 before the fix, same request to each hop:
	#   direct to web, XFP=https   -> https://thermograph.org/api/v2/...
	#   through this LB, XFP=https -> http://thermograph.org/api/v2/...
	#
	# private_ranges covers 127.0.0.1/8 and the Docker bridge ranges, which is
	# where the host Caddy reaches this container from. Nothing outside the box
	# can connect here — the LB is bound to loopback precisely so it cannot be
	# reached un-fronted (hazard #6, above) — so trusting the local peer does not
	# widen anything: the only party that can set these headers is the host Caddy.
	servers {
		trusted_proxies static private_ranges
	}
}

:8137 {
	reverse_proxy web:8137 {
		# Fail fast to the client if the VIP has no healthy task; Swarm's own
		# task healthchecks handle ejecting dead replicas from the VIP.
		lb_try_duration 5s
	}
}

:8080 {
	reverse_proxy frontend:8080 {
		lb_try_duration 5s
	}
}
