# Serves the Furtka landing page + live JSON on :80 (plain HTTP) and on # HTTPS via Caddy's built-in `tls internal` — locally-issued certs signed # by a root CA that Caddy generates on first start and stores under # /var/lib/caddy/pki/authorities/local/. Static pages are read from # /opt/furtka/current/ — updates flip the symlink and everything picks up # the new content without a Caddy restart (a `systemctl reload caddy` is # still triggered post-swap to flush the file-server's handle cache). # /apps and /api are reverse-proxied to the resource-manager API # (furtka serve, bound to 127.0.0.1:7000). # # Hostname templating: __FURTKA_HOSTNAME__ gets substituted with the # install-time hostname by webinstaller/app.py on first install and by # furtka.updater._refresh_caddyfile on every self-update. A bare `:443 # { tls internal }` (no hostname) never triggers leaf-cert issuance, so # SNI-based handshakes die with `SSL_ERROR_INTERNAL_ERROR_ALERT` — the # 26.4-alpha regression this file exists to cure. # # Force-HTTPS: /etc/caddy/furtka.d/*.caddyfile gets imported into the :80 # block. The /api/furtka/https/force endpoint creates or removes # redirect.caddyfile there to toggle the HTTP→HTTPS redirect, then reloads # Caddy. Glob imports silently no-op on an empty/missing directory, so the # toggle-off state is "no file present" rather than "empty file". { # Named-hostname :443 blocks would otherwise make Caddy add its own # HTTP→HTTPS redirect — but we already serve our own `:80` block and # the opt-in /settings toggle owns the redirect. Disable the built-in # to keep a single source of truth. auto_https disable_redirects } (furtka_routes) { handle /api/* { reverse_proxy localhost:7000 } handle /apps* { reverse_proxy localhost:7000 } handle /login* { reverse_proxy localhost:7000 } handle /logout* { reverse_proxy localhost:7000 } # /settings and / — these previously served as static HTML straight # from the catch-all file_server, which meant the auth-guard was # bypassed: a LAN visitor could see the box's version, IP, and # reach the Update-now / Reboot buttons (the API calls behind them # are auth-gated, but the page itself rendered without a redirect # to /login). Route them through the Python handler which checks # the session cookie and either serves the static HTML from # assets/www/ or redirects to /login. handle /settings* { reverse_proxy localhost:7000 } handle / { reverse_proxy localhost:7000 } # Runtime JSON lives under /var/lib/furtka/ so it survives self-updates # (which only swap /opt/furtka/current). handle /status.json { root * /var/lib/furtka file_server } handle /furtka.json { root * /var/lib/furtka file_server } handle /update-state.json { root * /var/lib/furtka file_server } # Download the local root CA cert Caddy generated for `tls internal`. # Available on both :80 and :443 so users can grab it before they've # trusted it. The private key next to it stays 0600 / caddy-owned. handle /rootCA.crt { root * /var/lib/caddy/pki/authorities/local rewrite * /root.crt file_server header Content-Type "application/x-x509-ca-cert" header Content-Disposition "attachment; filename=furtka-local-rootCA.crt" } handle { root * /opt/furtka/current/assets/www file_server encode gzip } log { output stdout } } :80 { import /etc/caddy/furtka.d/*.caddyfile import furtka_routes } __FURTKA_HOSTNAME__.local, __FURTKA_HOSTNAME__ { tls internal import furtka_routes }