{
	# Disable HTTP/3 (QUIC) globally. Some restrictive / mobile networks break QUIC, and iOS would
	# otherwise try h3 via the Alt-Svc header and hang ~60s before falling back — the root of the
	# "phone can't reach the relay" failure. Forcing h1/h2 (TCP) makes URLSession use TCP directly.
	servers {
		protocols h1 h2
	}
}

pocket.ark-nexus.cc {
	# Public support is deliberately split from the OpenClaw admin Gateway. The API reaches the
	# isolated support host through a loopback-only, key-restricted SSH tunnel; static help files
	# are served here too so the App never depends on a messaging-team permission or Pages cache.
	handle_path /support-api/* {
		request_body {
			max_size 8KB
		}
		reverse_proxy 127.0.0.1:10966 {
			# Never forward a caller-supplied address. The API trusts this header only from
			# its loopback SSH-tunnel peer and parses it as one canonical IP address.
			header_up X-Forwarded-For {remote_host}
			header_up X-Real-IP {remote_host}
			# The support agent can need more than a minute for cold or complex queries.
			# Flush its JSON-stream heartbeats immediately so every proxy hop stays live.
			flush_interval -1
			transport http {
				read_timeout 150s
				response_header_timeout 135s
			}
		}
	}
	handle /support/* {
		header {
			Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' https://challenges.cloudflare.com; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; font-src https://fonts.gstatic.com; connect-src 'self' https://pocket.ark-nexus.cc https://challenges.cloudflare.com; frame-src https://challenges.cloudflare.com; img-src 'self' data:; frame-ancestors 'none'; base-uri 'self'; form-action 'self'"
			Referrer-Policy "no-referrer"
			X-Frame-Options "DENY"
			X-Content-Type-Options "nosniff"
			Permissions-Policy "camera=(), microphone=(), geolocation=()"
		}
		root * /var/www/cc-pocket-site
		file_server
	}
	# Release mirror for mainland-China installs/updates (GitHub's CDN crawls there). The tree is
	# maintained by cc-pocket-mirror-sync.{service,timer} (deploy/mirror-sync.sh); clients try
	# /dl/latest.json first and fall back to GitHub, so this path may lag but must never lie —
	# latest.json is swapped in atomically only after assets verify against the release SHA256SUMS.
	handle_path /dl/* {
		root * /var/www/cc-pocket-dl
		header /latest.json Cache-Control "no-cache"
		file_server
	}
	handle /manual/* {
		root * /var/www/cc-pocket-site
		file_server
	}
	handle /styles.css {
		root * /var/www/cc-pocket-site
		file_server
	}
	handle /app.js {
		root * /var/www/cc-pocket-site
		file_server
	}
	handle /favicon.svg {
		root * /var/www/cc-pocket-site
		file_server
	}
	handle /favicon-32.png {
		root * /var/www/cc-pocket-site
		file_server
	}
	handle /apple-touch-icon.png {
		root * /var/www/cc-pocket-site
		file_server
	}
	# Caddy auto-provisions a Let's Encrypt cert (needs inbound 80/443 from the
	# internet for the ACME challenge) and auto-handles the WebSocket upgrade,
	# so the relay's /v1/daemon and /v1/device WS endpoints just work.
	handle {
		reverse_proxy 127.0.0.1:9000 {
			# Same rule as /support-api above: never forward a caller-supplied address. Caddy
			# APPENDS to an existing X-Forwarded-For, so without this overwrite the relay's
			# rate limiters key on a string the caller wrote — rotate it per request and the
			# pair-code / redeem / auth / connect limits all stop counting. The relay also
			# pins itself to the last hop (installRelayForwardedHeaders); both, deliberately.
			header_up X-Forwarded-For {remote_host}
			header_up X-Real-IP {remote_host}
		}
	}
}

# Pairlet website on the HK origin. Keep the legacy relay block above unchanged.
www.pairlet.org {
    redir https://pairlet.org{uri} 308
}

pairlet.org {
	handle_path /support-api/* {
		request_body {
			max_size 8KB
		}
		reverse_proxy 127.0.0.1:10966 {
			# Never forward a caller-supplied address. The API trusts this header only from
			# its loopback SSH-tunnel peer and parses it as one canonical IP address.
			header_up X-Forwarded-For {remote_host}
			header_up X-Real-IP {remote_host}
			# The support agent can need more than a minute for cold or complex queries.
			# Flush its JSON-stream heartbeats immediately so every proxy hop stays live.
			flush_interval -1
			transport http {
				read_timeout 150s
				response_header_timeout 135s
			}
		}
	}
	handle /support/* {
		header {
			Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' https://challenges.cloudflare.com; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; font-src https://fonts.gstatic.com; connect-src 'self' https://pocket.ark-nexus.cc https://challenges.cloudflare.com; frame-src https://challenges.cloudflare.com; img-src 'self' data:; frame-ancestors 'none'; base-uri 'self'; form-action 'self'"
			Referrer-Policy "no-referrer"
			X-Frame-Options "DENY"
			X-Content-Type-Options "nosniff"
			Permissions-Policy "camera=(), microphone=(), geolocation=()"
		}
		root * /var/www/pairlet-site/current
		file_server
	}
	# Release mirror for mainland-China installs/updates (GitHub's CDN crawls there). The tree is
	# maintained by cc-pocket-mirror-sync.{service,timer} (deploy/mirror-sync.sh); clients try
	# /dl/latest.json first and fall back to GitHub, so this path may lag but must never lie —
	# latest.json is swapped in atomically only after assets verify against the release SHA256SUMS.
	handle_path /dl/* {
		root * /var/www/cc-pocket-dl
		header /latest.json Cache-Control "no-cache"
		file_server
	}
	handle /manual/* {
		root * /var/www/pairlet-site/current
		file_server
	}
	handle /styles.css {
		root * /var/www/pairlet-site/current
		file_server
	}
	handle /app.js {
		root * /var/www/pairlet-site/current
		file_server
	}
	handle /favicon.svg {
		root * /var/www/pairlet-site/current
		file_server
	}
	handle /favicon-32.png {
		root * /var/www/pairlet-site/current
		file_server
	}
	handle /apple-touch-icon.png {
		root * /var/www/pairlet-site/current
		file_server
	}
    handle {
        root * /var/www/pairlet-site/current
        file_server
    }
}

# Same relay process and database as the legacy host; never redirect WebSocket/API traffic.
relay.pairlet.org {
    reverse_proxy 127.0.0.1:9000 {
        header_up X-Forwarded-For {remote_host}
        header_up X-Real-IP {remote_host}
    }
}
