Skip to content

Fix/status page forwarded host routing#1977

Open
aiokaizen wants to merge 4 commits intoopenstatusHQ:mainfrom
aiokaizen:fix/status-page-forwarded-host-routing
Open

Fix/status page forwarded host routing#1977
aiokaizen wants to merge 4 commits intoopenstatusHQ:mainfrom
aiokaizen:fix/status-page-forwarded-host-routing

Conversation

@aiokaizen
Copy link
Copy Markdown

  • Fixes custom-domain routing for self-hosted status pages behind a reverse proxy.
  • The status-page app was reading x-forwarded-host, but then still derived subdomain from url.host.
  • In self-hosted Docker deployments, url.host is the container host (0.0.0.0:3000 / localhost:3000), not the public domain.
  • That caused the resolved routing prefix to be overwritten with the container host, breaking custom-domain routing.
  • Result: requests for domains like status.pinbridge.io could fall back to the public root/theme-builder flow instead of the intended status page.
  • This patch introduces effectiveHost = x-forwarded-host ?? url.host and uses it consistently for:
    • hostname splitting
    • subdomain detection
    • .vercel.app checks
  • Updated files:
    • apps/status-page/src/proxy.ts
    • apps/status-page/src/lib/domain.ts
  • This is especially important for self-hosted setups behind nginx or another reverse proxy that forwards the public host.
  • No version changes included.

@vercel
Copy link
Copy Markdown

vercel Bot commented Mar 13, 2026

@aiokaizen is attempting to deploy a commit to the OpenStatus Team on Vercel.

A member of the Team first needs to authorize it.

@vercel
Copy link
Copy Markdown

vercel Bot commented Mar 13, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
openstatus-dashboard Ready Ready Preview, Comment Mar 13, 2026 10:44am
openstatus-status-page Ready Ready Preview, Comment Mar 13, 2026 10:44am
openstatus-web Ready Ready Preview, Comment Mar 13, 2026 10:44am

Request Review

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR primarily fixes self-hosted status-page domain routing behind reverse proxies by consistently using x-forwarded-host (when present) instead of the container host, and it additionally introduces broader self-host wiring for checker/workflows, Redis, and public URL configuration.

Changes:

  • Fix status-page routing by introducing effectiveHost = x-forwarded-host ?? url.host and using it for hostname/subdomain detection.
  • Add self-host mode support across API/server/workflows/checker (configurable checker/workflows base URLs, region handling, and direct-dispatch fallbacks when Cloud Tasks aren’t available).
  • Update Docker compose + env examples to run Redis + redis-http shim and a local checker service, and introduce a dashboard public URL helper used for absolute redirect/callback URLs.

Reviewed changes

Copilot reviewed 24 out of 24 changed files in this pull request and generated 15 comments.

Show a summary per file
File Description
packages/api/src/router/checker.ts Adds self-host checker routing helpers and uses them for ping/tcp/dns tests + trigger URL generation.
packages/api/package.json Version bump.
docker-compose.yaml Adds Redis + redis-http shim, local checker service, and self-host env wiring across services.
docker-compose.github-packages.yaml Mirrors compose changes for GitHub Packages deployment.
apps/workflows/src/env.ts Adds SELF_HOST and base URL/region envs for self-host.
apps/workflows/src/cron/monitor.ts Skips Cloud Tasks usage in self-host/missing-config scenarios and threads context through task creation.
apps/workflows/src/cron/checker.ts Adds direct checker dispatch path when self-host or Cloud Tasks config missing.
apps/status-page/src/proxy.ts Uses effectiveHost for hostname/subdomain routing decisions.
apps/status-page/src/lib/domain.ts Uses effectiveHost for custom-domain parsing and routing decisions.
apps/status-page/package.json Version bump.
apps/server/src/routes/v1/check/http/post.ts Supports self-host checker base URL/region for manual HTTP checks.
apps/server/src/routes/slack/oauth.ts Makes dashboard redirect base configurable via env and trims trailing slash.
apps/server/src/libs/checker/utils.ts Uses self-host checker base URL when generating checker URLs.
apps/server/package.json Version bump.
apps/dashboard/src/lib/public-url.ts New helper for consistent dashboard public URL construction.
apps/dashboard/src/components/data-table/billing/data-table.tsx Uses dashboard public URL for Stripe success/cancel URLs.
apps/dashboard/src/app/(dashboard)/settings/integrations/slack-card.tsx Switches Slack install redirect base to dashboard public URL helper.
apps/dashboard/src/app/(dashboard)/settings/general/page.tsx Uses dashboard public URL for invite link base.
apps/dashboard/src/app/(dashboard)/settings/billing/client.tsx Uses dashboard public URL helper.
apps/dashboard/src/app/(dashboard)/notifications/client.tsx Uses dashboard public URL for PagerDuty redirect URL base.
apps/dashboard/package.json Version bump.
apps/checker/checker/update.go Adds direct HTTP fallback for posting status updates to workflows when self-host.
.env.docker.example Updates self-host defaults (Redis shim, checker/workflows routing).
.env.docker-lightweight.example Adds self-host routing + Redis shim envs for lightweight setup.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

You can also share your feedback on Copilot code review. Take the survey.

Comment on lines +27 to +44
function isSelfHost() {
return process.env.SELF_HOST === "true";
}

function getCheckerBaseUrl() {
return (process.env.CHECKER_BASE_URL || "http://checker:8080").replace(
/\/$/,
"",
);
}

function getCheckerRegion(region: string) {
if (!isSelfHost()) {
return region;
}

return process.env.CHECKER_REGION || "ams";
}
const cloudTaskContext = getCloudTaskContext("workflow");
if (!cloudTaskContext) {
console.log(
"Skipping monitor lifecycle workflow: Cloud Tasks are unavailable in self-host mode.",
Comment on lines +10 to +19
function isSelfHost() {
return process.env.SELF_HOST === "true";
}

function getCheckerBaseUrl() {
return (process.env.CHECKER_BASE_URL || "http://checker:8080").replace(
/\/$/,
"",
);
}
Comment on lines 493 to +496
function generateUrl({ row }: { row: z.infer<typeof selectMonitorSchema> }) {
if (isSelfHost()) {
return `${getCheckerBaseUrl()}/checker/${row.jobType}?monitor_id=${row.id}`;
}
process.env.NODE_ENV === "production"
? "https://api.openstatus.dev"
: "http://localhost:3000";
const SERVER_URL = getDashboardPublicUrl();
c: Context,
) {
const timestamp = Date.now();
const selfHostRegion = env().CHECKER_REGION as Region;
Comment on lines +45 to +57
req, err := http.NewRequestWithContext(ctx, http.MethodPost, url, payloadBuf)
if err != nil {
log.Ctx(ctx).Error().Err(err).Msg("error while creating update request")
return err
}
req.Header.Set("Authorization", basic)
req.Header.Set("Content-Type", "application/json")

res, err := http.DefaultClient.Do(req)
if err != nil {
log.Ctx(ctx).Error().Err(err).Msg("error while posting update status directly")
return err
}
Comment thread packages/api/package.json
{
"name": "@openstatus/api",
"version": "1.0.0",
"version": "1.0.1",
Comment thread docker-compose.yaml
- "8079:80"
environment:
- SRH_MODE=env
- SRH_TOKEN=${UPSTASH_REDIS_REST_TOKEN:-replace-with-a-long-random-secret}
Comment on lines +83 to +84
- SRH_MODE=env
- SRH_TOKEN=${UPSTASH_REDIS_REST_TOKEN:-replace-with-a-long-random-secret}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants