ProliferateDocs
Join the beta

Troubleshoot

Diagnose a self-hosted deployment with doctor.sh, preflight.sh, and known failure signatures.

Two scripts in the deploy directory (/opt/proliferate/server/deploy on a guided install) cover the vast majority of self-hosting problems: preflight.sh catches a dangerous configuration before it touches a running instance, and doctor.sh reports the current state of everything, redacting every secret value along the way.

preflight.sh: catches bad config before it boots#

bootstrap.sh and update.sh both run preflight.sh on the resolved .env.runtime, right after secrets are generated and before any docker compose lifecycle command — so a dangerous partial config fails here, leaving a previously healthy instance untouched instead of crash-looping it. Run it by hand any time:

bash
sudo ./preflight.sh

It checks, in order: SITE_ADDRESS is set (or the sslip fallback is on) and isn't still the placeholder value; the cloud sandboxes credential pair is complete or both empty (the crash-loop trap); the agent gateway's master key, Postgres password, public URL, and at least one provider key are all present when AGENT_GATEWAY_ENABLED=true; the bundled Redis URL still points at the bundled service when cloud workspaces are configured; OIDC SSO has a client id, secret (unless a public client), and an endpoint source when SSO_ENABLED=true, plus a warning if the default SSO_JIT_POLICY=disabled combined with an empty ADMIN_EMAILS would lock every SSO user out; GitHub OAuth and the GitHub App each have complete credential pairs; the cloud-sandbox runtime binaries are reachable; and any env key that isn't in .env.production.example or the documented advanced overrides (likely a typo).

Exit code 0 means no errors (warnings may still have printed); 1 means an error was found and the caller must not replace a healthy stack. PROLIFERATE_PREFLIGHT_STRICT=1 treats warnings as errors too, for CI-style gating.

doctor.sh: what's actually running#

bash
sudo ./doctor.sh

Reports, section by section: host (OS, architecture, Docker/Compose, disk, ports 80/443); configuration (the same shape checks as preflight); compose services and enabled profiles; local and public /health + /meta, DNS resolution, and TLS certificate expiry; version compatibility against the newest published server-v* release; Redis (only checked when cloud workspaces are configured); the agent gateway (litellm running + healthy, the public /llm endpoint reachable, at least one provider key set — only checked when enabled); deployment SSO (only checked when enabled, including the same first-user-lockout warning as preflight); and the shape — never the value — of GitHub OAuth, the GitHub App, cloud sandboxes, and Resend configuration. It ends with a pass/warn/fail summary.

Every secret is reported as set (N chars) or not set, never the actual value, so it's safe to paste doctor output into a support request.

Known failure signatures#

SymptomLikely causeFix
Whole instance offline after an env change, api container RestartingA half-configured cloud sandboxes credential pairpreflight.sh should have caught this before you ran update.sh; set the missing value, or clear both, and rerun.
Public /health never responds after launchDNS not pointed at the host yet, or ports 80/443 blockeddoctor.sh's Endpoints section reports DNS resolution and port checks. Let's Encrypt needs both ports reachable from the internet.
Raw docker compose pull/up fails with a missing env file errorRan Compose directly instead of through the scriptsUse ./update.sh (or --env-file .env.runtime, since Compose's default .env doesn't exist in this bundle).
Gateway session gets 400 Invalid model nameOffered a native model selector (e.g. default) on a gateway-only routeShould not happen after #1106 — file it as a bug rather than a config issue; readiness and launch are meant to agree on the credential route.
Invitation never arrives by emailNo RESEND_API_KEY set (the self-hosted default)Expected: use the Copy invite link action in the members list; delivery shows as skipped, not failed.
GitHub sign-in shows "redirect_uri mismatch"OAuth app's callback URL doesn't matchRegister exactly <API_BASE_URL>/auth/github/callback — see GitHub sign-in.

Logs#

bash
docker compose --env-file .env.runtime -f docker-compose.production.yml logs -f api

Swap api for caddy, db, litellm, or redis as needed (run from the deploy directory).

Note

Neither script requires network egress beyond what it's already checking (the public health probe and the release-version check); both run entirely against the local .env.runtime/.env.static otherwise.