Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,22 @@ Please read our [deployment documentation](https://shroud.email/docs/deployment/

If you just want to get up and running with Shroud.email quickly, you can sign up for our hosted version [here](https://app.shroud.email/users/register).

Copy `haraka/haraka_config/config/me.example` to `haraka/haraka_config/config/me` and set your mail hostname.

## TLS via Bunny DNS-01 (optional)

Caddy defaults to HTTP-01 ACME (port 80), which works behind no other reverse
proxy. If your setup needs DNS-01 (e.g. you can't open port 80, or you want
wildcard certs), opt in to the Bunny.net DNS challenge:

1. Set `BUNNY_API_KEY` in `.env` to your Bunny.net account API key.
2. Set `CADDYFILE_PATH=./caddy/Caddyfile.bunny` in `.env`.
3. `docker compose up -d --build caddy`.

The Caddy binary is built locally (see `caddy/Dockerfile`) with both the
`caddy-permissive-file-storage` and `caddy-dns/bunny` modules. Self-hosters who
leave the defaults get HTTP-01 and never need a Bunny key.

## Living on the edge

The committed `docker-compose.yaml` tracks the stable `:1` image. If you'd rather
Expand Down
21 changes: 21 additions & 0 deletions caddy/Caddyfile.bunny
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
# Global options
storage permissive_file_storage {
root "/data"
}

email {$ADMIN_EMAIL}
}

{$APP_DOMAIN} {
reverse_proxy web:8080
tls {
dns bunny {env.BUNNY_API_KEY}
}
}

{$EMAIL_DOMAIN} {
tls {
issuer acme
}
}
14 changes: 14 additions & 0 deletions caddy/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# Compile Caddy with custom modules.
# - caddy-permissive-file-storage: world-readable certs so the cron
# sidecar can bundle them for Haraka (the whole reason this fork exists).
# - caddy-dns/bunny: DNS-01 ACME via Bunny.net, opt-in via Caddyfile.bunny.
FROM caddy:2.10-builder AS builder

RUN xcaddy build v2.10.0 \
--with github.com/Shroud-email/caddy-permissive-file-storage@main \

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: Build reproducibility and supply-chain risk: pinning to @main instead of a specific commit hash makes the build non-deterministic. Every docker compose up --build caddy run pulls whatever is latest on the upstream main branch at that moment, so two builds at different times may produce different Caddy binaries — and any push to that repo's main (even an accidental force-push or a future incompatible change) could silently break the build for all self-hosters. The previous pin to commit 4059a602 was more robust. Consider restoring a commit-hash pin and keeping the explicit Replace with @v0.1.5 reminder, so there is a stable known-good point while awaiting the release.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At caddy/Dockerfile, line 14:

<comment>Build reproducibility and supply-chain risk: pinning to `@main` instead of a specific commit hash makes the build non-deterministic. Every `docker compose up --build caddy` run pulls whatever is latest on the upstream `main` branch at that moment, so two builds at different times may produce different Caddy binaries — and any push to that repo's `main` (even an accidental force-push or a future incompatible change) could silently break the build for all self-hosters. The previous pin to commit `4059a602` was more robust. Consider restoring a commit-hash pin and keeping the explicit `Replace with @v0.1.5` reminder, so there is a stable known-good point while awaiting the release.</comment>

<file context>
@@ -4,14 +4,14 @@
 
 RUN xcaddy build v2.10.0 \
-    --with github.com/Shroud-email/caddy-permissive-file-storage@4059a602db55a1762de165dac7f1204c823ebbd4 \
+    --with github.com/Shroud-email/caddy-permissive-file-storage@main \
     --with github.com/caddy-dns/bunny@v1.2.0
 
</file context>
Suggested change
--with github.com/Shroud-email/caddy-permissive-file-storage@main \
--with github.com/Shroud-email/caddy-permissive-file-storage@4059a602db55a1762de165dac7f1204c823ebbd4 \

--with github.com/caddy-dns/bunny@v1.2.0

# Production image
FROM caddy:2.10-alpine

COPY --from=builder /usr/bin/caddy /usr/bin/caddy
1 change: 1 addition & 0 deletions docker-compose.override.example.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,4 @@ services:
- WATCHTOWER_LABEL_ENABLE=true # ONLY update opted-in containers — never db
- WATCHTOWER_POLL_INTERVAL=300 # poll GHCR every 5 min
- WATCHTOWER_CLEANUP=true # delete old images after updating
- DOCKER_API_VERSION=1.44 # watchtower 1.7.1's SDK defaults to 1.25, too old for Docker Engine 28+
7 changes: 5 additions & 2 deletions docker-compose.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -74,20 +74,23 @@ services:
- S3_HOST=${S3_HOST}
- LOOPS_API_KEY=${LOOPS_API_KEY}
- LOOPS_ACTIVE_USERS_LIST_ID=${LOOPS_ACTIVE_USERS_LIST_ID}
- CHATWOOT_MAC_TOKEN=${CHATWOOT_MAC_TOKEN}
- CHATWOOT_BASE_URL=${CHATWOOT_BASE_URL}

caddy:
image: ghcr.io/shroud-email/caddy-permissive-file-storage:main
build: ./caddy
restart: unless-stopped
environment:
- ADMIN_EMAIL=${ADMIN_EMAIL}
- APP_DOMAIN=${APP_DOMAIN}
- EMAIL_DOMAIN=${EMAIL_DOMAIN}
- BUNNY_API_KEY=${BUNNY_API_KEY}
ports:
- "80:80"
- "443:443"
volumes:
- caddy_data:/data
- ./caddy/Caddyfile:/etc/caddy/Caddyfile
- ${CADDYFILE_PATH:-./caddy/Caddyfile}:/etc/caddy/Caddyfile

cron:
build: ./cron
Expand Down
16 changes: 16 additions & 0 deletions example.env
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,22 @@ AWS_SECRET_ACCESS_KEY=replace
S3_BUCKET=replace
S3_HOST=replace

# CHATWOOT_MAC_TOKEN / CHATWOOT_BASE_URL: optional, for Chatwoot support
# auth on the hosted app. Leave blank if unused.
CHATWOOT_MAC_TOKEN=
CHATWOOT_BASE_URL=

# BUNNY_API_KEY: optional. Bunny.net API key for DNS-01 ACME TLS issuance in
# Caddy. Only used if you opt in by setting CADDYFILE_PATH to
# ./caddy/Caddyfile.bunny below. Leave blank to keep the default HTTP-01.
BUNNY_API_KEY=

# CADDYFILE_PATH: optional. Path to the Caddyfile to mount into the caddy
# container. Defaults to ./caddy/Caddyfile (HTTP-01). Set to
# ./caddy/Caddyfile.bunny to use DNS-01 via Bunny (requires BUNNY_API_KEY).
# Self-hosters can leave the default.
CADDYFILE_PATH=./caddy/Caddyfile

## You can leave the defaults for the remaining options.

DB_USER=postgres
Expand Down
1 change: 0 additions & 1 deletion haraka/haraka_config/config/me

This file was deleted.

1 change: 1 addition & 0 deletions haraka/haraka_config/config/me.example
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
example.com
Loading