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