2026-06-03 22:25:38 -04:00
|
|
|
|
# tailwart
|
|
|
|
|
|
|
|
|
|
|
|
> Tailscale × Stalwart. A mailbox with no WAN presence, fronted by a layer-4
|
|
|
|
|
|
> proxy that can live on another machine entirely.
|
|
|
|
|
|
|
|
|
|
|
|
A deliberately over-engineered playground: [Stalwart](https://github.com/stalwartlabs/stalwart)
|
|
|
|
|
|
mail server wired into **Postgres + Redis + Garage S3** at once, deployed as a
|
|
|
|
|
|
Tailscale sidecar, with a separate `caddy-l4` edge that pipes the raw mail ports
|
|
|
|
|
|
over the tailnet. For `infinidim.net`.
|
|
|
|
|
|
|
|
|
|
|
|
See [CLAUDE.md](./CLAUDE.md) for the architecture and the gotchas.
|
|
|
|
|
|
|
|
|
|
|
|
## Layout
|
|
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
tailwart/
|
|
|
|
|
|
├── docker-compose.yml # the mailbox: ts-stalwart sidecar + stalwart
|
|
|
|
|
|
├── config/config.toml # Stalwart config — PG + Redis + S3 wiring (strawman)
|
|
|
|
|
|
├── caddy/ # the edge: custom Caddy (caddy-l4) layer-4 mail proxy
|
2026-06-03 22:39:33 -04:00
|
|
|
|
│ ├── Dockerfile # pulls prebuilt caddy-l4 binary (caddyserver.com, no local build)
|
2026-06-03 22:25:38 -04:00
|
|
|
|
│ ├── caddy.json # :25/465/587/143/993 → stalwart over the tailnet
|
|
|
|
|
|
│ ├── docker-compose.yml # deploy on any public-IP, tailnet, tag:reverse-proxy host
|
|
|
|
|
|
│ └── README.md
|
|
|
|
|
|
├── acl-snippet.hujson # tag:stalwart owner + grants to merge into your policy
|
|
|
|
|
|
├── .env.example # operator surface — copy to .env
|
|
|
|
|
|
└── .gitignore
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
## Quickstart
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
cp .env.example .env && $EDITOR .env # fill secrets (see CLAUDE.md prereqs)
|
|
|
|
|
|
|
|
|
|
|
|
# 1. create the stalwart role/db in shared Postgres + the Garage bucket
|
|
|
|
|
|
# (one-off; see CLAUDE.md "Prerequisites")
|
|
|
|
|
|
# 2. admin console: assign tag:stalwart to the OAuth client + paste acl-snippet
|
|
|
|
|
|
# 3. bring up the mailbox (tailnet-only)
|
|
|
|
|
|
docker compose up -d
|
|
|
|
|
|
# 4. bring up the edge (binds public mail ports; can be a different host)
|
|
|
|
|
|
cd caddy && docker compose up -d --build
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
Then point `infinidim.net`'s MX at the edge host, add SPF/DKIM/DMARC, and finish
|
|
|
|
|
|
configuration in Stalwart's web admin (`mail.infinidim.net`).
|
|
|
|
|
|
|
|
|
|
|
|
## Status
|
|
|
|
|
|
|
|
|
|
|
|
Scaffold / strawman. The Stalwart `config.toml` keys need verifying against a
|
|
|
|
|
|
pinned image version before first real boot — treat it as a starting shape, not
|
|
|
|
|
|
a turnkey config.
|