openbsd-mailstack is a public, operator-focused framework for building and maintaining a hardened OpenBSD 7.9 mail platform.
It publishes reusable documentation, configuration examples, phase scripts, maintenance helpers, and staged rendered assets for a single-host mail system built around:
- Postfix
- Dovecot
- Rspamd
- Roundcube
- PostfixAdmin
- MariaDB
- Redis
- ClamAV and FreshClam
- PF, WireGuard, DNS, and DDNS
It also includes public-safe operational layers for QEMU validation, autonomous install preparation, backup and recovery, monitoring, maintenance, security hardening, runtime secret handling, and optional Suricata, Brevo, SOGo, and SBOM workflows.
This repository is public by design.
It is not a literal mirror of the private openbsd-self-hosting repository. It publishes only deliberately sanitized production observations, never raw evidence, secrets, restore archives, or site-specific control-plane doctrine.
It is a materially complete public-safe baseline for building the same class of OpenBSD mail server with operator-supplied:
- domains and hostnames
- network and exposure values
- provider accounts and API credentials
- host-local runtime secrets and private keys
- final hardening and exposure choices
Read these in order:
- Project status
- Phase crosswalk
- Documentation map
- Install guide
- Architecture and flow
- Observed production and OSMAP integration
- Quick start and usage paths
- Install order and phase sequence
- Public repo readiness check
- Targeted public hardening validation pass
- Security hardening and runtime secrets
Use these sections as the main navigation layer:
- Install docs
- Phase docs
- Operator docs
- Architecture docs
- Configuration wiring
- Project status and boundaries
- OpenBSD 7.9 maintenance runbook
The public repository now contains:
- phase documentation and apply and verify scripts through Phase 17
- a core runtime rendering path for mail, web, filtering, and SQL services
- QEMU lab and autonomous installer tooling
- tracked config examples and ignored local input paths
- backup, disaster recovery, monitoring, maintenance, and network exposure helpers
- public-safe hardening and runtime secret layout helpers
- optional Suricata, Brevo, SOGo, and SBOM layers
- tracked sanitized rendered examples under
services/generated/rootfs/ - gitignored live operator render workspaces under
.work/, including.work/runtime/rootfs/,.work/network-exposure/rootfs/,.work/identity/,.work/advanced/, and.work/operations/ - operator-local SBOM and host inventory reports under
.work/advanced/sbom/, with core runtime secret-bearing files forced to mode0600during render and install
With operator-provided data and external account setup, a new operator can use the public repository to:
- create local input files and provider credential files
- render the live core runtime and review
.work/runtime/rootfs/ - render network exposure, identity, or advanced optional layers only into the gitignored
.work/paths - validate the baseline in QEMU
- apply and verify the phased deployment path on a real OpenBSD host
- run post-install checks, generate live operations plan packs under
.work/operations/, and use maintenance and backup workflows - add optional advanced layers only when the base system is stable
Tracked examples live under config/.
The most important examples are:
config/system.conf.exampleconfig/network.conf.exampleconfig/domains.conf.exampleconfig/secrets.conf.exampleconfig/security.conf.exampleconfig/secrets-runtime.conf.exampleconfig/dns.conf.exampleconfig/ddns.conf.exampleconfig/backup.conf.exampleconfig/monitoring.conf.exampleconfig/maintenance.conf.example
Real values belong in ignored local files such as:
config/local/*.conf/root/.config/openbsd-mailstack/*.conf- provider-specific ignored env files documented in the install docs
See:
The public repository still intentionally excludes:
- raw production evidence and operational telemetry from the private deployment
- encrypted recovery payloads and private restore archives
- real API keys, PATs, passwords, private keys, and runtime secret values
- site-specific control-plane doctrine and private automation overlays
- provider-specific integrations beyond the published public-safe set
Those are design boundaries, not undocumented defects.
Useful commands after the repository is populated with local inputs. The install helper also rebuilds the required Postfix hash: maps for sasl_passwd and tls_policy inside the target root so fresh installs do not depend on a separate manual postmap step:
./scripts/install/render-core-runtime-configs.ksh
./scripts/install/run-phase-sequence.ksh --phase-start 0 --phase-end 10
./scripts/verify/run-post-install-checks.ksh
./scripts/verify/verify-rendered-config-integrity.ksh
./scripts/verify/verify-host-service-integrity.ksh
./scripts/verify/verify-documentation-integrity.ksh
./scripts/verify/verify-lab-assets.ksh
./scripts/verify/verify-autonomous-installer-assets.ksh
./maint/validate-public-hardening-surface.ksh
./maint/production-regression.ksh --repo-only
./scripts/verify/run-repo-ci-gates.kshThe repository now includes a GitHub Actions workflow that runs repo-only validation on push and pull request for main.
The local helper used by that workflow is:
./scripts/verify/run-repo-ci-gates.kshIt renders live test output into temporary gitignored paths, validates the repo semantic checks, and exercises the public-safe render and phase surfaces that can be proven without a live OpenBSD host.
SECURITY.mdfor reporting security issuesCONTRIBUTING.mdfor contribution expectations
Use the repository issue templates for bugs, documentation gaps, and operator validation reports. Do not post secrets, private keys, tokens, or sensitive host details in public issues. Use the repository security policy for sensitive disclosures.