# One image, two entrypoints: the appview and the firehose run the same code with a # different Exec= in their Quadlet units. # Build stage — the asset build needs devDependencies (tailwind, bun build); the # runtime does not, so they never reach the final image. FROM docker.io/oven/bun:1.3.11 AS builder WORKDIR /app COPY package.json bun.lock bunfig.toml tsconfig.json ./ RUN bun install --frozen-lockfile COPY src/ ./src/ COPY public/ ./public/ RUN bun run build FROM docker.io/oven/bun:1.3.11 WORKDIR /app # The base image ships no fonts at all. sharp rasterizes the OG cards through librsvg, # which resolves families via fontconfig — without these every glyph came out as tofu. # Keep FONT_STACK in src/lib/og-card.ts naming families installed here. # noto-core covers the non-Latin scripts, noto-cjk the Han/Kana/Hangul ranges those # omit. The cards are drawn entirely in sans, so the serif faces are deleted in the # same layer — 70MB of the 136MB installed, and nothing can reach them. RUN apt-get update \ && apt-get install -y --no-install-recommends \ fontconfig fonts-dejavu-core fonts-noto-core fonts-noto-cjk \ && find /usr/share/fonts -name 'NotoSerif*' -delete \ && fc-cache -f \ && rm -rf /var/lib/apt/lists/* COPY package.json bun.lock bunfig.toml tsconfig.json ./ # The prune drops 52MB that nothing here can reach: sharp ships prebuilt libvips for # both libcs and bun installs both, but this image is glibc; and bun leaves the # TypeScript 7 native binary behind despite --production, since it is an # optionalDependency of a devDependency. The server runs .ts through bun's own # transpiler, never tsc. Bun's download cache is hardlinked into node_modules, so # dropping it in the same layer costs nothing and keeps it out of the image. RUN bun install --frozen-lockfile --production \ && rm -rf node_modules/@img/*musl* node_modules/@typescript node_modules/typescript \ && rm -rf /root/.bun/install/cache COPY src/ ./src/ # scripts/ carries the moderation CLI, run via `podman exec` against DB_PATH. COPY scripts/ ./scripts/ # The key generator needs node_modules, which /opt/lichen no longer has. COPY deploy/gen-oauth-jwk.ts ./deploy/ COPY --from=builder /app/public ./public # staticPlugin resolves assets relative to CWD, so /app has to be the working dir. # uid 1000 — the volume's contents are chowned to match during migration. USER bun ENV NODE_ENV=production CMD ["bun", "run", "src/server/index.ts"]