orchard
mirrorEvery site I host, in one repo, along with the Cloudflare Tunnel and Caddy that front them. It's all Go, Vite, and SQLite, and it runs on a desktop at home with nothing listening on an inbound port.
blogbuncaddycloudflare-tunneldockergogolanghomelabhtml-templatemonorepoself-hostedseosqlitestatic-sitetypstuptime-monitoringviteweb-analytics
1# chat.bythewood.me.
2#
3# This one ends at Alpine rather than scratch, for poppler's pdftotext. The pure
4# Go reader cannot open an encrypted pdf, which is what a bank statement usually
5# is, and it loses the column alignment that makes a statement readable at all.
6# Everything else here is still parsed in process.
7FROM golang:1.27-trixie AS build
8WORKDIR /src
9COPY go.mod go.sum ./
10RUN go mod download
11COPY . .
12# -tags embed swaps the disk asset loader for the embedded one, so the shipped
13# image cannot read templates off a filesystem that is not there, and the
14# development bypass in assets_disk.go cannot be turned on however the
15# environment is set.
16RUN CGO_ENABLED=0 go build -tags embed -trimpath -ldflags="-s -w" -o /app .
17
18FROM alpine:3.23@sha256:fd791d74b68913cbb027c6546007b3f0d3bc45125f797758156952bc2d6daf40
19
20# poppler-utils is pdftotext and nothing else here needs a shell. ca-certificates
21# because every tool fetches over TLS, and tzdata because the ambient block
22# states a local time.
23RUN apk add --no-cache ca-certificates poppler-utils tzdata
24
25COPY --from=build /app /app
26
27# chown before the VOLUME, and the order matters: Docker seeds a fresh volume
28# from the image path it mounts over and carries its ownership. Without it the
29# mountpoint is root-owned and the first boot dies on a database open error.
30RUN mkdir -p /data && chown 65532:65532 /data
31VOLUME ["/data"]
32
33# UID 65532 like the scratch images here, so one number owns every /data volume.
34RUN addgroup -g 65532 app && adduser -u 65532 -G app -D -H app
35USER 65532:65532
36
37# pdftotext writes its temporary files under the working directory otherwise.
38ENV TMPDIR=/tmp
39
40EXPOSE 8000
41HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \
42 CMD ["/app", "-healthcheck"]
43ENTRYPOINT ["/app"]