WitNote / Dockerfile
AUXteam's picture
Upload folder using huggingface_hub
6a7089a verified
# Stage 1: Build the React dashboard with Bun.
# The compiled assets are copied into the Go embed directory in stage 2.
FROM oven/bun:1 AS dashboard
WORKDIR /build
COPY dashboard/package.json dashboard/bun.lock ./
RUN bun install --frozen-lockfile
COPY dashboard/ .
RUN bun run build
# Stage 2: Compile the Go binary.
# Dashboard dist is embedded via Go's embed package.
# Vite always outputs index.html; rename to dashboard.html so it doesn't
# collide with http.FileServer's automatic index.html handling at /dashboard/.
FROM golang:1.26-alpine AS builder
RUN apk add --no-cache git
WORKDIR /build
COPY go.mod go.sum ./
RUN go mod download
COPY . .
COPY --from=dashboard /build/dist/ internal/dashboard/dashboard/
RUN mv internal/dashboard/dashboard/index.html internal/dashboard/dashboard/dashboard.html
RUN go build -ldflags="-s -w" -o pinchtab ./cmd/pinchtab
# Stage 3: Minimal runtime image with Chromium.
# Only the compiled binary and entrypoint script are copied in.
#
# Security model:
# - Chrome runs with --no-sandbox (set by entrypoint) because containers don't
# have user namespaces for sandboxing
# - Container provides isolation via cgroups, seccomp, dropped capabilities,
# read-only filesystem, and non-root user
# - This matches best practices for headless Chrome in containerized environments
FROM alpine:3.21
LABEL org.opencontainers.image.source="https://github.com/pinchtab/pinchtab"
LABEL org.opencontainers.image.description="High-performance browser automation bridge"
# Chromium and its runtime dependencies for headless operation
RUN apk add --no-cache \
chromium \
nss \
freetype \
harfbuzz \
ca-certificates \
ttf-freefont \
dumb-init
# Non-root user; /data is the persistent volume mount point
RUN adduser -D -h /data -g '' pinchtab && \
mkdir -p /data && \
chown pinchtab:pinchtab /data
COPY --from=builder /build/pinchtab /usr/local/bin/pinchtab
COPY --chmod=0755 docker-entrypoint.sh /usr/local/bin/docker-entrypoint.sh
USER pinchtab
WORKDIR /data
# HOME and XDG_CONFIG_HOME point into the persistent volume so config
# and Chrome profiles survive container restarts.
ENV HOME=/data \
XDG_CONFIG_HOME=/data/.config
EXPOSE 7860
HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \
CMD wget -q -O /dev/null http://localhost:7860/health || exit 1
ENTRYPOINT ["/usr/bin/dumb-init", "--"]
CMD ["/usr/local/bin/docker-entrypoint.sh", "pinchtab"]