50 lines
1.9 KiB
Markdown
50 lines
1.9 KiB
Markdown
|
|
# tailwart edge — layer-4 mail proxy
|
||
|
|
|
||
|
|
A custom Caddy (with the `caddy-l4` app) that pipes the public mail ports to the
|
||
|
|
Stalwart sidecar over the tailnet. Pure TCP pass-through with PROXY protocol —
|
||
|
|
Stalwart still terminates all the TLS. **Runs anywhere** with a public IP that's
|
||
|
|
on the tailnet and tagged `tag:reverse-proxy`; doesn't need to share a host with
|
||
|
|
the mailbox.
|
||
|
|
|
||
|
|
## Why layer 4 and not a normal Caddy vhost
|
||
|
|
|
||
|
|
Web apps reverse-proxy at layer 7 (route by Host/SNI, Caddy terminates TLS).
|
||
|
|
Mail can't: port 25 has no SNI (STARTTLS comes after connect), and you want one
|
||
|
|
global `:25` listener, not per-domain routing. So the edge is a dumb L4 pipe and
|
||
|
|
Stalwart owns the TLS. The novelty you spotted: this is the same `stream`-style
|
||
|
|
proxying nginx/Caddy can do for *any* TCP — it just usually isn't used for it.
|
||
|
|
|
||
|
|
## Build & run
|
||
|
|
|
||
|
|
```bash
|
||
|
|
docker compose up -d --build # builds Dockerfile (xcaddy + caddy-l4), runs it
|
||
|
|
caddy list-modules | grep layer4 # (inside the image) proof the module loaded
|
||
|
|
```
|
||
|
|
|
||
|
|
The build fails loudly if `caddy-l4` isn't in the resulting binary.
|
||
|
|
|
||
|
|
## Edit the upstream
|
||
|
|
|
||
|
|
`caddy.json` dials `stalwart.tail7b1641.ts.net:<port>`. If your
|
||
|
|
`STALWART_MAGIC_NAME` / `TS_TAILNET` differ, update the five `dial` lines. (JSON
|
||
|
|
can't read `.env`; this is the one spot the MagicDNS name is hardcoded — same
|
||
|
|
trade-off as pgAdmin's `servers.json`.)
|
||
|
|
|
||
|
|
## The HTTP side (JMAP / autoconfig / admin) is separate
|
||
|
|
|
||
|
|
That part *is* ordinary layer 7. Don't put it here if this box already runs the
|
||
|
|
main Caddy on :443 — you'll collide. Instead add a vhost to the existing Caddy:
|
||
|
|
|
||
|
|
```caddyfile
|
||
|
|
mail.infinidim.net {
|
||
|
|
reverse_proxy stalwart.tail7b1641.ts.net:8080
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
## Prerequisites on the host running this
|
||
|
|
|
||
|
|
- Joined to the tailnet, tagged `tag:reverse-proxy` (so the ACL lets it reach
|
||
|
|
`tag:stalwart`).
|
||
|
|
- Public firewall opens for whichever mail ports you expose (`25` minimum).
|
||
|
|
- Nothing else bound to those ports.
|