-
-
Notifications
You must be signed in to change notification settings - Fork 634
[Self-Hosted] Custom domain resolution broken on status-page — middleware hardcoded to stpg.dev #1968
Description
Description
When self-hosting OpenStatus via Docker Compose, custom domains configured
on a status page do not resolve correctly. Instead of serving the status page,
visiting the custom domain redirects to the theme editor with a 400 Bad Request
tRPC error.
Environment
- Self-hosted via Docker Compose
- Image: ghcr.io/openstatushq/openstatus-status-page:latest
- Reverse proxy: Nginx
- DNS/CDN: Cloudflare
Steps to Reproduce
- Deploy OpenStatus via Docker Compose using the official self-hosting guide
- Create a status page and set a custom domain (e.g.
status.example.com) - Configure DNS A record pointing to your server IP
- Configure Nginx to proxy
status.example.com→localhost:3003 - Visit
status.example.com
Expected Behavior
The public status page loads at the custom domain.
Actual Behavior
The app redirects to the theme editor. The tRPC call to statusPage.get
sends slug: null because the custom domain lookup fails.
Container logs show:
{
hostnames: [ 'localhost', '3000' ],
host: 'localhost:3000',
urlHost: 'status-admin.veteranmx.com',
subdomain: 'status-admin.veteranmx.com'
}
Root Cause (Investigated)
Inspecting the compiled middleware in the status-page container:
docker exec openstatus-status-page grep -o ".\{50\}urlHost.\{50\}" \
/app/apps/status-page/.next/server/edge/chunks/_56137d89._.jsReturns:
return console.log({hostnames:a,pathnames:s,host:n,urlHost:r.host,subdomain:o}),
a.length>2&&"www"!==a[0]&&!r.host.endsWith(".vercel.app")
The middleware derives the host from r.host (the incoming request), which
resolves to localhost:3000 internally. Additionally, the middleware contains
routing logic hardcoded to the hosted platform's stpg.dev subdomain pattern:
has:[{type:"host",value:"(?[^.]+).stpg.dev"}]
This means custom domain resolution is built around the hosted SaaS
infrastructure and does not work in a self-hosted context where r.host
will always be the container's internal address.
Setting proxy_set_header Host status.example.com and
proxy_set_header X-Forwarded-Host status.example.com in Nginx does not
resolve the issue since the edge runtime reads the actual request host,
not the forwarded header.
Workaround
Access the status page via its slug URL instead:
https://status.example.com/your-slug
And use an Nginx redirect for the root path:
location = / {
return 301 https://status.example.com/your-slug;
}Suggested Fix
The middleware should fall back to custom domain lookup via the database
when running in self-hosted mode (SELF_HOST=true), using
X-Forwarded-Host or a configurable STATUS_PAGE_URL environment
variable to determine which page to serve, rather than relying on
r.host or the stpg.dev subdomain pattern.
Additional Context
The custom domain UI in the dashboard also shows an A record prompt
pointing to 76.76.21.21 (the hosted platform IP), which is not
relevant for self-hosted deployments. This adds confusion during setup.