Devserver: run Caddy on standard ports such that it can obtain certs.

This commit is contained in:
Leo Vasanko
2025-12-06 22:50:42 +00:00
parent 9763ab37bc
commit f74b32c70b
+17 -17
View File
@@ -13,7 +13,7 @@ All other options are forwarded to `paskia serve`.
Backend always listens on localhost:4402. Backend always listens on localhost:4402.
Options: Options:
--caddy Run Caddy as HTTPS proxy on port 4443 --caddy Run Caddy as HTTPS proxy on port 443 (requires sudo)
--rp-id HOST Relying Party ID (used as hostname for Caddy) --rp-id HOST Relying Party ID (used as hostname for Caddy)
--origin URL Allowed origin(s), passed to backend --origin URL Allowed origin(s), passed to backend
--auth-host H Dedicated auth host, passed to backend --auth-host H Dedicated auth host, passed to backend
@@ -36,7 +36,8 @@ from urllib.parse import urlparse
DEFAULT_VITE_PORT = 4403 # overrides by CLI option DEFAULT_VITE_PORT = 4403 # overrides by CLI option
BACKEND_PORT = 4402 # hardcoded, also in vite.config.ts BACKEND_PORT = 4402 # hardcoded, also in vite.config.ts
CADDY_PORT = 4443 # HTTPS port for Caddy proxy CADDY_PORT = 443 # HTTPS port for Caddy proxy
CADDY_HTTP_PORT = 80 # HTTP port for ACME challenges
DEFAULT_HOST = "localhost" DEFAULT_HOST = "localhost"
NO_FRONTEND_TOOL = """\ NO_FRONTEND_TOOL = """\
@@ -61,11 +62,10 @@ NO_FRONTEND = """\
for various frontend assets, so make sure to start it manually. for various frontend assets, so make sure to start it manually.
""" """
# Global options to disable auto HTTPS redirect (requires port 80) # Global options for Caddy
CADDYFILE_GLOBAL = """\ CADDYFILE_GLOBAL = """\
{ {
admin off admin off
auto_https off
log { log {
level warn level warn
} }
@@ -210,8 +210,12 @@ def run_caddy(origins: list[str], vite_port: int) -> subprocess.Popen | None:
# Extract scheme://host:port from origin URL # Extract scheme://host:port from origin URL
scheme = parsed.scheme or "https" scheme = parsed.scheme or "https"
host = parsed.hostname or parsed.path # handle case without scheme host = parsed.hostname or parsed.path # handle case without scheme
port = parsed.port or (4480 if scheme == "http" else CADDY_PORT) port = parsed.port or (CADDY_HTTP_PORT if scheme == "http" else CADDY_PORT)
site_addr = f"{scheme}://{host}:{port}" # Use standard ports without explicit port in address (cleaner URLs)
if port in (80, 443):
site_addr = f"{scheme}://{host}"
else:
site_addr = f"{scheme}://{host}:{port}"
block = ( block = (
CADDYFILE_SITE_BLOCK CADDYFILE_SITE_BLOCK
.replace("SITE_ADDR", site_addr) .replace("SITE_ADDR", site_addr)
@@ -224,7 +228,8 @@ def run_caddy(origins: list[str], vite_port: int) -> subprocess.Popen | None:
caddy_process = None caddy_process = None
try: try:
cmd = [caddy_path, "run", "--config", "-", "--adapter", "caddyfile"] # Use sudo to bind to privileged ports (80/443) for ACME certificate fetching
cmd = ["sudo", caddy_path, "run", "--config", "-", "--adapter", "caddyfile"]
caddy_process = subprocess.Popen( caddy_process = subprocess.Popen(
cmd, cmd,
stdin=subprocess.PIPE, stdin=subprocess.PIPE,
@@ -316,21 +321,16 @@ def main():
auth_host = args.auth_host auth_host = args.auth_host
if "://" not in auth_host: if "://" not in auth_host:
auth_host = f"https://{auth_host}" auth_host = f"https://{auth_host}"
# Add port if not standard caddy_origins.append(auth_host)
parsed = urlparse(auth_host)
if not parsed.port:
caddy_origins.append(f"{auth_host}:{CADDY_PORT}")
else:
caddy_origins.append(auth_host)
else: else:
# Use rp-id as the hostname # Use rp-id as the hostname (standard port 443, no port in URL)
caddy_origins.append(f"https://{args.rp_id}:{CADDY_PORT}") caddy_origins.append(f"https://{args.rp_id}")
# Start Caddy if requested (after computing origins) # Start Caddy if requested (after computing origins)
if args.caddy: if args.caddy:
if not caddy_origins: if not caddy_origins:
caddy_origins = [f"https://{args.rp_id}:{CADDY_PORT}"] caddy_origins = [f"https://{args.rp_id}"]
stderr.write(f">>> caddy @ {' '.join(caddy_origins)}/\n") stderr.write(f">>> sudo caddy @ {' '.join(caddy_origins)}\n")
if not run_caddy(caddy_origins, vite_port): if not run_caddy(caddy_origins, vite_port):
raise SystemExit(1) raise SystemExit(1)