mirror of
https://github.com/warmbly/warmbly.git
synced 2026-10-03 16:02:02 +00:00
* feat: let the backend, consumer and tracking service fetch their own MaxMind databases from GEODB_URL and TRACKING_SCANNER_ASN_DB_URL, reading the archive shape from the content so a permalink tar.gz, a gzipped mmdb and a bare mmdb all work, never replacing a file already at the path, opening the bytes before installing them so a licence-key error page cannot become the database forever, skipping the AppleDouble sidecars a macOS tar writes ahead of the real file, and treating both URLs as secrets because the permalink carries the licence key * feat: drop the trailing blank line cargo fmt --check rejects at the end of tracking/src/asndb.rs * feat: stream the downloaded ASN archive instead of decompressing it whole, sizing each buffer from the gzip footer and the tar header so the member is allocated exactly once, which drops the peak of unwrapping a permalink tar.gz from 38 MB to 11.9 MB, essentially the database itself * feat: stop the MaxMind licence key reaching the logs through net/http's and reqwest's own error text, which both print the URL they were given and so defeated the redaction beside them, drop userinfo as well as the query when redacting, refuse plain http for a URL carrying a credential and refuse an https-to-http redirect, and apply the size cap to the decoded database rather than the compressed transfer so a gzip bomb cannot fill the disk * feat: strip basic-auth userinfo as well as the query when the tracking service redacts its database URL, parsing it rather than cutting at the first question mark so where a credential sits is the URL library's problem and not a guess
93 lines
5.5 KiB
Docker
93 lines
5.5 KiB
Docker
# syntax=docker/dockerfile:1.7
|
|
#
|
|
# Default build is CGO-free (NATS + JSON) — no librdkafka, gcc, or musl-dev, so
|
|
# it builds in a fraction of the time and cross-compiles to arm64/amd64 cleanly.
|
|
# BuildKit cache mounts keep the module + compile caches warm across builds.
|
|
#
|
|
# The builder always runs on the build host ($BUILDPLATFORM) and cross-compiles
|
|
# to $TARGETARCH, so multi-arch CI builds never run the Go compiler under QEMU.
|
|
#
|
|
# To include the optional Kafka backend, build with --build-arg GO_TAGS=kafka
|
|
# (adds librdkafka + CGO; slower, and CGO cannot cross-compile — build each arch
|
|
# on a native runner). Runtime selection is still by env
|
|
# (EVENTBUS_PROVIDER / CODEC_PROVIDER).
|
|
FROM --platform=$BUILDPLATFORM golang:1.25-alpine AS builder
|
|
|
|
ARG GO_TAGS=""
|
|
ARG TARGETOS TARGETARCH
|
|
# Build identity shown in the admin panel; see internal/version.
|
|
ARG VERSION="" COMMIT="" BUILT_AT=""
|
|
RUN apk add --no-cache git ca-certificates && \
|
|
if echo "$GO_TAGS" | grep -qw kafka; then apk add --no-cache gcc musl-dev librdkafka-dev; fi
|
|
|
|
WORKDIR /app
|
|
COPY go.mod go.sum ./
|
|
RUN --mount=type=cache,id=gomod,target=/go/pkg/mod go mod download
|
|
|
|
COPY . .
|
|
RUN --mount=type=cache,id=gomod,target=/go/pkg/mod \
|
|
--mount=type=cache,id=gobuild,target=/root/.cache/go-build \
|
|
set -eux; \
|
|
if echo "$GO_TAGS" | grep -qw kafka; then CGO=1; TAGS="musl kafka"; else CGO=0; TAGS=""; fi; \
|
|
CGO_ENABLED=$CGO GOOS=$TARGETOS GOARCH=$TARGETARCH go build -tags "$TAGS" -ldflags="-s -w -X github.com/warmbly/warmbly/internal/version.Version=$VERSION -X github.com/warmbly/warmbly/internal/version.Commit=$COMMIT -X github.com/warmbly/warmbly/internal/version.BuiltAt=$BUILT_AT" -o /out/backend ./cmd/backend; \
|
|
CGO_ENABLED=0 GOOS=$TARGETOS GOARCH=$TARGETARCH go build -ldflags="-s -w -X github.com/warmbly/warmbly/internal/version.Version=$VERSION -X github.com/warmbly/warmbly/internal/version.Commit=$COMMIT -X github.com/warmbly/warmbly/internal/version.BuiltAt=$BUILT_AT" -o /out/seed ./cmd/seed; \
|
|
CGO_ENABLED=0 GOOS=$TARGETOS GOARCH=$TARGETARCH go build -ldflags="-s -w -X github.com/warmbly/warmbly/internal/version.Version=$VERSION -X github.com/warmbly/warmbly/internal/version.Commit=$COMMIT -X github.com/warmbly/warmbly/internal/version.BuiltAt=$BUILT_AT" -o /out/migrate ./cmd/migrate; \
|
|
CGO_ENABLED=0 GOOS=$TARGETOS GOARCH=$TARGETARCH go build -ldflags="-s -w -X github.com/warmbly/warmbly/internal/version.Version=$VERSION -X github.com/warmbly/warmbly/internal/version.Commit=$COMMIT -X github.com/warmbly/warmbly/internal/version.BuiltAt=$BUILT_AT" -o /out/warmblyctl ./cmd/warmblyctl; \
|
|
CGO_ENABLED=0 GOOS=$TARGETOS GOARCH=$TARGETARCH go build -ldflags="-s -w -X github.com/warmbly/warmbly/internal/version.Version=$VERSION -X github.com/warmbly/warmbly/internal/version.Commit=$COMMIT -X github.com/warmbly/warmbly/internal/version.BuiltAt=$BUILT_AT" -o /out/warmbly ./cmd/cli
|
|
|
|
# Runtime stage
|
|
FROM alpine:3.23
|
|
|
|
ARG GO_TAGS=""
|
|
# postgresql-client is here for `warmblyctl backup` and `warmblyctl restore`:
|
|
# the instance bundle is a pg_dump and the restore replays it with psql, and the
|
|
# backend container is where the CLI already has PRIMARY_DB and the blob root.
|
|
RUN apk add --no-cache ca-certificates tzdata postgresql-client && \
|
|
if echo "$GO_TAGS" | grep -qw kafka; then apk add --no-cache librdkafka; fi && \
|
|
adduser -D -u 1000 warmbly
|
|
|
|
# BLOB_FS_ROOT's default mount point, owned by the user the process runs as.
|
|
# Docker seeds a fresh named volume from the image, so the directory has to
|
|
# exist here with the right owner; otherwise Docker creates the mount point
|
|
# root-owned, the non-root process cannot write to it, and the first send fails
|
|
# with "mkdir /data/blobs/emails: permission denied".
|
|
RUN mkdir -p /data/blobs && chown -R warmbly:warmbly /data
|
|
|
|
# GEODB_PATH's default directory, owned by the same user for the same reason:
|
|
# with GEODB_URL set the process writes the database here itself, and /app is
|
|
# root-owned, so without this the download fails on a directory it cannot make.
|
|
# A bind mount over it still wins, which is how an operator supplies their own.
|
|
RUN mkdir -p /app/data && chown -R warmbly:warmbly /app/data
|
|
|
|
# Amazon RDS presents a chain rooted in an RDS CA that is in no public trust
|
|
# store, so sslmode=verify-full cannot work against it from the system bundle
|
|
# alone. Shipping AWS's truststore makes verification possible for operators who
|
|
# opt in with sslrootcert=/etc/ssl/rds/global-bundle.pem; nothing here changes
|
|
# the default, because pointing every install at an RDS-only store would break
|
|
# a Postgres fronted by a public CA.
|
|
RUN mkdir -p /etc/ssl/rds && \
|
|
wget -qO /etc/ssl/rds/global-bundle.pem \
|
|
https://truststore.pki.rds.amazonaws.com/global/global-bundle.pem && \
|
|
chmod 0644 /etc/ssl/rds/global-bundle.pem
|
|
|
|
COPY --from=builder /out/backend /app/backend
|
|
COPY --from=builder /out/seed /app/seed
|
|
COPY --from=builder /out/migrate /app/migrate
|
|
|
|
# The operator CLI goes on PATH, not /app, so the documented recovery command is
|
|
# `docker compose exec backend warmblyctl status` and not a path.
|
|
COPY --from=builder /out/warmblyctl /usr/local/bin/warmblyctl
|
|
|
|
# The customer CLI ships alongside it, so an operator who has exec on the box
|
|
# can drive the product as well as recover it without installing anything.
|
|
COPY --from=builder /out/warmbly /usr/local/bin/warmbly
|
|
|
|
USER warmbly
|
|
EXPOSE 8080
|
|
|
|
# 127.0.0.1, not localhost: busybox wget tries ::1 first but the server binds IPv4.
|
|
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s \
|
|
CMD wget --no-verbose --tries=1 --spider http://127.0.0.1:8080/health || exit 1
|
|
|
|
ENTRYPOINT ["/app/backend"]
|