main
6 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
8f15646cf0 |
Add Tab completion to mailctl
The command tree lives in Go, in complete.go, next to the commands it describes: the hidden __complete subcommand is handed the words typed so far and answers with what may follow the last of them. The zsh function installed alongside the binary does nothing but pass the line in and hand the answer back, so it needs no change when a command is added, and it cannot describe a grammar the tool no longer has. Two rules hold throughout: - Completion never writes. It reads through completeValues, which opens the database read-only, and not through openDB, which would create it from schema.sql and run migrate() on every call. Checked: after repeated completions the mtime and size of mail.db are unchanged and no -wal or -shm file appears beside it. - Completion never fails out loud. Every error ends as an empty list, and __complete is dispatched before the root check, so as an unprivileged user the structure still completes, the values stay empty, nothing reaches stderr and the status is 0. The values come out of the database, so only what exists is offered: `user enable` lists the locked mailboxes and `user disable` the unlocked ones, `alias del <source>` only the targets of that alias, `sieve edit <address>` that mailbox's scripts via doveadm, and `lang allow` the languages Rspamd has a model for, minus those already on the line. For a path argument the answer is the single line ":files", which hands over to zsh's own file completion. Narrowing the answer down to what has been typed is left to the shell rather than done in Go, so that the matcher-list styles keep working - completing "MARTIN@" to "martin@example.com" is zsh's business, and a filter here would defeat it. Two details on the shell side are worth recording, both found by driving a real interactive zsh through a pseudo-terminal rather than by reading: - The binary is located with `whence -p mailctl`, not through $commands. That parameter is not populated inside a completion function, so the lookup yields nothing and every candidate list silently comes back empty. - zsh writes "--" between a value and its description. The function sets list-separator to a single hyphen, scoped to mailctl's own context so no other completion changes, and only when nothing has been set for it already. `make install` now also puts the function in /usr/local/share/zsh/site-functions. The installer needs no change for it: stage 8 already builds through `make install`. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
||
|
|
420831dd43 |
Document ARM support
arm64 needs no change to anything here, and the claim is backed by checks rather than assumption: - mailctl was cross-compiled for linux/arm64 and linux/arm - both produce a statically linked binary. modernc.org/sqlite ships code for linux_arm64, linux_arm, linux_riscv64, linux_ppc64le and s390x, and with CGO_ENABLED=0 there is nothing else to worry about. - Every package is built for arm64 in Debian 13, including golang-go at 1.24 - exactly the version go.mod asks for. fail2ban and certbot are Architecture: all. - Regex acceleration survives: the amd64 rspamd package depends on libhyperscan5, the arm64 one on libvectorscan5, the ARM port of the same library. This setup leans on regexes for the block, allow and language filters, so that mattered. armhf is documented as possible but not advisable: the armhf rspamd package depends on neither, so every expression falls back to PCRE. The real constraint is memory, not the instruction set. Rspamd holds around 510 MB resident in normal operation here, which rules out 1 GB boards whatever their architecture. Measured figures are in the table. Also noted that Maildir means one file per message - over 20,000 on this server - which is the wrong workload for an SD card. The only hardcoded path in the installer, /usr/lib/go-1.24/bin/go, is a fallback behind "command -v go" and is the same on every Debian architecture. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
||
|
|
e09f7618f6 |
Document the ports needed when the host is behind a firewall
New section 2 in docs/installation.md, split into inbound and outbound, because the outbound half is the one that gets forgotten. Inbound is the easy part and matches the nftables ruleset exactly: 25, 465/587, 993/143, 80, 4190 and the SSH port. Noted that port 80 is not needed for mail and therefore tends to get closed again after the installation - two months later the certificate renewal fails quietly. DNS-01 is the way out if it cannot stay open. Outbound: 25 for sending, 443 and 80 for Rspamd maps, certificates, packages and the Go build, UDP 11335 for fuzzy hashes, UDP 123 for the clock. And DNS on UDP *and* TCP 53 - TCP matters because DNSSEC answers are large and get truncated, which produces intermittent resolution failures that are hard to place. The trap gets its own block: unbound here is a full resolver and asks the root and authoritative servers directly. Corporate firewalls routinely permit DNS to the internal resolver only. That does not break the setup outright, it breaks it silently - DNSBL operators refuse queries from shared resolvers, and a blocklist that answers nothing looks exactly like a clean sender. The forward-zone workaround is documented together with what it costs. Also documented: behind NAT the A record must name the DNAT address and the PTR the SNAT address. If they differ, receiving works while sending fails on PTR and SPF - a miserable diagnosis, because mail arrives fine. Every verification command in the section was run on the live server first. Two matching entries in operations.md troubleshooting, for "mail arrives but nothing goes out" and for blocklists going quiet. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
||
|
|
2b84a8a493 |
Everything in English: documentation, comments, identifiers
The user works in German but wants the artefacts in English throughout.
Translated were roughly 1,500 lines: every comment in the configuration
files, all comments in the Go sources, both shell scripts, and the three
manuals.
Renamed along with it, so nothing is left half-translated:
- install/vorlagen-pruefen -> install/verify-templates
- install/mailserver.conf.beispiel -> install/mailserver.conf.example
- docs/betrieb.md -> docs/operations.md
- shell functions and variables (schritt/abbruch/einsetzen/ZIEL/BEHALTEN
-> stage/die/deploy/DEST/KEEP), the ten installer stages, the Dovecot
quota root "Postfach" -> "Mailbox" and the sieve_script names
lernspam/lernham -> learnspam/learnham
- the comment headers that mailctl writes into the generated map files
Two things this dug up while translating:
- Perl treats $) and $/ as variables. A careless s{}{} put a NUL byte into
the regular expression documented in lang.go and mangled a line in
list.go. Both repaired; the sources were checked for NUL bytes and the
generated maps compared against the previous ones - the expressions
themselves are unchanged.
- The map files are only rewritten on a change, so their German headers
survived the first pass. Regenerated and verified line by line.
The origin server was brought along in the same step: configuration
deployed, Sieve scripts recompiled, mailctl rebuilt, services reloaded,
maps regenerated. Checked afterwards: postfix check, doveconf -n,
nft -c, unbound-checkconf, rspamadm configtest all pass; block list and
language filter still fire; a test message went through the full chain
into the mailbox. install/verify-templates reports 37 files identical,
no differences at all.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
||
|
|
e6ce180bf1 |
Ursprungsserver angeglichen, Dokumentation nur noch hier
Der Server, aus dem diese Anlage stammt, laeuft jetzt mit genau diesen Dateien: portables mailctl aus /etc/mailserver/server.conf, verbessertes mailbackup, angeglichene Kopfzeilen. install/vorlagen-pruefen meldet 37 Dateien identisch, keine Abweichung. Die Dokumentation wird ab jetzt ausschliesslich in diesem Repository gepflegt. Auf dem Server liegt unter /etc/mailserver/README.md nur noch ein Verweis darauf, mit den paar Befehlen, die man beim Anmelden sofort braucht - der Installer legt ihn aus config/mailserver/README.md an. Ausserdem: - mailbackup sichert /etc/mailserver/server.conf mit. Ohne sie weiss eine Wiederherstellung nicht, fuer welchen Namen die Zertifikate galten und welche Adresse in die DNS-Empfehlungen gehoert. Die Aufraeumlogik ist gegen 35 Sicherungen und gegen ein leeres Verzeichnis geprueft, unter /bin/sh, nicht nur unter zsh. - betrieb.md erklaert server.conf und was passiert, wenn sie fehlt: mailctl raet dann ueber /etc/mailname und die Route nach aussen und weist in "mailctl dns" sichtbar darauf hin. Hinter NAT ist der geratene Wert immer falsch. - Spaltenausrichtung des A-Eintrags in "mailctl dns" berichtigt. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
||
|
|
c9e5494992 |
Mailserver: Konfiguration, Installationsskript und Anleitung
Der vollstaendige Aufbau eines Mailservers auf Debian 13, herausgezogen aus einer laufenden Anlage: Postfix mit postscreen und DANE, Dovecot 2.4 mit Maildir, Sieve und Kontingenten, Rspamd als Milter mit Bayes, Greylisting und DKIM, dazu Redis, unbound, nftables, fail2ban und certbot. Domains, Postfaecher, Aliases und Absenderlisten liegen in einer SQLite-Datei, die Postfix und Dovecot direkt lesen. install/mailserver-install fuehrt das in zehn wiederholbaren Stufen aus. Jede Stufe laesst sich einzeln nachholen; ersetzte Dateien werden vorher gesichert. Die riskanteste Stelle - die Firewall - prueft vorher, ob auf dem angegebenen Port wirklich ein sshd lauscht, weil eine falsche Nummer die laufende Sitzung aussperren wuerde. install/vorlagen-pruefen vergleicht die Vorlagen mit dem, was auf einem Server tatsaechlich laeuft. Gegen den Ursprungsserver gepruefte Bilanz: 30 Dateien Byte fuer Byte gleich, 5 Abweichungen nur in Kommentaren. mailctl ist portabel gemacht: Servername, Adresse und Zertifikatspfad standen fest im Quelltext und kommen jetzt aus /etc/mailserver/server.conf, mit Rueckfallebene ueber /etc/mailname und die Route nach aussen. Die Go-Abhaengigkeiten sind auf Fassungen zurueckgezogen, die mit dem Go aus Debian 13 uebersetzen - vorher verlangte go.mod eine Toolchain, die sich Go im Hintergrund nachgeladen hat. Kommentare deutsch, Benutzerfuehrung englisch. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |