Safe OnlineExam
Connect Canvas

Self-hosted Canvas

Endpoint overrides, issuer rules, platform signing-key requirements, and the launch-error recovery table for Canvas instances you run yourself.

The service is portable across Canvas environments, but a deployment configured with Canvas cloud defaults will not work against a self-hosted Canvas until you override its endpoints. Read this before registering a self-hosted instance.

Why a self-hosted Canvas needs overrides

The service has one active LTI platform configuration: CANVAS_DOMAIN, LTI_ISSUER, LTI_KEY_SET_URL, LTI_AUTH_URL, LTI_CLIENT_ID, and LTI_DEPLOYMENT_ID. Canvas cloud values are the defaults.

If a service still holding those defaults is registered in a self-hosted Canvas, /lti/login redirects the embedded tool frame to sso.canvaslms.com — a page that is intentionally not embeddable, so the browser shows sso.canvaslms.com refused to connect.

Set the endpoints

For self-hosted Canvas, set its JWKS and authorization endpoints (normally under ${CANVAS_DOMAIN}):

LTI_KEY_SET_URL=https://canvas.example.edu/api/lti/security/jwks
LTI_AUTH_URL=https://canvas.example.edu/api/lti/authorize_redirect

On Google Cloud these are _LTI_KEY_SET_URL and _LTI_AUTH_URL substitutions in cloudbuild-school.yaml; on Docker they are environment variables. See Configuration → Canvas and LTI endpoints.

Do not infer the issuer from the hostname

Set LTI_ISSUER to the exact iss value Canvas sends — not by guessing from CANVAS_DOMAIN. A self-hosted Canvas can still use https://canvas.instructure.com as its issuer. Keep the default unless the actual launch's iss differs.

Platform signing keys

Canvas must sign LTI launch tokens with an RSA key of at least 2048 bits. Before registering a tool, inspect ${CANVAS_DOMAIN}/api/lti/security/jwks. Do not use the legacy sample JWKs shipped with some Canvas Docker configurations — a verifier must reject undersized RS256 keys rather than accept a weaker signature.

To rotate the three platform keys on a running Canvas, run this in the Canvas web container and then restart the web service so its JWKS response reloads:

bundle exec rails runner '
  store = Lti::KeyStorage
  values = {
    CanvasSecurity::KeyStorage::PAST => CanvasSecurity::KeyStorage.new_key,
    CanvasSecurity::KeyStorage::PRESENT => CanvasSecurity::KeyStorage.new_key,
    CanvasSecurity::KeyStorage::FUTURE => CanvasSecurity::KeyStorage.new_key
  }
  store.send(:consul_proxy).set_keys(values, global: true)
  DynamicSettings.reset_cache!
'

After the restart, verify every key at ${CANVAS_DOMAIN}/api/lti/security/jwks has a 2048-bit-or-larger modulus, then reopen the external tool so Canvas issues a fresh launch token. Rotating all three keys invalidates a launch already open in an iframe — that is expected.

Detector theme loading

Self-hosted Canvas may also hit the local-file (HTTP 422) case when serving uploaded theme JavaScript. Use the hosted theme loader described in Load the detector script.

Launch-error recovery

Use the visible error to choose the next check:

What appears in CanvasMeaningRecovery
sso.canvaslms.com refused to connectThe tool is using Canvas cloud's authorization endpoint for a self-hosted Canvas.Set LTI_AUTH_URL and LTI_KEY_SET_URL to the self-hosted endpoints, deploy, and relaunch.
Canvas Signing-Key ErrorCanvas's platform JWKS contains an RSA key smaller than 2048 bits.Rotate the three Lti::KeyStorage keys above, restart Canvas web, verify the public JWKS, and reopen the tool.
Invalid LTI LaunchThe signed launch could not be verified for another reason.Reopen the tool. If it repeats, compare deployment ID, issuer, client ID, target-link URI, and public JWKS URL against the Canvas Developer Key.
Connect CanvasThe launch succeeded but the user has not granted Canvas API access to this Canvas instance yet.Select Connect Canvas and complete the authorization flow.

The full symptom index is in Troubleshooting → Canvas launch.

On this page