Skip to content

fix: keep one dashboard certificate across restarts (1.8 backport) - #1289

Merged
eous merged 3 commits into
mainfrom
backport/1.8-caddy-dashboard-cert
Oct 6, 2026
Merged

eous merged 3 commits into
mainfrom
backport/1.8-caddy-dashboard-cert

Conversation

@eous

@eous eous commented Oct 6, 2026

Copy link
Copy Markdown
Contributor

Backports #1288 to the 1.8 line (main). Both commits cherry-pick with -x. The only conflict was CHANGELOG.md, whose hunks are dropped here so the entry can go in with the next release's changelog commit.

This matters on main in particular: install.sh serves main's run.sh and new installs clone main, so until this lands, new and re-run installs keep a dashboard certificate that changes after almost every restart.

What it does, as described in #1288:

  • Caddyfile (both compose stacks): default_sni 127.0.0.1, so IP-address visitors share one certificate instead of one named after the container's Docker IP; a global cert_issuer internal default of 365 days, signed with the root; and grace_period 5s, so a restart with the dashboard open no longer waits out Docker's stop timeout and gets killed.
  • run.sh: re-running the installer restarts Caddy after docker compose up -d, so a pulled Caddyfile actually takes effect.
  • turnstone-doctor: a read-only preflight section that reports when Caddy is running an older config than the Caddyfile on disk, with the restart command.

The accepted trade-off carries over too: on-demand certificates for names a client makes up now last a year as well, which the Caddyfile and docs/tls.md call out.

Identical to dev: run.sh, turnstone/deploy/Caddyfile, both compose files, docs/tls.md and QUICKSTART.md. In turnstone/doctor.py, both test files and docs/docker.md, the files already differed between the branches; the change itself is identical to dev's, line offsets aside.

Checked on this branch (1.8.5 base): tests/test_doctor.py and tests/test_docker_config.py pass (182); ruff, mypy and shellcheck are clean; caddy validate (caddy:2.11) accepts the Caddyfile.

eous added 2 commits October 6, 2026 10:21
A browser sends no server name when it dials an IP address, so Caddy's
on-demand issuance named the dashboard certificate after the container's
Docker address. That address changes whenever compose recreates the
container, so each restart issued a new certificate, and each one expired
after 12 hours. Set default_sni to 127.0.0.1 so those connections share one
certificate, and issue every local certificate for a year, signed by the
10-year root because Caddy's intermediate lasts only 7 days.

Caddy reads its Caddyfile only at start, and an installer re-run leaves the
unchanged caddy container running on its old mount, so run.sh now restarts
Caddy after bringing the stack up. turnstone-doctor's report gains a Caddy
section that compares the config Caddy loaded with the adapted Caddyfile on
disk and gives the restart command when they differ.

(cherry picked from commit 0ffcee3)
Make the one-year lifetime Caddy's global issuer default instead of a
per-site snippet, and say plainly in the Caddyfile and docs that on-demand
issuance lets anyone who reaches the port add year-long certs. Set a 5s
grace_period so a restart with the dashboard open closes its streams
instead of waiting out Docker's stop timeout and being killed.

turnstone-doctor no longer copies Caddy's adapt error into the report, which
is shared and sent to a model, because Caddy quotes the offending token; it
names the line and the command that shows the error. A Caddyfile with
relative imports, which cannot resolve from stdin, now reads as
inconclusive instead of stale. Reading the Caddyfile or docker output no
longer crashes on non-UTF-8 text, wget gets a timeout, and the restart
commands quote the install directory.

Tests pin the Caddyfile's issuer, lifetime, default_sni and grace_period,
allow only the two read-only commands inside the container, and cover the
check's remaining branches.

(cherry picked from commit 02bbf8f)
@eous
eous merged commit ad95c3c into main Oct 6, 2026
11 checks passed
@eous
eous deleted the backport/1.8-caddy-dashboard-cert branch October 6, 2026 17:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant