base-trixie: the image on Debian trixie, Postfix 3.10.13; Received: hidden on 465/587
test / test (push) Canceled after 0s
test / test (push) Canceled after 0s
The runtime base is debian:trixie-slim, the build stage golang:1.26-trixie:
Postfix 3.10.13 with upstream's 2026 security fixes up to the August
batch, libmilter 8.18.1, OpenSSL 3.5. Every citation of another program in
code, scripts and documents was re-read against the trixie sources
(dev/upstream; bookworm's kept in dev/upstream-bookworm) and updated;
development.md's cited-package table holds the trixie versions.
What the re-reading changed in behaviour:
- logtail: reject lines with sasl_method/sasl_username/sasl_sender
(smtpd_check.c:1019-1026); cleanup's "removed (canceled)" forgets a
port-25 id (cleanup_api.c:363-364).
- internal/postfix/retry.go reads postconf's stdout only: since 3.9 a
deprecated-parameter warning on stderr made one value too many and the
panel fell back to the compiled-in retry policy.
- logrotate-loop.sh: logrotate 3.22 exits 1 when it ignores a config;
the loop refuses on that output whatever the status.
- postfix-config.sh: cyrus_sasl_config_path set explicitly (bookworm's
07_sasl_config.diff is gone); maillog_file_permissions=0640; mynetworks
explicit; Dockerfile: SYNC_CHROOT= in /etc/default/postfix,
opendkim-tools dropped, openssl named, systemd-standalone-sysusers so
cron does not bring the whole of systemd.
- The selfpost group is 10998, outside the system range 100-999: in
trixie a package took 998 and the build failed (owner's decision:
a conflict-free id, the distribution's own ids untouched). The
entrypoint hands /data back by name when the user or the group differs.
Guide, backup refusal text, help (design commit 68ec8b2), e2e.
- smtpd_hide_client_session=yes on smtps and submission (owner's
decision): Received: names no client, TLS, login or protocol; port 25
keeps the full header. e2e checks both.
- test/upstream/opendkim-probe.sh makes keys with openssl genrsa.
Tests: on the server, make e2e exit 0 (674 s, the image built on trixie),
go vet + go test 27 packages ok. CHANGELOG [Unreleased], guide,
architecture.md, security.md, roadmap.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
+21
-7
@@ -73,6 +73,20 @@ listened on: refused from outside over IPv4 and from the host's public IPv4
|
||||
address; accepted and closed through `127.0.0.1`, the same proxy. IPv6 itself
|
||||
was not probed for this.
|
||||
|
||||
Since `2.7.0` the image runs Postfix 3.10, whose defaults hold every
|
||||
listener - 465 and 587 as well as 25 - to two rules of SMTP: a message ends
|
||||
only at the standard `<CR><LF>.<CR><LF>` (a client that ends DATA with a
|
||||
bare newline waits for a reply that does not come), and a client that sends
|
||||
commands ahead of the server's replies where RFC 2920 does not allow it is
|
||||
answered `554 5.5.0 Error: SMTP protocol synchronization` and disconnected.
|
||||
|
||||
Since `2.7.0` a message sent on 465 or 587 does not tell its recipients
|
||||
where the application runs: the `Received:` header SelfPost adds reads
|
||||
`Received: by mail.example.com (Postfix) id 4AbC12xyz for <...>; <date>`,
|
||||
without the application's address, host name or login. To trace a message
|
||||
someone complains about, take that queue id to *Outbound › Log*; mail.log
|
||||
keeps the client address on smtpd's `client=` line for the same id.
|
||||
|
||||
### Local trial
|
||||
|
||||
The [README quick start](../README.md#quick-start) runs a single container
|
||||
@@ -312,13 +326,13 @@ ln -s /etc/letsencrypt/live/mail.example.com/privkey.pem certs/privkey.pem
|
||||
```
|
||||
|
||||
The panel reads them as its own user (Health shows the certificate, a full
|
||||
backup carries both files), through the container's group 998. certbot's
|
||||
backup carries both files), through the container's group 10998. certbot's
|
||||
documentation gives the way for a server that is not root, and certbot keeps
|
||||
the key's group and mode at every renewal:
|
||||
|
||||
```sh
|
||||
sudo chmod 0755 /etc/letsencrypt/live /etc/letsencrypt/archive
|
||||
sudo chgrp 998 /etc/letsencrypt/archive/mail.example.com/privkey*.pem
|
||||
sudo chgrp 10998 /etc/letsencrypt/archive/mail.example.com/privkey*.pem
|
||||
sudo chmod 0640 /etc/letsencrypt/archive/mail.example.com/privkey*.pem
|
||||
```
|
||||
|
||||
@@ -339,7 +353,7 @@ docker compose -f docker-compose.yml -f nginx/docker-compose.nginx.yml \
|
||||
The fragment mounts certbot's directory into both nginx and SelfPost, at
|
||||
`/etc/letsencrypt`; `./certs` holds two links to
|
||||
`/etc/letsencrypt/live/mail.example.com/` — a path that exists inside the
|
||||
container, not on the host — and the panel reads the key through group 998,
|
||||
container, not on the host — and the panel reads the key through group 10998,
|
||||
as in the Apache case. Then start everything:
|
||||
|
||||
```sh
|
||||
@@ -347,7 +361,7 @@ mkdir certs
|
||||
ln -s /etc/letsencrypt/live/mail.example.com/fullchain.pem certs/fullchain.pem
|
||||
ln -s /etc/letsencrypt/live/mail.example.com/privkey.pem certs/privkey.pem
|
||||
sudo chmod 0755 nginx/certbot-etc/live nginx/certbot-etc/archive
|
||||
sudo chgrp 998 nginx/certbot-etc/archive/mail.example.com/privkey*.pem
|
||||
sudo chgrp 10998 nginx/certbot-etc/archive/mail.example.com/privkey*.pem
|
||||
sudo chmod 0640 nginx/certbot-etc/archive/mail.example.com/privkey*.pem
|
||||
|
||||
docker compose -f docker-compose.yml -f nginx/docker-compose.nginx.yml up -d
|
||||
@@ -714,11 +728,11 @@ instance keeps running, what goes into the archive, and what happens on restore.
|
||||
→ *Full backup*. *Encrypt with a password* is ticked; untick it for a plain
|
||||
archive. Same archive as the CLI below. The panel runs as its own user, not as
|
||||
root, so **the private key in `certs/` has to be readable by it**: give the
|
||||
file to the container's `selfpost` group, which has the fixed id 998 and holds
|
||||
file to the container's `selfpost` group, which has the fixed id 10998 and holds
|
||||
both the panel and Postfix —
|
||||
|
||||
```sh
|
||||
chgrp 998 certs/privkey.pem && chmod 640 certs/privkey.pem
|
||||
chgrp 10998 certs/privkey.pem && chmod 640 certs/privkey.pem
|
||||
```
|
||||
|
||||
— and have whatever renews the certificate do the same; certbot does it by
|
||||
@@ -795,7 +809,7 @@ methods avoid it by stopping first.
|
||||
| SQLite consistency | `VACUUM INTO` snapshot | Safe when stopped | Safe when stopped |
|
||||
| `data/log/` | Excluded | Included (optional exclude) | Included (optional exclude) |
|
||||
| Postfix queue | No | Yes | Yes |
|
||||
| `certs/` private key | Yes (the panel needs it readable by group 998; links are followed) | Yes when `certs/` holds the files; links are stored as links unless `tar -h` | No — deploy files separate |
|
||||
| `certs/` private key | Yes (the panel needs it readable by group 10998; links are followed) | Yes when `certs/` holds the files; links are stored as links unless `tar -h` | No — deploy files separate |
|
||||
| `data/manifest.json` | Written (version stamp) | Absent | Absent |
|
||||
| Restore version check | Yes — must match image tag | No | No |
|
||||
| Post-restore *Resync* | Yes, on first boot | No | No |
|
||||
|
||||
Reference in New Issue
Block a user