diff --git a/scripts/dev.py b/scripts/devserver.py similarity index 92% rename from scripts/dev.py rename to scripts/devserver.py index c8beb44..c413a6d 100755 --- a/scripts/dev.py +++ b/scripts/devserver.py @@ -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)