Devserver: run Caddy on standard ports such that it can obtain certs.
This commit is contained in:
@@ -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)
|
||||||
|
|
||||||
Reference in New Issue
Block a user