Add HTTPS support and a management-token gate for the web UI
Build and push server image / build-and-push (push) Successful in 31s

ESP32 side can now reach the tools server over HTTPS: the Tools Server
field accepts an https:// address for a TLS-terminating reverse proxy
in front of the server (which still only ever speaks plain HTTP
itself), trusting Cloudflare's Origin CA root (embedded at build time)
since that's the common way to get a real cert on a private origin.
Every URL the device builds -- image fetch, config check, manage-menu
data, the QR codes' own links -- goes through one build_url() helper
that picks the scheme from what's configured.

Also adds an optional MANAGEMENT_TOKEN (docker-compose.yml) that gates
the web UI (/, /api/*) behind a shared secret -- unset by default, so
existing trusted-LAN deployments are unaffected. The same token is
entered once during the ESP32's captive-portal setup and gets baked
into the manage-menu's QR code (?token=...), so scanning it just works;
visiting the page without a valid token shows a plain entry prompt
instead of the config UI, and a valid query-param hit sets a cookie so
the page's own fetch()/<img> calls stay authorized for the rest of the
visit. Device-facing /frame/* endpoints are unaffected -- a separate,
already-documented trust boundary.
This commit is contained in:
2026-07-19 09:42:38 -04:00
parent 461beed04f
commit 6c7468a36e
12 changed files with 253 additions and 30 deletions
+35 -2
View File
@@ -78,8 +78,41 @@ two-step setup screen:
The config page asks for your home WiFi SSID/password and the "Tools
Server" address (`host:port` of the [server](../server/) -- **not** your
Immich server). Saving reboots the device, which then connects to your
home network and starts its normal fetch/sleep cycle.
Immich server; see below for the `https://` form). Saving reboots the
device, which then connects to your home network and starts its normal
fetch/sleep cycle.
## HTTP vs HTTPS
The Tools Server field accepts either:
- `host:port` (e.g. `192.168.1.50:8420`) -- plain HTTP, talks straight to
the [server](../server/), which never speaks TLS itself. This is the
default and needs nothing extra.
- `https://host[:port]` (e.g. `https://frame.example.com`) -- HTTPS,
for a TLS-terminating reverse proxy (nginx, etc.) sitting in front of
the server. Every URL the device builds (image fetch, config check,
manage-menu overlay data, the QR codes' own links) uses whichever
scheme you enter.
The firmware only trusts one certificate authority for the HTTPS case:
**Cloudflare's Origin CA** (both the RSA and ECC root, embedded at build
time from [`main/certs/cloudflare_origin_ca.pem`](main/certs/cloudflare_origin_ca.pem),
downloaded directly from Cloudflare's docs). This is the free, long-lived
certificate Cloudflare issues for origin servers -- not a
publicly-trusted cert, so ordinary browsers won't accept it directly, but
it's exactly what a reverse proxy in front of a Cloudflare-proxied
hostname presents. If your reverse proxy uses a different certificate
(a real publicly-trusted one from Let's Encrypt, or a different private
CA), swap the PEM file's contents for that CA's root and rebuild.
The device does perform normal hostname verification (it's not skipped),
so the Tools Server field's hostname has to match what the certificate
was actually issued for -- a bare LAN IP address (`https://192.168.1.50`)
will fail the handshake even with the right CA trusted, since an Origin
CA cert never covers a raw IP. Use whatever hostname the certificate's
SAN list actually covers (e.g. a local DNS/hosts entry pointing at the
frame's LAN IP, or the same public hostname the proxy is issued for).
## Skipping to the next photo