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.
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)
--origin URL Allowed origin(s), 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
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"
NO_FRONTEND_TOOL = """\
@@ -61,11 +62,10 @@ NO_FRONTEND = """\
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 = """\
{
admin off
auto_https off
log {
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
scheme = parsed.scheme or "https"
host = parsed.hostname or parsed.path # handle case without scheme
port = parsed.port or (4480 if scheme == "http" else CADDY_PORT)
site_addr = f"{scheme}://{host}:{port}"
port = parsed.port or (CADDY_HTTP_PORT if scheme == "http" else CADDY_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 = (
CADDYFILE_SITE_BLOCK
.replace("SITE_ADDR", site_addr)
@@ -224,7 +228,8 @@ def run_caddy(origins: list[str], vite_port: int) -> subprocess.Popen | None:
caddy_process = None
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(
cmd,
stdin=subprocess.PIPE,
@@ -316,21 +321,16 @@ def main():
auth_host = args.auth_host
if "://" not in auth_host:
auth_host = f"https://{auth_host}"
# Add port if not standard
parsed = urlparse(auth_host)
if not parsed.port:
caddy_origins.append(f"{auth_host}:{CADDY_PORT}")
else:
caddy_origins.append(auth_host)
caddy_origins.append(auth_host)
else:
# Use rp-id as the hostname
caddy_origins.append(f"https://{args.rp_id}:{CADDY_PORT}")
# Use rp-id as the hostname (standard port 443, no port in URL)
caddy_origins.append(f"https://{args.rp_id}")
# Start Caddy if requested (after computing origins)
if args.caddy:
if not caddy_origins:
caddy_origins = [f"https://{args.rp_id}:{CADDY_PORT}"]
stderr.write(f">>> caddy @ {' '.join(caddy_origins)}/\n")
caddy_origins = [f"https://{args.rp_id}"]
stderr.write(f">>> sudo caddy @ {' '.join(caddy_origins)}\n")
if not run_caddy(caddy_origins, vite_port):
raise SystemExit(1)