Production Deployment
Deploy Pry behind a reverse proxy with HTTPS, secrets in a manager (gopass),
and monitoring. This page is a deployment guide — the operational runbook
lives in the DEPLOYMENT.md of the pryscraper repo.
Architecture
Internet → Cloudflare (optional) → nginx (443) → pry (127.0.0.1:8005)
→ flaresolverr (127.0.0.1:8192, internal only)
| Layer | Choice |
|---|---|
| Container | Docker (docker-compose.yml) |
| Orchestration | docker compose |
| Reverse proxy | nginx |
| Auto-deploy | Forgejo webhook → deploy script |
| Secrets | gopass (or 1Password/vault) |
Reverse proxy (nginx)
All host ports in the compose file bind to 127.0.0.1 — put nginx in front
for external access:
server {
listen 443 ssl http2;
server_name pry.example.com;
ssl_certificate /etc/letsencrypt/live/pry.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/pry.example.com/privkey.pem;
location / {
proxy_pass http://127.0.0.1:8005;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_http_version 1.1;
proxy_set_header Connection "";
# WebSocket streaming (job progress) needs upgrade headers:
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_read_timeout 300s;
}
}
HTTPS
- Issue certificates with acme.sh or certbot (Let's Encrypt).
- Redirect all HTTP → HTTPS.
- Optional: put Cloudflare in front (DDoS protection, CDN). Note that
Pry's own auth already fail-closes: a keyless instance rejects every
non-loopback source with 401, so double-check the proxy
X-Forwarded-Forhandling when combining proxies.
Secrets (gopass)
No secrets live in .env in production. Seed the secrets manager:
gopass insert -m pry/jwt_secret
gopass insert -m pry/api_key
gopass insert -m pry/x402_wallet
gopass insert -m pry/x402_facilitator
The default PRY_SECRET_BACKEND=gopass resolves every secret from the store
under pry/<name> (see Configuration).
Docker loads non-secret env via env_file: .env / --env-file; secrets stay
in gopass.
Rotation policy (from SECURITY.md): API tokens quarterly, DB passwords
quarterly, signing keys on personnel change. Any leak triggers rotation within
1 hour.
Hardening checklist
- Set a strong
PRY_API_KEY(fail-closed auth for every request) - Bind API to
127.0.0.1and proxy through nginx (never expose8002/8005directly) - Keep all compose host ports loopback-only
- Secrets in gopass — never in
.envin production - Enable the
/metricsendpoint and scrape it with Prometheus - Set resource limits (compose defaults: 2 GB / 2 CPU for pry)
- Keep dependencies updated (renovate bot;
pip-auditweekly) - Restrict admin/configuration endpoints:
POST /v1/config,/v1/config/profile/tor,/v1/proxy/configurerequire the key - Firewall: only nginx ports public; everything else localhost
Schema migrations (Alembic)
The container entrypoint runs migrations before starting uvicorn:
alembic stamp head— idempotent; marks the DB up-to-date without running migrations (preserves existing data when schema already matches).- On stamp failure:
alembic upgrade head— applies pending migrations. exec "$@"— chains to uvicorn.
PRY_SKIP_MIGRATIONS=1 skips the migration step (read-only debug runs).
docker exec pry alembic current
docker exec pry alembic upgrade head # apply pending
Monitoring
| Endpoint | Purpose |
|---|---|
GET /health | Health + cache stats + active sessions |
GET /live | Liveness probe |
GET /ready | Readiness probe |
GET /metrics | Prometheus metrics |
| WebSocket streaming | Real-time job progress |
Stack: Prometheus → Grafana dashboards; Loki for log aggregation.
Deploy / rollback
# Manual deploy
git pull origin main
docker build -t pryscraper:latest .
docker stop pryscraper && docker rm pryscraper
docker run -d --name pryscraper --restart unless-stopped \
--network host -p 8005:8005 pryscraper:latest
# Health check
curl -fsS http://localhost:8005/health
# Rollback
git checkout <last-good-commit>
docker build -t pryscraper:latest .
docker restart pryscraper
# Logs
docker logs pryscraper --tail 100 -f
On merge to main, a Forgejo webhook can trigger the deploy script: pull →
rebuild → swap container → health check → rollback on failure.
Backup
- Code: Forgejo (source of truth)
- Data: daily DB snapshot +
PRY_DATA_DIR(quality, monitors, sessions, vault) - Config: secrets manager
Next steps
- Docker Compose — compose reference
- Configuration — every env var
- Troubleshooting — common production errors