You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Phase 1 (PR #72) put the control plane behind TLS on the bare IP: Caddy terminates HTTPS on public :4000 with a Let's Encrypt short-lived IP certificate (shortlived ACME profile, GA since 2026-01, auto-renewed), and devbox-server binds 127.0.0.1:4001. See create-katalystwp/server/deploy/Caddyfile.example and the README "HTTPS on a bare IP" section.
Still plain HTTP: every per-env WordPress site on ports 9000–9999 (wpUrl), including wp-admin browsing after redeeming a minted admin-login link. WP session cookies and page traffic are MITM-able. This issue is Phase 2: serve the env sites over HTTPS too.
Key enabler: an IP certificate is valid for any port, so https://<ip>:9033 works with the same cert Caddy already holds — no domain or per-env subdomains needed.
Work items
Rebind env containers to loopback — the generated docker-compose.yml publishes the WP port (and appPorts) publicly, e.g. "9033:80". Template change: "127.0.0.1:9033:80" so Caddy owns the public side. Applies to the WP port and workspace appPorts alike.
Caddy on the port range — terminate TLS for WP_PORT_RANGE (default 9000–9999), proxying port-for-port to 127.0.0.1. Options, in rough order of preference:
generate site blocks for the range with a small script (1000 listeners is unusual for Caddy but workable; consider narrowing the range first);
drive Caddy's admin API from the server's allocator (add/remove a route per env on create/destroy) — cleaner but couples the server to Caddy;
the layer4 plugin.
WordPress must know it's HTTPS — siteurl/home are baked as http://<ip>:<port> at install:
wp-config forwarded-proto shim in the template (set $_SERVER['HTTPS']='on' when X-Forwarded-Proto: https), and Caddy must send the header (default for reverse_proxy);
new server/scaffolder config (e.g. DEVBOX_PUBLIC_SCHEME=https) so fresh installs get https:// siteurls and the server's wpUrl / env-card links follow;
UI: the admin-login rebase in ui/app.js currently rebases host:port — must carry the scheme too.
Migration for existing envs (~49 on the prod box, all frozen at scaffold time): script that per env (a) edits compose to loopback-bind, docker compose up -d to rebind; (b) adds the forwarded-proto shim; (c) wp option update home/siteurl to https://. Must handle both bare-named and katalyst--prefixed compose projects (see PR The Katalyst menu: create lands on an interactive hub #68) WITHOUT regenerating compose files (regeneration would rename the project and orphan containers).
Warm pools bake at build time — after the template/scheme change, POST /pool/:presetId/rebuild every pool.
Server-side probes stay HTTP — health checks and wp exec go through docker/loopback; they must NOT be switched to the public HTTPS URL.
Risk areas to test first
In-container access: setup/dev scripts and health checks hit http://wordpress from inside the compose network. With an https:// siteurl, WP canonical redirects can bounce those requests. The forwarded-proto shim usually suffices, but verify: plugin activation, agent-connector install, admin-login mint (wp eval), and the Breakdance/Oxygen builders.
Admin-login flow end-to-end: mint returns a http://localhost:<port> URL that the UI rebases; token redemption must land on https://<ip>:<port> and the resulting wp-admin session must stay https (no mixed-content or redirect loop).
SANDBOX_PUBLIC_HOST consumers: preset setup scripts build browser-valid URLs from it; audit for hardcoded http://.
Do it on one fresh test env + one migrated env before touching the fleet.
Acceptance
New env via a warm claim: wpUrl is https://, site + wp-admin load with a valid cert, no mixed content.
Migrated old env (bare compose name): same, containers not orphaned.
curl http://<ip>:<wp-port> from outside: connection refused (nothing publicly bound but Caddy).
All pools rebuilt green; MCP mint_admin_login + browser admin-login both work.
Context
Phase 1 (PR #72) put the control plane behind TLS on the bare IP: Caddy terminates HTTPS on public
:4000with a Let's Encrypt short-lived IP certificate (shortlivedACME profile, GA since 2026-01, auto-renewed), and devbox-server binds127.0.0.1:4001. Seecreate-katalystwp/server/deploy/Caddyfile.exampleand the README "HTTPS on a bare IP" section.Still plain HTTP: every per-env WordPress site on ports 9000–9999 (
wpUrl), including wp-admin browsing after redeeming a minted admin-login link. WP session cookies and page traffic are MITM-able. This issue is Phase 2: serve the env sites over HTTPS too.Key enabler: an IP certificate is valid for any port, so
https://<ip>:9033works with the same cert Caddy already holds — no domain or per-env subdomains needed.Work items
docker-compose.ymlpublishes the WP port (andappPorts) publicly, e.g."9033:80". Template change:"127.0.0.1:9033:80"so Caddy owns the public side. Applies to the WP port and workspaceappPortsalike.WP_PORT_RANGE(default 9000–9999), proxying port-for-port to127.0.0.1. Options, in rough order of preference:layer4plugin.siteurl/homeare baked ashttp://<ip>:<port>at install:$_SERVER['HTTPS']='on'whenX-Forwarded-Proto: https), and Caddy must send the header (default forreverse_proxy);DEVBOX_PUBLIC_SCHEME=https) so fresh installs gethttps://siteurls and the server'swpUrl/ env-card links follow;ui/app.jscurrently rebases host:port — must carry the scheme too.docker compose up -dto rebind; (b) adds the forwarded-proto shim; (c)wp option update home/siteurltohttps://. Must handle both bare-named andkatalyst--prefixed compose projects (see PR The Katalyst menu: create lands on an interactive hub #68) WITHOUT regenerating compose files (regeneration would rename the project and orphan containers).POST /pool/:presetId/rebuildevery pool.wpexec go through docker/loopback; they must NOT be switched to the public HTTPS URL.Risk areas to test first
http://wordpressfrom inside the compose network. With anhttps://siteurl, WP canonical redirects can bounce those requests. The forwarded-proto shim usually suffices, but verify: plugin activation, agent-connector install, admin-login mint (wp eval), and the Breakdance/Oxygen builders.http://localhost:<port>URL that the UI rebases; token redemption must land onhttps://<ip>:<port>and the resulting wp-admin session must stay https (no mixed-content or redirect loop).SANDBOX_PUBLIC_HOSTconsumers: preset setup scripts build browser-valid URLs from it; audit for hardcodedhttp://.Acceptance
wpUrlishttps://, site + wp-admin load with a valid cert, no mixed content.curl http://<ip>:<wp-port>from outside: connection refused (nothing publicly bound but Caddy).mint_admin_login+ browser admin-login both work.🤖 Generated with Claude Code