The public shape now works end to end: real ports, Caddy in front, and both
programs that need certificates getting them from the same CA -- Caddy for
the front ends over TLS-ALPN-01, the mail server for its own names over
HTTP-01, which Caddy forwards on port 80.
Proved in the lab against Pebble, with a DNS stub answering every name with
the machine's own address, so no public name or public CA is involved:
twenty checks, ending with IMAPS and submissions presenting a certificate
for the mail host that verifies against the CA, and the webmail sending
sign-in to the server as the first-party client the server registered.
Two things the test found, both of which would have shipped:
- The proxy fronted four of the server's five names. The server puts
ua-auto-config in its own certificate too, so its challenge was never
forwarded, one name failed, and the whole order failed with it -- leaving
the mail ports on a self-signed certificate while everything else looked
healthy. The list now matches what the server asks for.
- Nothing waited for the certificate. An order that fails is not retried on
its own and a restart does not start a new one, so the install declared
itself finished over a self-signed certificate. It now waits, asks again
every 45 seconds, and reports the issuer -- or says plainly that the
server will keep trying once the domain resolves here, which is the
ordinary case on a first install.
--acme-directory and --acme-ca-root are what let a private CA be used: the
root is added to the server image's own bundle and given to Caddy, because
neither sees the other's trust store.
The plan now happens. "inbuxa install --local --domain example.test
--install-deps --yes" on a machine with nothing on it ends with a mail
server, a console and a webmail running, an administrator and a first
mailbox created, and the records the domain needs written out.
The sequence is the one ihasmail-oneshot worked out against a running
server, which is why its JMAP client and its Docker handling came across
nearly whole: bring the server up in bootstrap mode with a credential that
lives in an override file for that step only, complete bootstrap, bring the
rest up without it -- so no recovery credential outlives the setup -- exempt
the front ends from the auto-ban, restart for the settings that need it,
create the first account, and write down the password nothing else holds.
New here: three services rather than two. The console is static files that
learn their server's address at start, and the webmail is given the
first-party OAuth client secret that the server is given too.
Twenty checks in the lab, from a bare Debian 13. The two worth having are
the ones that catch an install that looks fine and is not: nothing in the
running server carries a recovery admin any more, and the account the
installer created can sign in to the webmail it installed.
Two bugs the lab caught, both of which would have shipped:
- the private addresses were worked out on a copy of the stack, so the
server was told the webmail speaks from "", and refused it.
- the console image rewrites index.html when it starts, so a read-only root
filesystem left it restarting forever. The webmail keeps read_only; the
console cannot have it until that rewrite moves.