diff --git a/CLAUDE.md b/CLAUDE.md index feeb39e..646bc19 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -33,8 +33,10 @@ compose, config, ACL snippet, and Caddy build, and only *reads from the tailnet* - **Mailbox** (`docker-compose.yml`): Stalwart in a Tailscale sidecar via `network_mode: service:ts-stalwart`. Binds nothing on the host. All mail ports listen on the tailnet only. -- **Edge** (`caddy/`): a layer-4 TCP proxy. Pure pass-through; Stalwart owns - TLS. **Can run on a different machine** than the mailbox — the key idea. +- **Edge** (`caddy/`): a layer-4 TCP proxy (Caddy + `caddy-l4`, pulled prebuilt + from caddyserver.com — no local `xcaddy` build, per `~/docs/caddy.md`). Pure + pass-through; Stalwart owns TLS. **Can run on a different machine** than the + mailbox — the key idea. - **Backends**: data+fts → Postgres, blob → Garage S3, lookup/in-memory → Redis. One stalwart role/db, one Garage bucket, one Redis logical DB. diff --git a/README.md b/README.md index 1da7709..4a038d0 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ 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 -│ ├── Dockerfile # xcaddy build with caddy-l4 + ratelimit +│ ├── Dockerfile # pulls prebuilt caddy-l4 binary (caddyserver.com, no local build) │ ├── 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 diff --git a/caddy/Dockerfile b/caddy/Dockerfile index 2dcf44c..a8fb7a9 100644 --- a/caddy/Dockerfile +++ b/caddy/Dockerfile @@ -1,15 +1,21 @@ -# Custom Caddy with the layer-4 (TCP/UDP) app so it can proxy raw mail ports, -# not just HTTP. caddy-ratelimit is included to match the house build on `box`. +# Caddy with the layer-4 (TCP/UDP) app so it can proxy raw mail ports. +# +# Built the house way (see ~/docs/caddy.md "Custom Binary"): grab the prebuilt +# static binary from caddyserver.com's build server, NOT a local xcaddy/Go +# build. The compile burns ~1GB RAM, which this VPS can't spare — the download +# server does it for us. The base image only contributes its entrypoint + CA +# certs; we swap in the L4-enabled binary over the stock one. # # docker build -t tailwart-caddy ./caddy # -# Pinned to 2.11 to match box's Caddy. Bump deliberately. -FROM caddy:2.11-builder AS build -RUN xcaddy build \ - --with github.com/mholt/caddy-l4 \ - --with github.com/mholt/caddy-ratelimit - +# Add more plugins by appending &p= to CADDY_DOWNLOAD, +# e.g. ...&p=github.com%2Fmholt%2Fcaddy-ratelimit (the main box build has that). FROM caddy:2.11 -COPY --from=build /usr/bin/caddy /usr/bin/caddy -# Proof the L4 module is in the binary (fails the build if not): -RUN caddy list-modules | grep -q 'layer4' || (echo 'caddy-l4 missing!' && exit 1) + +ARG CADDY_DOWNLOAD="https://caddyserver.com/api/download?os=linux&arch=amd64&p=github.com%2Fmholt%2Fcaddy-l4" + +RUN apk add --no-cache curl \ + && curl -fsSL -o /usr/bin/caddy "$CADDY_DOWNLOAD" \ + && chmod 0755 /usr/bin/caddy +# Fail the build loudly if the L4 module isn't actually in the binary. +RUN caddy list-modules | grep -q 'layer4' || { echo 'caddy-l4 missing from binary!'; exit 1; } diff --git a/caddy/README.md b/caddy/README.md index 02dc7a6..749e5a8 100644 --- a/caddy/README.md +++ b/caddy/README.md @@ -17,11 +17,15 @@ 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 +docker compose up -d --build # builds the image, runs it ``` -The build fails loudly if `caddy-l4` isn't in the resulting binary. +The Dockerfile doesn't compile Caddy — it pulls the prebuilt L4-enabled binary +from `caddyserver.com/api/download` (the house method, see `~/docs/caddy.md` +"Custom Binary"), dodging the ~1GB-RAM local `xcaddy` build this VPS can't +afford. The build still fails loudly if `caddy-l4` isn't in the downloaded +binary. To add plugins, append `&p=` to +`CADDY_DOWNLOAD` in the Dockerfile. ## Edit the upstream