Deployment overview
The two supported ways to run the service, the invariants that hold for both, and how to choose.
The service is a single Node.js process backed by PostgreSQL. It needs a container runtime, PostgreSQL 17+, environment variables or mounted secret files, an HTTPS public origin, a one-shot migration step before each new revision, and a scheduled cleanup job. Everything else is your choice of platform.
Two supported modes
Google Cloud Run + Cloud SQL
Recommended. Managed HTTPS ingress, managed PostgreSQL, immutable Artifact Registry images, Secret Manager, and Cloud Build as the release gate that runs migrations before traffic shifts.
Docker Compose on a VPS
The same image on any Linux host. You operate DNS, TLS termination, backups, the cleanup schedule, and monitoring.
The runtime itself is provider-agnostic — the Google-specific behavior lives only in the checked-in Cloud Build files. Any platform that provides PostgreSQL 17+, public HTTPS ingress, secret injection, an exact-image migration job before traffic, and a scheduled cleanup job can run the same container.
Release invariants (both modes)
These hold no matter how you deploy. Treat them as rules, not suggestions.
The invariants
- Keep each Canvas environment isolated by URL, database, credentials, secrets, LTI deployment, and runtime identity.
- Run the exact image's migrations before sending traffic to that image.
- Deploy immutable image digests in managed environments — never a moving tag.
- Treat application rollback and schema recovery as separate decisions.
- Keep PostgreSQL private. Only the HTTPS application endpoint is public.
- Use
/healthfor process liveness and/readyfor database + schema readiness. - Do not change an existing service's name/URL unless a Canvas URL change is intentional.
Health and readiness
Two endpoints tell you the state of a revision:
| Endpoint | Meaning |
|---|---|
GET /health | The process is up and listening. Liveness only. |
GET /ready | PostgreSQL is reachable and every checked-in migration has been applied. Fails until the database is healthy and current. |
/ready failing after a deploy almost always means the migration job did not run
or did not complete against this image — see Operations
and Troubleshooting → Deployment.
The two-pass bootstrap
Both guides deploy twice on first install: once with placeholder LTI IDs to
obtain a stable URL and a working /lti/config, then again with the real
LTI_CLIENT_ID and LTI_DEPLOYMENT_ID after you register in Canvas. This is
because the Canvas registration is served by the running service. The
Setup overview shows where this fits in the whole
sequence.
What you will produce
By the end of a deploy you will have:
- A reachable HTTPS service where
/health,/ready,/lti/config, and/.well-known/jwks.jsonall respond. - A PostgreSQL 17+ database with all migrations applied.
- A secret store holding the LTI signing key, session/state secrets, Canvas API credentials, the database password, and the public SEB encryption certificate.
- A scheduled cleanup job.
Then you move on to Connect Canvas.
Pick your path: Google Cloud or Docker / VPS. Both reference the shared Configuration and Certificate management pages.
Setup overview
The entire installation on one page — the order of operations, why each step precedes the next, and a checklist you can track against.
Google Cloud Run
Full first-time provisioning on Google Cloud Run with Cloud SQL — APIs, identity, database, secrets, the stable URL, and the two-pass deploy.