Skip to content

fix: resolve broken custom domain routing in self-hosted status-page#2029

Open
johnib wants to merge 6 commits intoopenstatusHQ:mainfrom
johnib:fix/self-hosted-custom-domain-1968
Open

fix: resolve broken custom domain routing in self-hosted status-page#2029
johnib wants to merge 6 commits intoopenstatusHQ:mainfrom
johnib:fix/self-hosted-custom-domain-1968

Conversation

@johnib
Copy link
Copy Markdown
Contributor

@johnib johnib commented Mar 28, 2026

This fixes custom domain resolution for self-hosted OpenStatus deployments, as reported in #1968.

The problem

The status-page middleware has routing logic hardcoded around stpg.dev (the SaaS platform domain). When you self-host via Docker and set up a custom domain like status.mycompany.com, the middleware can't resolve it — it tries to route through stpg.dev which doesn't exist in your environment, and you end up on a broken theme editor page.

The fix

Rather than scattering SELF_HOST checks everywhere, I introduced a small isSaasSubdomain(host, slug) helper that answers "is this request hitting the SaaS subdomain?" When SELF_HOST=true, it always returns false, so the middleware correctly takes the custom domain code path.

The URL rewrite logic is now split into two paths:

  • SaaS mode (unchanged) — rewrites to {slug}.stpg.dev where hostname routing resolves the page
  • Self-hosted mode — rewrites internally using the slug in the path, since there's no subdomain infrastructure

I was careful to keep SaaS behavior identical — the new condition is logically equivalent to the old inline host !== ${slug}.stpg.dev check when SELF_HOST isn't set.

Includes 8 new unit tests covering both modes.

Closes #1968

johnib added 4 commits March 28, 2026 00:45
Switch from CLAUDE_CODE_OAUTH_TOKEN to ANTHROPIC_API_KEY auth,
remove author_association restrictions for fork usage, and add
ANTHROPIC_BASE_URL env support.
The Regions table/chart on the monitor overview page was showing data
for all possible regions (monitorRegions) instead of only the regions
the monitor is actually configured to check. This caused unconfigured
regions with zero-data rows from Tinybird to appear in the UI.

Replaced monitorRegions with monitor.regions so mapRegionMetrics only
processes regions the monitor is set up to use, plus any private
locations. Removed the now-unnecessary isLoading conditional since
mapRegionMetrics already handles the undefined-timeline case by
returning placeholder entries for the given regions.
…deployments

Hardcoded stpg.dev checks in the status-page middleware caused incorrect
routing for self-hosted deployments where the SaaS subdomain infrastructure
is unavailable. Introduces isSaasSubdomain() helper that returns false when
SELF_HOST=true, and rewrites to internal paths instead of external stpg.dev
URLs in self-hosted mode.
Split the custom-domain rewrite logic into separate SaaS and self-hosted
code paths. In SaaS mode the slug is resolved via hostname routing on
stpg.dev, so the rewrite URL must NOT include a slug prefix. In
self-hosted mode the slug prefix is required and the rewrite targets
req.nextUrl.origin instead of req.url.

Also:
- Add isSelfHosted() helper to consolidate SELF_HOST checks
- Use isSelfHosted() in both domain.ts and proxy.ts
- Remove unrelated dashboard client.tsx changes (monitor regions)
@vercel
Copy link
Copy Markdown

vercel bot commented Mar 28, 2026

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

A member of the Team first needs to authorize it.

Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

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

1 issue found across 5 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name=".github/workflows/claude.yml">

<violation number="1" location=".github/workflows/claude.yml:16">
P0: Removing the `author_association` checks allows **any** GitHub user to trigger the Claude Code action by commenting `@claude`. This exposes the repository to API credit abuse and lets untrusted users execute Claude with write permissions on pull requests and issues. Restore the authorization guards.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

Comment on lines +16 to +19
(github.event_name == 'issue_comment' && contains(github.event.comment.body, '@claude')) ||
(github.event_name == 'pull_request_review_comment' && contains(github.event.comment.body, '@claude')) ||
(github.event_name == 'pull_request_review' && contains(github.event.review.body, '@claude')) ||
(github.event_name == 'issues' && (contains(github.event.issue.body, '@claude') || contains(github.event.issue.title, '@claude')))
Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai bot Mar 28, 2026

Choose a reason for hiding this comment

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

P0: Removing the author_association checks allows any GitHub user to trigger the Claude Code action by commenting @claude. This exposes the repository to API credit abuse and lets untrusted users execute Claude with write permissions on pull requests and issues. Restore the authorization guards.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At .github/workflows/claude.yml, line 16:

<comment>Removing the `author_association` checks allows **any** GitHub user to trigger the Claude Code action by commenting `@claude`. This exposes the repository to API credit abuse and lets untrusted users execute Claude with write permissions on pull requests and issues. Restore the authorization guards.</comment>

<file context>
@@ -13,55 +13,29 @@ on:
-        (contains(github.event.issue.body, '@claude') || contains(github.event.issue.title, '@claude')) &&
-        (github.event.issue.author_association == 'OWNER' || github.event.issue.author_association == 'MEMBER' || github.event.issue.author_association == 'COLLABORATOR')
-      )
+      (github.event_name == 'issue_comment' && contains(github.event.comment.body, '@claude')) ||
+      (github.event_name == 'pull_request_review_comment' && contains(github.event.comment.body, '@claude')) ||
+      (github.event_name == 'pull_request_review' && contains(github.event.review.body, '@claude')) ||
</file context>
Suggested change
(github.event_name == 'issue_comment' && contains(github.event.comment.body, '@claude')) ||
(github.event_name == 'pull_request_review_comment' && contains(github.event.comment.body, '@claude')) ||
(github.event_name == 'pull_request_review' && contains(github.event.review.body, '@claude')) ||
(github.event_name == 'issues' && (contains(github.event.issue.body, '@claude') || contains(github.event.issue.title, '@claude')))
(
github.event_name == 'issue_comment' &&
contains(github.event.comment.body, '@claude') &&
(github.event.comment.author_association == 'OWNER' || github.event.comment.author_association == 'MEMBER' || github.event.comment.author_association == 'COLLABORATOR')
) ||
(
github.event_name == 'pull_request_review_comment' &&
contains(github.event.comment.body, '@claude') &&
(github.event.comment.author_association == 'OWNER' || github.event.comment.author_association == 'MEMBER' || github.event.comment.author_association == 'COLLABORATOR')
) ||
(
github.event_name == 'pull_request_review' &&
contains(github.event.review.body, '@claude') &&
(github.event.review.author_association == 'OWNER' || github.event.review.author_association == 'MEMBER' || github.event.review.author_association == 'COLLABORATOR')
) ||
(
github.event_name == 'issues' &&
(contains(github.event.issue.body, '@claude') || contains(github.event.issue.title, '@claude')) &&
(github.event.issue.author_association == 'OWNER' || github.event.issue.author_association == 'MEMBER' || github.event.issue.author_association == 'COLLABORATOR')
)
Fix with Cubic

johnib and others added 2 commits March 28, 2026 12:37
Biome's lint/performance/noDelete rule flags the delete operator.
Use Reflect.deleteProperty to remove env vars in tests instead.
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.

[Self-Hosted] Custom domain resolution broken on status-page — middleware hardcoded to stpg.dev

1 participant