Skip to content

Deploy the Web app

Pinchana Web is hosted with the repository’s docker-compose.yml. It uses the official oven/bun:1.3.14-debian image directly—there is no Pinchana Web image to build or publish. On container start, Bun installs the frozen lockfile, synchronizes browser FFmpeg assets, builds Next.js, and starts the production server.

Pinchana Web requires a running server. It cannot be exported as static HTML because route handlers proxy authenticated requests, verify Ed25519 certificates, read server-only configuration, and manage HttpOnly cookies.

Variable Phase Exposure
NEXT_PUBLIC_TURNSTILE_SITE_KEY container build/public Embedded for the browser; required and registered for the production Web hostname
PINCHANA_API_URL container runtime/server Default API origin; required and never public
PINCHANA_INSTANCE_PUBLIC_KEY container runtime/server Optional Ed25519 public verification PEM; preserve newlines or use escaped \n
WEB_BIND_ADDRESS Compose host Host interface, default 127.0.0.1
WEB_HOST_PORT Compose host Reverse-proxy target port, default 3000

Configure the selected API separately with the matching Turnstile secret, expected Web hostname pinchana.example.com, action turnstile-spin-v1, and signed-session secret.

  1. Clone Pinchana Web on the Docker host.
  2. Create a mode-0600 .env beside docker-compose.yml with the required variables. Compose reads this file for interpolation; it is not mounted into the container.
  3. Run docker compose config and inspect the effective configuration without sharing it because it contains deployment values.
  4. Start with docker compose up -d and follow the initial install/build with docker compose logs -f web.
  5. Wait for docker compose ps to report the service healthy, then proxy HTTPS to 127.0.0.1:3000.
PINCHANA_API_URL=https://api.pinchana.cc
NEXT_PUBLIC_TURNSTILE_SITE_KEY=REPLACE_WITH_PUBLIC_SITE_KEY
PINCHANA_INSTANCE_PUBLIC_KEY="-----BEGIN PUBLIC KEY-----\nREPLACE_WITH_PUBLIC_KEY\n-----END PUBLIC KEY-----"
WEB_BIND_ADDRESS=127.0.0.1
WEB_HOST_PORT=3000

Application source and configuration are mounted read-only into a writable /app workspace. The container copies public/ into that workspace before install so the FFmpeg synchronization step can write public/ffmpeg. Named volumes hold installed dependencies and .next-build; recreate these disposable volumes if a corrupt dependency/build cache survives an update.

Put Caddy, Nginx, Traefik, or another HTTPS reverse proxy in front of the loopback port. Preserve streaming, disable response buffering for App Router streams, and forward byte-range requests used by the media proxy.

Terminal window
git pull --ff-only
docker compose up -d --force-recreate web
docker compose logs --tail=100 web

The startup command rebuilds from the checked-out revision. NEXT_PUBLIC_TURNSTILE_SITE_KEY is frozen into that build, so changing it also requires recreation. Roll back by checking out the previous revision and force-recreating the service again.

  • Page load checks an existing session or renders Turnstile.
  • Browser network requests never reveal the API origin, signed session, or instance certificate cookie.
  • URL processing, image/video/audio preview, byte-range seeking, Media and Audio-only saves, ZIP creation, and FFmpeg loading work.
  • Cookies are HttpOnly, SameSite=Strict, and Secure over production HTTPS.
  • Custom origin selection accepts an authorized certificate and rejects mismatched/expired envelopes.