health-setup-checks: the certificate's name, Postfix's greeting, the proxy
Decided by the owner on 2026-10-13 (in place of preflight), taken up on 2026-10-16; mockupsb2dcefc,cc33890,0feaa55(his: the greeting on a row of its own, the name check a tag beside Names). - The certificate: health.Certificate keeps its names (DNS names, or the CN without any) and ForHost holds it to SELFPOST_HOSTNAME as a TLS client does - VerifyHostname over the DNS names, the CN only without any, as OpenSSL's X509_check_host and so a sending Postfix still take it (src/tls/tls_client.c:439, 513). A certificate for another name fails; the tag beside Names says matches / not for the hostname. - The greeting: postconf -x -h smtpd_banner, read once at the panel's start like the served certificate's path (main.cf is not rewritten after), is what smtpd writes after "220 " (src/smtpd/smtpd.c:5979). A first word other than the hostname warns, with what to set. A fact may now take the whole row (Fact.Wide, sp-wide) and carry a tag beside its label (Fact.LabelTag); both on the kit page. - The proxy: auth.Module.Seen says the address the panel counts sign-ins against, the peer, and whether X-Forwarded-For was read or left unread for an untrusted peer; the Configuration card shows "Your address" and, in the second case, warns that every visitor shares one sign-in limit and names the /32 (or /128) to put in TRUSTED_PROXY_CIDR. Tests: TestCertificateForHost (CN-only, DNS names, a wildcard, the CN ignored beside DNS names), TestSeenAddress, TestHealthSaysWhereItSeesTheViewer, TestHealthGreetingAndCertificateName; e2e reads the stand's right state on Health (matches, "220 mail.e2e.test ESMTP", a direct client). go vet + go test (26 packages) and make e2e on the test server for this tree. Docs: help (word for word with the mockup), guide § Overview and Health, CHANGELOG [Unreleased] § Added, roadmap row done. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -2,6 +2,7 @@ package view
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
@@ -53,6 +54,38 @@ type Health struct {
|
||||
|
||||
Configuration Box
|
||||
Reload Action
|
||||
// ConfigFacts is the address the panel sees the viewer at
|
||||
// (WithClientAddress); ConfigProblem says what to do when it is the
|
||||
// reverse proxy's own.
|
||||
ConfigFacts []Fact
|
||||
ConfigProblem Text
|
||||
}
|
||||
|
||||
// WithClientAddress says where the panel sees the viewer's request from:
|
||||
// client is the address it counts sign-ins against, peer the connection's,
|
||||
// fromHeader that client came from X-Forwarded-For of a trusted proxy, and
|
||||
// ignored that the header was there but peer is no trusted proxy - then
|
||||
// every visitor has the proxy's address and shares one sign-in limit, which
|
||||
// nothing else shows (auth.Module.Seen; guide § TRUSTED_PROXY_CIDR).
|
||||
func (h *Health) WithClientAddress(client, peer string, fromHeader, ignored bool) *Health {
|
||||
f := Fact{Label: "Your address", Value: Plain(client), Mono: true}
|
||||
switch {
|
||||
case fromHeader:
|
||||
f.Note = Plain("From X-Forwarded-For, which the trusted proxy " + peer + " set")
|
||||
case ignored:
|
||||
f.Note = Plain("The proxy's own: its X-Forwarded-For is not read")
|
||||
mask := "/32"
|
||||
if strings.Contains(peer, ":") {
|
||||
mask = "/128"
|
||||
}
|
||||
h.ConfigProblem = Rich("Every visitor reaches the panel as ", Mono(peer),
|
||||
", the reverse proxy, and they all share one sign-in limit. Set ", Code("TRUSTED_PROXY_CIDR"),
|
||||
" to ", Code(peer+mask), " - or the proxy's network - and restart the container.")
|
||||
default:
|
||||
f.Note = Plain("The connection's own; no proxy in between said otherwise")
|
||||
}
|
||||
h.ConfigFacts = []Fact{f}
|
||||
return h
|
||||
}
|
||||
|
||||
// SenderCheckRow is one period of the Sender check table.
|
||||
|
||||
Reference in New Issue
Block a user