/ Dockerfile
Dockerfile
  1  # syntax=docker/dockerfile:1
  2  
  3  # Stage 1: Build frontend
  4  FROM node:22-alpine AS frontend
  5  
  6  WORKDIR /app
  7  
  8  # Copy workspace package files first for layer caching
  9  COPY package.json package-lock.json ./
 10  COPY webui/app/package.json webui/app/
 11  COPY webui/components/package.json webui/components/
 12  COPY webui/website/package.json webui/website/
 13  
 14  RUN npm ci --workspaces
 15  
 16  COPY webui/ webui/
 17  
 18  RUN npm run build -w @hister/app
 19  
 20  # Stage 2: Build Go binary
 21  FROM golang:1.24-alpine AS builder
 22  
 23  RUN apk add --no-cache gcc musl-dev
 24  
 25  WORKDIR /app
 26  
 27  COPY go.mod go.sum ./
 28  RUN go mod download
 29  
 30  COPY . .
 31  COPY --from=frontend /app/webui/app/build/ server/static/app/
 32  
 33  RUN CGO_ENABLED=1 go build \
 34      -tags netgo,osusergo \
 35      -ldflags "-linkmode external -extldflags '-static' -s -w" \
 36      -o hister .
 37  
 38  # Release stage (nonroot)
 39  # latest & vx.x.x
 40  FROM alpine:3.21 AS release
 41  
 42  LABEL org.opencontainers.image.title="Hister" \
 43        org.opencontainers.image.description="Self-hosted browser history search engine" \
 44        org.opencontainers.image.source="https://github.com/asciimoo/hister" \
 45        org.opencontainers.image.licenses="AGPL-3.0"
 46  
 47  WORKDIR /hister
 48  
 49  RUN adduser -D -u 65532 hister && mkdir -p /hister/data && chown -R 65532:65532 /hister
 50  COPY --chown=65532:65532 --from=builder /app/hister .
 51  USER 65532:65532
 52  
 53  ENV HISTER_DATA_DIR=/hister/data
 54  ENV HISTER_CONFIG=/hister/data/config.yml
 55  ENV HISTER__SERVER__ADDRESS=0.0.0.0:4433
 56  ENV HISTER__SERVER__BASE_URL=http://localhost:4433
 57  
 58  EXPOSE 4433
 59  
 60  HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \
 61      CMD wget -qO /dev/null http://localhost:4433/api/stats || exit 1
 62  
 63  ENTRYPOINT ["/hister/hister"]
 64  CMD ["listen"]
 65  
 66  # Release stage (root)
 67  # latest-root & vx.x.x-root
 68  FROM alpine:3.21 AS root
 69  WORKDIR /hister
 70  
 71  RUN mkdir -p /hister/data
 72  COPY --from=builder /app/hister .
 73  
 74  USER root
 75  
 76  ENV HISTER_DATA_DIR=/hister/data
 77  ENV HISTER_CONFIG=/hister/data/config.yml
 78  ENV HISTER__SERVER__ADDRESS=0.0.0.0:4433
 79  ENV HISTER__SERVER__BASE_URL=http://localhost:4433
 80  
 81  EXPOSE 4433
 82  
 83  HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \
 84      CMD wget -qO /dev/null http://localhost:4433/api/stats || exit 1
 85  
 86  ENTRYPOINT ["/hister/hister"]
 87  CMD ["listen"]
 88  
 89  # Release stage (debug)
 90  # latest-debug & vx.x.x-debug
 91  FROM alpine:3.21 AS debug
 92  WORKDIR /hister
 93  
 94  RUN apk add --no-cache curl bash && mkdir -p /hister/data
 95  
 96  COPY --from=builder /app/hister .
 97  
 98  USER root
 99  
100  ENV HISTER_DATA_DIR=/hister/data
101  ENV HISTER_CONFIG=/hister/data/config.yml
102  ENV HISTER__SERVER__ADDRESS=0.0.0.0:4433
103  ENV HISTER__SERVER__BASE_URL=http://localhost:4433
104  
105  EXPOSE 4433
106  
107  HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \
108      CMD wget -qO /dev/null http://localhost:4433/api/stats || exit 1
109  
110  ENTRYPOINT ["/hister/hister"]
111  CMD ["listen"]