Deployment
Build, run, and deploy Bosia apps in production.
Production Build
bun run buildThis produces a dist/ directory with:
dist/server/— server entry pointdist/client/— client JavaScript and CSS bundlesdist/prerendered/— static HTML for prerendered routes
Running in Production
bun run startOr directly:
bun dist/server/index.jsSet the port with the PORT environment variable (default: 9000).
Health Check
Bosia exposes a health endpoint at /_health:
curl http://localhost:9000/_health{ "status": "ok", "timestamp": 1711360000000, "timezone": "UTC" }Prerendering
Mark routes for static prerendering:
// +page.server.ts
export const prerender = true;Prerendered pages are built as static HTML during bosia build and served from dist/prerendered/ with a 1-hour cache header.
Data payloads for client-side navigation are also prerendered as JSON files at dist/prerendered/__bosia/data/<route>.json. This means client navigation works on fully static sites (GitHub Pages, Netlify, etc.) without a running server.
Static Asset Caching
Bosia sets cache headers automatically:
| Asset Type | Cache Header |
|---|---|
| Hashed filenames | public, max-age=31536000, immutable |
| Non-hashed files | no-cache |
Behind a Reverse Proxy
When Bosia runs behind nginx, Caddy, Cloudflare, an ALB, or any other reverse proxy / load balancer, the public-facing host typically differs from the Host header reaching the inner Bun process. Set:
TRUST_PROXY=trueso that CSRF origin checks honour X-Forwarded-Host and X-Forwarded-Proto and accept requests whose Origin matches the public-facing URL.
Only enable TRUST_PROXY=true when:
- A proxy or load balancer sits in front of Bosia, and
- That proxy strips any client-supplied
X-Forwarded-*headers before forwarding (verify your proxy's behaviour), and - The proxy injects its own
X-Forwarded-Host/X-Forwarded-Protoreflecting the public origin.
Do not set TRUST_PROXY=true when:
- Bosia is directly internet-facing with no proxy, or
- You cannot confirm the proxy sanitises inbound
X-Forwarded-*headers — that would let any client spoof its own origin and bypass CSRF.
See Security › Reverse-proxy deployments for the full rationale.
Graceful Shutdown
The production server handles SIGTERM and SIGINT signals:
- Stops accepting new connections
- Waits for in-flight requests to complete
- Force exits after 10 seconds if shutdown hangs
Docker
Example Dockerfile:
FROM oven/bun:1 AS base
WORKDIR /app
# Install dependencies
FROM base AS deps
COPY package.json bun.lock ./
RUN bun install --frozen-lockfile
# Build
FROM deps AS build
COPY . .
RUN bun run build
# Production
FROM base AS runtime
COPY --from=deps /app/node_modules ./node_modules
COPY --from=build /app/dist ./dist
COPY --from=build /app/package.json ./
ENV NODE_ENV=production
ENV PORT=9000
EXPOSE 9000
CMD ["bun", "dist/server/index.js"]Environment Variables
See Environment Variables for the full list of configuration options including PORT, BODY_SIZE_LIMIT, CORS, and CSRF settings.