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.
72 lines
1.9 KiB
Cheetah
72 lines
1.9 KiB
Cheetah
# Written by the inbuxa installer {{.Version}} for {{.Domain}}.
|
|
#
|
|
# Caddy holds 80 and 443 for two programs that both want certificates for some
|
|
# of the same names: Caddy itself, to serve HTTPS, and the mail server, whose
|
|
# IMAP and SMTP listeners need a certificate of their own. They are kept apart
|
|
# by challenge type rather than by name:
|
|
#
|
|
# Caddy TLS-ALPN-01 on 443 -- for the server's names it never uses 80.
|
|
# the server HTTP-01 on 80, which Caddy forwards to it untouched.
|
|
#
|
|
# So neither answers the other's challenge, and neither needs the other's key.
|
|
|
|
{
|
|
email {{.Email}}
|
|
{{- if .ACMEDirectory}}
|
|
acme_ca {{.ACMEDirectory}}
|
|
{{- end}}
|
|
{{- if .ACMECARoot}}
|
|
acme_ca_root /etc/caddy/acme-ca-root.pem
|
|
{{- end}}
|
|
}
|
|
{{- if .Webmail}}
|
|
|
|
# The webmail. Push arrives as Server-Sent Events, so responses are flushed as
|
|
# they are written rather than buffered.
|
|
{{.WebmailHost}} {
|
|
encode zstd gzip
|
|
reverse_proxy webmail:8080 {
|
|
flush_interval -1
|
|
}
|
|
}
|
|
{{- end}}
|
|
{{- if .Console}}
|
|
|
|
# The console. Static files: it talks to the mail server from the browser, so
|
|
# nothing here proxies the API.
|
|
{{.ConsoleHost}} {
|
|
encode zstd gzip
|
|
reverse_proxy console:8080
|
|
}
|
|
{{- end}}
|
|
|
|
# The mail server's web side: JMAP for the front ends and any other client,
|
|
# CalDAV, CardDAV, autoconfig and MTA-STS. The server is told to believe the
|
|
# X-Forwarded-For Caddy sets here, so a scanner is banned by its own address
|
|
# rather than by Caddy's.
|
|
{{join .ServerNames ", "}} {
|
|
tls {
|
|
issuer acme {
|
|
{{- if .ACMEDirectory}}
|
|
dir {{.ACMEDirectory}}
|
|
{{- end}}
|
|
{{- if .ACMECARoot}}
|
|
trusted_roots /etc/caddy/acme-ca-root.pem
|
|
{{- end}}
|
|
email {{.Email}}
|
|
disable_http_challenge
|
|
}
|
|
}
|
|
reverse_proxy server:8080
|
|
}
|
|
|
|
# Port 80 for the server's names is its challenge path and a redirect.
|
|
{{range $i, $n := .ServerNames}}{{if $i}}, {{end}}http://{{$n}}{{end}} {
|
|
handle /.well-known/acme-challenge/* {
|
|
reverse_proxy server:8080
|
|
}
|
|
handle {
|
|
redir https://{host}{uri} 308
|
|
}
|
|
}
|