WIP! A BB-style forum, on the ATmosphere!
We're still working... we'll be back soon when we have something to show off!
node
typescript
hono
htmx
atproto
1# Stage 1: Build
2FROM node:22.12-alpine3.21 AS builder
3
4# Install build dependencies (bash needed for lexicon glob expansion)
5RUN apk add --no-cache bash
6
7# Install pnpm
8RUN npm install -g pnpm@9.15.4
9
10# Set working directory
11WORKDIR /build
12
13# Copy package files for dependency installation
14COPY package.json pnpm-lock.yaml pnpm-workspace.yaml ./
15COPY apps/appview/package.json ./apps/appview/
16COPY apps/web/package.json ./apps/web/
17COPY packages/db/package.json ./packages/db/
18COPY packages/atproto/package.json ./packages/atproto/
19COPY packages/cli/package.json ./packages/cli/
20COPY packages/lexicon/package.json ./packages/lexicon/
21COPY packages/logger/package.json ./packages/logger/
22
23# Install all dependencies (including dev dependencies for build)
24# Skip prepare script (lefthook requires git, which we don't need in Docker)
25RUN pnpm install --frozen-lockfile --ignore-scripts
26
27# Copy source code (.dockerignore filters out unwanted files)
28COPY . .
29
30# Build all packages (turbo builds lexicon → appview + web)
31RUN pnpm build
32
33# Stage 2: Runtime
34FROM node:22.12-alpine3.21
35
36# Install nginx and wget (for health checks)
37RUN apk add --no-cache nginx wget
38
39# Set working directory
40WORKDIR /app
41
42# Copy package files for production install
43COPY package.json pnpm-lock.yaml pnpm-workspace.yaml ./
44COPY apps/appview/package.json ./apps/appview/
45COPY apps/web/package.json ./apps/web/
46COPY packages/db/package.json ./packages/db/
47COPY packages/atproto/package.json ./packages/atproto/
48COPY packages/cli/package.json ./packages/cli/
49COPY packages/lexicon/package.json ./packages/lexicon/
50COPY packages/logger/package.json ./packages/logger/
51
52# Install pnpm and production dependencies only
53# Skip prepare script (lefthook not needed in production)
54RUN npm install -g pnpm@9.15.4 && \
55 pnpm install --prod --frozen-lockfile --ignore-scripts
56
57# Create non-root user and set permissions
58RUN addgroup -g 1001 -S atbb && \
59 adduser -S -D -H -u 1001 -h /app -s /sbin/nologin -G atbb atbb && \
60 chown -R atbb:atbb /app
61
62# Give nginx permissions to run as non-root
63RUN mkdir -p /var/lib/nginx /var/log/nginx /run/nginx && \
64 chown -R atbb:atbb /var/lib/nginx /var/log/nginx /run/nginx
65
66# Copy built artifacts from builder stage
67COPY --from=builder /build/apps/appview/dist ./apps/appview/dist
68COPY --from=builder /build/apps/web/dist ./apps/web/dist
69COPY --from=builder /build/packages/db/dist ./packages/db/dist
70COPY --from=builder /build/packages/atproto/dist ./packages/atproto/dist
71COPY --from=builder /build/packages/cli/dist ./packages/cli/dist
72COPY --from=builder /build/packages/lexicon/dist ./packages/lexicon/dist
73COPY --from=builder /build/packages/logger/dist ./packages/logger/dist
74
75# Copy migration files for drizzle-kit
76COPY --from=builder /build/apps/appview/drizzle ./apps/appview/drizzle
77
78# Copy nginx config to standard location and entrypoint script
79COPY nginx.conf /etc/nginx/nginx.conf
80COPY entrypoint.sh ./
81RUN chmod +x entrypoint.sh
82
83# Expose port 80 (nginx listens here)
84EXPOSE 80
85
86# Add health check for container orchestration
87HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
88 CMD wget --no-verbose --tries=1 --spider http://localhost/api/healthz || exit 1
89
90# Switch to non-root user
91USER atbb
92
93# Set entrypoint
94ENTRYPOINT ["/app/entrypoint.sh"]