(READ ONLY) Margin is an open annotation layer for the internet. Powered by the AT Protocol.
margin.at
extension web atproto comments
Something went wrong. Try again.
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980FROM oven/bun:1 AS frontend-builder
WORKDIR /app/webCOPY web/package.json web/bun.lock ./RUN bun installCOPY web/ ./# Lexicons are the source of truth for schema docs rendered by the web build.COPY lexicons/ /app/lexicons/RUN bun run build
FROM golang:1.25-alpine AS backend-builder
RUN apk add --no-cache gcc musl-dev
WORKDIR /appCOPY backend/go.mod backend/go.sum ./RUN go mod download
COPY backend/ ./RUN CGO_ENABLED=1 GOOS=linux go build -a -ldflags '-linkmode external -extldflags "-static"' -o margin-server ./cmd/server
FROM node:20-alpine
RUN apk add --no-cache ca-certificates tzdata
WORKDIR /app
COPY --from=backend-builder /app/margin-server ./margin-server
COPY --from=frontend-builder /app/web/dist ./distCOPY --from=frontend-builder /app/web/node_modules ./node_modules
ENV PORT=8080ENV API_PORT=8081ENV DATABASE_URL=margin.dbENV HOST=0.0.0.0ENV API_URL=http://localhost:8081
EXPOSE 8080
COPY <<'EOF' /app/start.sh#!/bin/shset -e
term() { kill -TERM "$api_pid" "$web_pid" 2>/dev/null exit 0}trap term TERM INT
PORT=$API_PORT ./margin-server &api_pid=$!
until wget -qO- "http://localhost:$API_PORT/health" >/dev/null 2>&1; do if ! kill -0 "$api_pid" 2>/dev/null; then echo "API exited before becoming ready" exit 1 fi echo "Waiting for API..." sleep 0.5done
node ./dist/server/entry.mjs &web_pid=$!
while kill -0 "$api_pid" 2>/dev/null && kill -0 "$web_pid" 2>/dev/null; do sleep 1done
kill -TERM "$api_pid" "$web_pid" 2>/dev/nullexit 1EOFRUN chmod +x /app/start.sh
HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \ CMD wget -qO- "http://localhost:$API_PORT/health" >/dev/null 2>&1 && wget -qO- "http://localhost:$PORT/" >/dev/null 2>&1 || exit 1
CMD ["/app/start.sh"]