# syntax=docker/dockerfile:1 # # SelfPost — single Debian-slim image running postfix + opendkim + panel under # supervisord (spec 4). Build from the repository root: # # docker build -f build/Dockerfile -t selfpost:dev --build-arg VERSION=dev . # ---- build stage ------------------------------------------------------------- FROM golang:1.26-bookworm AS build WORKDIR /src # Version stamped into both binaries; MUST match the image tag (spec 7.5.A). ARG VERSION=dev # Module metadata first for layer caching. go.sum arrived in Phase 2 with the # SQLite driver and bcrypt. COPY go.mod go.sum ./ RUN go mod download COPY cmd ./cmd COPY internal ./internal ENV CGO_ENABLED=0 RUN go vet ./... \ && go build -trimpath \ -ldflags "-X codeberg.org/mix/selfpost/internal/buildinfo.Version=${VERSION}" \ -o /out/panel ./cmd/panel \ && go build -trimpath \ -ldflags "-X codeberg.org/mix/selfpost/internal/buildinfo.Version=${VERSION}" \ -o /out/selfpost-backup ./cmd/selfpost-backup # ---- runtime stage ----------------------------------------------------------- FROM debian:bookworm-slim AS runtime ENV DEBIAN_FRONTEND=noninteractive # Preseed Postfix so its install is non-interactive and yields a working # main.cf. The real relay configuration is generated by the panel in Phase 5. RUN echo "postfix postfix/mailname string localhost" | debconf-set-selections \ && echo "postfix postfix/main_mailer_type string Internet Site" | debconf-set-selections \ && apt-get update \ && apt-get install -y --no-install-recommends \ postfix \ opendkim \ opendkim-tools \ sasl2-bin \ libsasl2-modules \ supervisor \ logrotate \ ca-certificates \ && rm -rf /var/lib/apt/lists/* # Postfix logs to a plain file (via its built-in postlogd) so the panel's # log-tailer has something to follow and container logging works without syslog. RUN postconf -e "maillog_file=/var/log/mail.log" # Unprivileged user for the panel process (spec 7.6.8). RUN useradd --system --no-create-home --shell /usr/sbin/nologin panel # Shared group bridging the unprivileged services (spec 5.1, 6): the panel # generates per-domain DKIM keys, application SASL accounts (sasldb2) and the # Postfix sender map, while OpenDKIM and Postfix (different users) must read # them. Membership in this group — plus setgid dirs under /data (set up in # entrypoint.sh) — lets OpenDKIM read the panel-owned keys and lets Postfix read # the sasldb2/sender map, and lets the panel reach the supervisor control socket # to signal OpenDKIM/Postfix reloads without any process running as root. RUN groupadd --system selfpost \ && usermod -aG selfpost panel \ && usermod -aG selfpost opendkim \ && usermod -aG selfpost postfix # Runtime directories: milter sockets and the consolidated persistent root. RUN mkdir -p /run/opendkim /run/selfpost /data \ && chown opendkim:opendkim /run/opendkim \ && chown panel:panel /run/selfpost /data COPY --from=build /out/panel /usr/local/bin/panel COPY --from=build /out/selfpost-backup /usr/local/bin/selfpost-backup COPY build/opendkim.conf /etc/opendkim.conf COPY build/postfix-wrapper.sh /usr/local/bin/postfix-wrapper.sh COPY build/crashexit.py /usr/local/bin/crashexit.py COPY build/entrypoint.sh /usr/local/bin/entrypoint.sh COPY build/supervisord.conf /etc/supervisor/supervisord.conf RUN chmod +x /usr/local/bin/postfix-wrapper.sh /usr/local/bin/crashexit.py /usr/local/bin/entrypoint.sh # 8080 panel; 25 outbound; 465/587 inbound submission (used from Phase 5). EXPOSE 8080 25 465 587 # The entrypoint fixes /data ownership (bind mount) as root, then execs # supervisord, which becomes PID 1 and owns process supervision (spec 4). ENTRYPOINT ["/usr/local/bin/entrypoint.sh"]