Building Images & Deploying¶
Prerequisites¶
GitHub CLI¶
You need the GitHub CLI (gh) installed and authenticated:
GHCR Package Push Access¶
Your GitHub token must include the write:packages scope to push images to GitHub Container Registry. Add it with:
You can verify your scopes with gh auth status.
Docker Buildx¶
Docker Buildx is required for multi-platform builds. It comes bundled with Docker Desktop.
Tube token¶
Deployments are triggered via the Tube internal service. You need a TUBE_TOKEN in your .env.prod file (found in 1password):
Building & Pushing Images¶
Images are built using Docker Bake with the config in docker-bake.hcl. The bake file defines these targets:
| Target | Dockerfile | Description |
|---|---|---|
paperrun-api-base |
Dockerfile |
Base image shared by all services |
paperrun-api-web |
Dockerfile.web |
API server |
paperrun-api-celery |
Dockerfile.celery |
Celery worker |
paperrun-api-mcp |
Dockerfile.mcp |
MCP server |
Images are tagged with the short commit hash and pushed to ghcr.io/paper-run/paperrun-api/.
Deploying to Production¶
Full deploy (all services)¶
This builds all images, pushes them to GHCR, then calls the Tube service to update all services to the new image tag.
Selective deploy (subset of services)¶
Interactively pick which services to deploy from the live Tube list. Other matched prefixes get marked partial-<tag> in GHCR so you can tell them apart from a full release.
Redeploy current images¶
Tells Tube to redeploy the services at their current image tags — useful for picking up an env-var change without building a new image. Only prod is accepted.
Deploying to Staging¶
Same flow as deployprod, but the image tag is prefixed with staging- (so prod and staging images are distinguishable in GHCR) and the deploy targets the staging Railway environment via Tube's --staging flag.
The staging Railway environment ID lives alongside the production one in app/scripts/tube.py; the project ID is shared.
Rollback¶
Rollback returns services to the previous clean image set tracked by Tube — no rebuild, no GHCR push.
Both recipes prompt for confirmation. To preview without mutating Railway, call the script directly with --dry-run:
uv run --env-file .env.prod -m app.scripts.tube rollback --dry-run # prod
uv run --env-file .env.prod -m app.scripts.tube rollback --staging --dry-run # staging
Use tube services [--staging] to confirm current tags before and after.
Troubleshooting¶
403 Forbidden when pushing images¶
Your token is missing the write:packages scope. Run:
invalid reference format in image tag¶
Make sure git remote get-url origin returns a valid GitHub URL. The deploy commands parse this to build the GHCR registry path.