66 lines
3.3 KiB
Docker
66 lines
3.3 KiB
Docker
# syntax=docker/dockerfile:1
|
|
#
|
|
# Standalone mailgoserver image — SMTP + IMAP + admin dashboard + webmail, no rspamd.
|
|
# The built-in heuristic spam score (internal/mailstore/spam.go) always runs regardless;
|
|
# this is for anyone who doesn't want rspamd's extra dependency. See Dockerfile.rspamd
|
|
# (mailgoserver + rspamd) and Dockerfile.aio (mailgoserver + rspamd + redis, full spam
|
|
# stack) for the bundled variants.
|
|
#
|
|
# Build from the repo root:
|
|
# docker build -f docker-deploy/Dockerfile -t mailgoserver .
|
|
|
|
FROM golang:1.26-bookworm AS build
|
|
WORKDIR /src
|
|
COPY go.mod go.sum ./
|
|
RUN go mod download
|
|
COPY . .
|
|
# modernc.org/sqlite and every other dependency here are pure Go (no cgo), so a fully
|
|
# static binary is just CGO_ENABLED=0 — no libc/gcc needed in the runtime image.
|
|
RUN CGO_ENABLED=0 go build -trimpath -ldflags="-s -w" -o /out/mailgoserver .
|
|
|
|
FROM debian:bookworm-slim
|
|
# ca-certificates: outbound direct-to-MX delivery verifies remote STARTTLS certs.
|
|
# tzdata: [Server] time_zone (e.g. "Europe/London") needs the real IANA zone
|
|
# database — time.LoadLocation silently falls back to UTC without it.
|
|
# curl: used by the HEALTHCHECK below.
|
|
# libcap2-bin: provides setcap, used below so the binary can bind ports 25/465/80
|
|
# without running the process itself as root.
|
|
RUN apt-get update && apt-get install -y --no-install-recommends \
|
|
ca-certificates tzdata curl libcap2-bin \
|
|
&& rm -rf /var/lib/apt/lists/*
|
|
|
|
COPY --from=build /out/mailgoserver /usr/local/bin/mailgoserver
|
|
# CAP_NET_BIND_SERVICE is one of Docker's default capabilities (no --cap-add needed at
|
|
# `docker run`/compose time) — granting it to the binary itself, rather than running the
|
|
# whole container as root, means a bug in mailgoserver can't do anything a root process
|
|
# could that an unprivileged one couldn't, beyond binding these specific low ports.
|
|
RUN setcap 'cap_net_bind_service=+ep' /usr/local/bin/mailgoserver
|
|
|
|
# Everything persistent — settings.ini, the SQLite DB, encrypted mailbox storage,
|
|
# DKIM/mailstore master keys, TLS certs, the app secret — lives under server_data/,
|
|
# relative to wherever the process is started from (see config.Load / main.go's
|
|
# os.Getwd()). One volume covers all of it; no need to enumerate subpaths, and nothing
|
|
# persistent is ever written outside it.
|
|
RUN useradd --system --create-home --home-dir /app --shell /usr/sbin/nologin mailgoserver \
|
|
&& mkdir -p /app/server_data \
|
|
&& chown -R mailgoserver:mailgoserver /app \
|
|
&& chmod 755 /app
|
|
WORKDIR /app
|
|
VOLUME ["/app/server_data"]
|
|
USER mailgoserver
|
|
|
|
# Defaults from internal/config/config.go's generated settings.ini: SMTP 25, direct-TLS
|
|
# SMTP 465, IMAP 143, direct-TLS IMAP 993, admin/webmail HTTP 5000, HTTPS 5001
|
|
# (deliberately non-privileged; put a reverse proxy or the host's own 80/443 in front of
|
|
# those too if you want them there). Port 80 is only actually bound while
|
|
# [LetsEncrypt] challenge_type=http-01 is enabled and an obtain/renew is in flight —
|
|
# harmless to expose even when unused.
|
|
EXPOSE 25 465 143 993 80 5000 5001
|
|
|
|
# --host 0.0.0.0 is required: the binary's own default is 127.0.0.1, which would only
|
|
# be reachable from inside this container, never through a published port.
|
|
HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \
|
|
CMD curl -fs http://127.0.0.1:5000/health || exit 1
|
|
|
|
ENTRYPOINT ["mailgoserver", "--host", "0.0.0.0"]
|