# syntax=docker/dockerfile:1 FROM golang:1.26-alpine AS build WORKDIR /src # Dependencies first so edits to the source don't re-download the module cache. COPY go.mod go.sum ./ RUN go mod download COPY . . RUN mkdir -p /out/releases /out/logs RUN CGO_ENABLED=0 GOOS=linux go build -trimpath -buildvcs=false \ -ldflags="-s -w" -o /out/memby-server ./cmd/memby-server # The credits bench ships in the image because the number it prints is only meaningful # against the household's own media on its own hardware — a figure measured anywhere else # proves nothing about whether a scan on this NAS is cheap. RUN CGO_ENABLED=0 GOOS=linux go build -trimpath -buildvcs=false \ -ldflags="-s -w" -o /out/memby-credits ./cmd/memby-credits # Alpine rather than distroless/static, and the reason is ffmpeg. # # Credits detection is the only thing in the gateway that reads media bytes, and it does so # through ffmpeg used surgically — seek to the tail, downscale to a thumbnail, one frame every # few seconds, raw grayscale on stdout, nothing written to disk. A static distroless image # cannot carry a decoder, so the choice is this base or no visual detection at all. # # What is preserved from distroless: CA certificates, so an HTTPS Emby is reachable, and a # non-root user. What is given up: about a hundred megabytes, and a shell existing in the # image. The container healthcheck still re-runs the binary with -healthcheck rather than # using curl, so it is unchanged by the move and stays honest if the base ever goes back. FROM alpine:3.21 RUN apk add --no-cache ca-certificates ffmpeg \ && addgroup -g 65532 -S nonroot \ && adduser -u 65532 -S -G nonroot nonroot WORKDIR /app COPY --from=build /out/memby-server /app/memby-server COPY --from=build /out/memby-credits /app/memby-credits COPY --from=build --chown=nonroot:nonroot /out/releases /data/releases COPY --from=build --chown=nonroot:nonroot /out/logs /data/logs EXPOSE 8080 USER nonroot:nonroot ENTRYPOINT ["/app/memby-server"]