4 Commits
Author SHA1 Message Date
jcoffey-dev c6190d21ca Merge pull request 'Document installing from the registry' (#2) from readme-registry into main
Reviewed-on: #2
2026-09-24 19:49:42 +00:00
jcoffey-dev d8c84aae70 Document installing from the registry
Covers the published amd64/arm64 image with Compose and with plain
docker run, when to build your own instead, and fetching
egress-lockdown.sh on its own.
2026-09-24 12:49:10 -07:00
jcoffey-dev 9f189a86b5 Merge pull request 'Build multi-arch images for amd64 and arm64' (#1) from multi-arch into main
Reviewed-on: #1
2026-09-24 19:47:01 +00:00
jcoffey-dev 8a201db412 Build multi-arch images for amd64 and arm64
The build stage runs on the build platform and cross-compiles for the
target, so arm64 needs no emulation. The configuration check runs a
native build, since the target binary may not run on the builder.
2026-09-24 12:45:47 -07:00
2 changed files with 70 additions and 6 deletions
+12 -5
View File
@@ -37,20 +37,27 @@ ARG MAX_CONNECTIONS="100"
# ---------------------------------------------------------------------------
FROM golang:1.27-alpine AS build
# The compiler always runs natively and cross-compiles for the target
# platform, so an arm64 image builds without emulation.
FROM --platform=$BUILDPLATFORM golang:1.27-alpine AS build
ARG ALLOWED_DOMAINS ALLOWED_NETWORKS SMTP_HOSTNAME SMTP_PORT MAX_MESSAGE_SIZE MAX_RECIPIENTS MAX_CONNECTIONS
ARG TARGETOS TARGETARCH
WORKDIR /src
COPY go.mod main.go ./
RUN CGO_ENABLED=0 go build -trimpath -o /mailsink -ldflags "-s -w \
RUN set -e; \
ldflags="-s -w \
-X 'main.allowedDomains=${ALLOWED_DOMAINS}' \
-X 'main.allowedNetworks=${ALLOWED_NETWORKS}' \
-X 'main.hostname=${SMTP_HOSTNAME}' \
-X 'main.port=${SMTP_PORT}' \
-X 'main.maxMessageSize=${MAX_MESSAGE_SIZE}' \
-X 'main.maxRecipients=${MAX_RECIPIENTS}' \
-X 'main.maxConnections=${MAX_CONNECTIONS}'" . \
# Fail the build on a bad setting rather than at container start.
&& /mailsink -check
-X 'main.maxConnections=${MAX_CONNECTIONS}'"; \
# Fail the build on a bad setting rather than at container start. The
# check runs a native build, since the target binary may not run here.
CGO_ENABLED=0 go build -trimpath -o /tmp/check -ldflags "$ldflags" .; \
/tmp/check -check; \
CGO_ENABLED=0 GOOS=$TARGETOS GOARCH=$TARGETARCH go build -trimpath -o /mailsink -ldflags "$ldflags" .
# The runtime image holds the one static binary and nothing else: no shell,
# no MTA, no mail spool, no network tools.
+58 -1
View File
@@ -33,13 +33,70 @@ a setting, edit the Dockerfile and rebuild. A bad value fails the build.
| `MAX_RECIPIENTS` | `100` |
| `MAX_CONNECTIONS` | `100` |
## Run
## Install
### From the registry
Images for amd64 and arm64 are published at
`registry.coffeylabs.org/jcoffey-dev/mailsink`. No login is needed to pull
them. The tag `latest` follows `main`, and each build is also tagged with its
short commit hash.
The published image uses the default settings above. If those fit your test
network, use it as it is. Otherwise build your own (see below), since the
settings are compiled in and can't be changed when the container starts.
With Compose, take `compose.yaml` from this repository and replace the
`build: .` and `image:` lines with:
```yaml
image: registry.coffeylabs.org/jcoffey-dev/mailsink:latest
```
Then:
```sh
docker compose up -d
sudo ./egress-lockdown.sh # optional second layer; see below
```
Without Compose:
```sh
docker network create -o com.docker.network.bridge.name=br-mailsink mailsink
docker run -d --name mailsink --restart unless-stopped \
--network mailsink -p 25:25 \
--read-only --cap-drop ALL --security-opt no-new-privileges:true \
--log-driver none \
registry.coffeylabs.org/jcoffey-dev/mailsink:latest
```
`egress-lockdown.sh` finds the container by its bridge name, `br-mailsink`,
so keep that name if you use the script. To fetch just the script:
```sh
curl -fsSLO https://git.coffeylabs.org/jcoffey-dev/mailsink/raw/branch/main/egress-lockdown.sh
chmod +x egress-lockdown.sh
```
### Build your own
Clone the repository, change the settings at the top of the `Dockerfile`, then:
```sh
docker compose up -d --build
sudo ./egress-lockdown.sh # optional second layer; see below
```
The Dockerfile cross-compiles, so one build covers amd64 and arm64 without
emulation:
```sh
docker buildx build --platform linux/amd64,linux/arm64 -t mailsink .
```
## Use
Point applications at the Docker host on port 25. Any username and password
are accepted, so apps configured for authenticated SMTP work unchanged. There
is no TLS: clients must allow a plaintext connection.