Skip to content

Deploy the API

This is the production deployment path for the public Pinchana API stack. Use the development Compose file for local source work instead.

  • Linux host with Docker Engine and Compose plugin.
  • Enough disk for the shared media cache and, if enabled, temporary DLP jobs.
  • A provider WireGuard key for Gluetun.
  • HTTPS reverse proxy/DNS for the public gateway origin.
  • Firewall rules that keep scraper/control/DLP internal ports away from untrusted networks.
Terminal window
git clone --recurse-submodules https://github.com/Pinchana/pinchana-api.git
cd pinchana-api
cp .env.example .env
chmod 600 .env

Replace placeholder production credentials at minimum:

WIREGUARD_PRIVATE_KEY=REPLACE_WITH_PROVIDER_KEY
GLUETUN_API_KEY=REPLACE_WITH_RANDOM_CONTROL_KEY
PINCHANA_API_KEYS={"operator":"REPLACE_WITH_LONG_RANDOM_MACHINE_KEY"}

Add Spotify credentials if that module is enabled for real use.

Resolve the newest coherent API release before first startup and on later upgrades:

Terminal window
python scripts/update_rolling.py --env-file .env --dry-run
python scripts/update_rolling.py --env-file .env

This replaces the mutable discovery tags in .env with exact repository digests only after all selected services resolve to the same released CalVer.

If DLP should be deployed/updated too:

Terminal window
python scripts/update_rolling.py --env-file .env --dlp --dry-run
python scripts/update_rolling.py --env-file .env --dlp

Do not mix independently chosen scraper image versions in production.

Terminal window
docker compose --env-file .env config --quiet
docker compose --env-file .env up --detach
docker compose --env-file .env ps

Health check:

Terminal window
curl --fail-with-body --silent --show-error http://127.0.0.1:8080/health

The gateway and normal scraper services share Gluetun’s network namespace. Service containers do not publish independent ports: blocks; the host mappings live on Gluetun.

Even if operational host mappings for module ports exist, expose only gateway port 8080 through the public reverse proxy. Keep module ports 80818089 and Gluetun control 8000 firewalled from the Internet.

Example public routing:

https://api.example.com -> 127.0.0.1:8080

Terminate TLS at your reverse proxy and preserve normal HTTP range/request headers for media streaming.

If a Pinchana Web deployment will use this API, configure the API’s browser verifier:

TURNSTILE_SECRET_KEY=REPLACE_WITH_PRIVATE_TURNSTILE_SECRET
TURNSTILE_EXPECTED_HOSTNAME=pinchana.example.com
TURNSTILE_EXPECTED_ACTION=turnstile-spin-v1
TURNSTILE_SESSION_SECRET=REPLACE_WITH_AT_LEAST_32_RANDOM_CHARACTERS

The corresponding public Turnstile site key belongs on the Web deployment.

A self-hosted Web server using this API as its configured default origin does not require an instance certificate. A certificate is needed when this API should be accepted as a custom instance by a Web deployment that enforces project-issued instance trust.

The Shorts service can consume cookie files from:

SHORTS_COOKIES_DIR=./secrets/yt-cookies

Production Compose mounts that directory read-only to /run/pinchana-cookies.

For rootful Docker with the current image:

Terminal window
sudo install -d -o root -g root -m 0700 secrets/yt-cookies
sudo chown root:root secrets/yt-cookies/cookies.txt
sudo chmod 0600 secrets/yt-cookies/cookies.txt

Use the Docker host user instead for rootless Docker. Never store cookie files in Git or backups that are not designed for secrets.

DLP services are an optional Compose profile and should remain disabled publicly while infrastructure is prepared:

DLP_ENABLED=false

Use the production preflight and canary from DLP operations and security. Redis, DLP API, orchestrator, worker control paths, and the DLP worker network must remain internal.

The job root defaults to /srv/pinchana-dlp/jobs and is temporary, not backup data.

Routine application update:

Terminal window
python scripts/update_rolling.py --env-file .env --dry-run
python scripts/update_rolling.py --env-file .env
docker compose --env-file .env up --detach

If changed environment variables must be applied to one service, recreate that service explicitly. For Gluetun, use Compose recreation rather than docker restart:

Terminal window
docker compose --env-file .env up --detach --force-recreate gluetun

Treat these differently:

  • .env and mounted secrets — critical secret configuration; back up securely if your operational policy requires it.
  • scraper-cache — disposable working cache, not authoritative data.
  • mobile session SQLite — persistent state only if you actively use mobile installation grants.
  • DLP job directories/Redis — temporary and intentionally not backed up.
  • instance certificate envelope — public certificate material, but protect the operational file from accidental modification; never deploy its signing private key.