Deploy the API
The canonical production deployment is a Linux VPS running Docker Engine and the repository’s docker-compose.yml with prebuilt GHCR images.
1. Prepare the host
Section titled “1. Prepare the host”Create DNS for api.example.com, install current Docker Engine with the Compose plugin, clone recursively, and copy the example configuration:
git clone --recursive https://github.com/Pinchana/pinchana-api.gitcd pinchana-apicp .env.example .envchmod 600 .envEnsure /dev/net/tun exists. Allocate disk capacity beyond CACHE_MAX_SIZE_GB, and allow the VPN’s required outbound traffic, DNS, HTTPS, and your administration channel.
2. Configure secrets
Section titled “2. Configure secrets”At minimum, replace placeholders for the WireGuard private key, Gluetun API key, named machine API keys, Turnstile secret, expected Web hostname/action, and a random session secret of at least 32 characters. Add Spotify credentials if that module is enabled. If this origin will be selectable from the official Web app, install its issued public certificate envelope or mounted file.
WIREGUARD_PRIVATE_KEY=REPLACE_WITH_WIREGUARD_PRIVATE_KEYGLUETUN_API_KEY=REPLACE_WITH_LONG_RANDOM_CONTROL_KEYPINCHANA_API_KEYS={"production-client":"REPLACE_WITH_LONG_RANDOM_API_KEY"}TURNSTILE_SECRET_KEY=REPLACE_WITH_PRIVATE_TURNSTILE_SECRETTURNSTILE_EXPECTED_HOSTNAME=pinchana.example.comTURNSTILE_EXPECTED_ACTION=turnstile-spin-v1TURNSTILE_SESSION_SECRET=REPLACE_WITH_AT_LEAST_32_RANDOM_CHARACTERSPINCHANA_INSTANCE_CERTIFICATE='REPLACE_WITH_ISSUED_ONE_LINE_JSON_ENVELOPE'SPOTIFY_CLIENT_ID=REPLACE_IF_USEDSPOTIFY_CLIENT_SECRET=REPLACE_IF_USEDPINCHANA_INSTANCE_CERTIFICATE is required only when this origin should be selectable as a custom instance in the official Web app. A project maintainer issues it for the exact public API origin and the public Turnstile site key. Never copy the Ed25519 signing key to the server. See Custom API instances for issuance, file mounts, verification, and renewal.
Mount YouTube cookie files read-only through SHORTS_COOKIES_DIR only when required. Protect their directory as a credential store.
Optional DLP profile
Section titled “Optional DLP profile”Private downloads require the separate dlp Compose profile. Keep DLP_ENABLED=false, generate distinct gateway/owner/Redis secrets, create /srv/pinchana-dlp/jobs with mode 0711, and pin the API, orchestrator, worker, and VPN images before starting it.
docker compose --profile dlp pull dlp-redis dlp-vpn dlp-api dlp-orchestratordocker pull "$DLP_WORKER_IMAGE"python scripts/dlp-prod-preflight.py --env-file .env --phase infradocker compose --profile dlp up -d dlp-redis dlp-vpn dlp-api dlp-orchestratorRequire every DLP service to become healthy and complete anonymous plus encrypted-cookie canaries on a non-public instance. Then set DLP_ENABLED=true, recreate only server, run the enable preflight phase, and confirm authenticated /web/capabilities reports protocol 2. Roll back by setting the flag false and recreating server; active jobs can finish or expire independently.
See Private downloads (DLP) and the repository’s production rollout runbook.
3. Restrict networking
Section titled “3. Restrict networking”Production scraper services and the gateway share Gluetun’s network namespace. The supplied Compose file publishes API, scraper, and control mappings on Gluetun for local operability; do not expose them all to the Internet.
- Publish the gateway only through your HTTPS reverse proxy.
- Bind
API_HOST_PORTto a locally reachable port and firewall it from external clients if the proxy is on-host. - Deny public access to Gluetun control 8000 and scraper ports 8081–8089.
- Expose only TCP 443 publicly (and 80 only for redirect/ACME if needed).
- Keep the Docker socket and SSH/administration paths tightly restricted.
Configure Caddy, Nginx, Traefik, or another reverse proxy for https://api.example.com → the local gateway port. Preserve streaming and Range headers and choose timeouts longer than the gateway’s 120-second scrape forwarding timeout.
4. Start and verify
Section titled “4. Start and verify”- Validate interpolation with
docker compose configand inspect the output without sharing it—it contains secrets. - Pull and start:
docker compose pull && docker compose up -d. - Inspect
docker compose psanddocker compose logs --tail=200 gluetun server. - Check
curl --fail https://api.example.com/health. - If an instance certificate is configured, check
curl --fail https://api.example.com/web/identityand confirm it returnspayloadandsignature. - Send an authenticated
/scrape, then fetch its media URL with the sameX-API-Keyand a testRangeheader. - From the Web hostname, complete Turnstile and confirm
/web/verify, scrape, and media playback through the Web BFF.
5. Update safely
Section titled “5. Update safely”Pin explicit GHCR release tags for repeatability, then:
docker compose pulldocker compose up -ddocker compose pscurl --fail https://api.example.com/healthRoll back by restoring previous tags and running docker compose up -d. Preserve scraper-cache. Never use docker restart gluetun; use docker compose up -d --force-recreate gluetun, recreate affected dependent services if necessary, and verify health.