Self-Host the openstatus Status Page (Lightweight)
Should you self-host a status page?
Worth answering before the Docker section, because self-hosting a status page has a trap that other self-hosted software does not.
Self-host when: the page has to live inside your own network, compliance rules constrain where incident data is stored, you want infrastructure cost instead of per-seat pricing, or you intend to modify it.
Do not self-host when: the status page is your main channel for telling customers about an outage, and it would run on the infrastructure that outage affects. A status page that goes down alongside your product is worse than no status page — customers lose the one place that was supposed to answer them. If you self-host anyway, put it in a different failure domain: another provider, or at minimum a different region and account.
The cost is not the licence. The software is AGPL-3.0 and free. You pay in host, storage, TLS, domain, and your own time for upgrades and backups — and for this particular workload, in the obligation to keep it available exactly when everything else is not. If that trade sounds wrong, the hosted status page exists so someone else carries it.
For a first-hand account of what running it is actually like, a contributor wrote up self-hosting openstatus: the hurdles then, the experience now.
Problem
You want a status page to communicate incidents and maintenance to your users, but you don't need automated monitoring, analytics, or alerting. You may already have your own monitoring tools, or you simply want a lightweight way to manage your public-facing status page.
Solution
openstatus provides a lightweight Docker Compose setup that runs only 4 services: a database, a one-shot migration runner, the dashboard, and the status page. This is ideal for teams who only want to self-host the status page without monitoring, or for teams that manage incidents manually using external monitoring tools.
Lightweight vs full
The lightweight stack strips away all monitoring infrastructure. Here's what each version includes:
| Feature | Full | Lightweight |
|---|---|---|
| Status page | Yes | Yes |
| Dashboard | Yes | Yes |
| Database (libSQL) | Yes | Yes |
| Automated monitoring | Yes | No |
| Analytics & charts (Tinybird) | Yes | No |
| API server | Yes | No |
| Private location probes | Yes | No |
If you need automated monitoring, follow the full self-hosting guide instead.
Prerequisites
- Docker and Docker Compose installed
- Git installed
- Command line experience
Step-by-step guide
Part 1: initial setup and service launch
-
Clone the repository
Get the latest version of openstatus:
git clone https://github.com/openstatushq/openstatus cd openstatus -
Configure your environment
Copy the example environment file. This is a simplified version of the full configuration, with only the variables relevant to the status page and dashboard.
cp .env.docker-lightweight.example .env.dockerOpen
.env.dockerin a text editor. You must set values for the following variables:AUTH_SECRET— required for authentication. Generate a value with:openssl rand -base64 32RESEND_API_KEY— required for magic link login emails. Get a key from resend.com.
Optionally, you can configure GitHub or Google OAuth providers by filling in the
AUTH_GITHUB_*orAUTH_GOOGLE_*variables in the same file. -
Build and start services
Use Docker Compose to build and run all services in the background:
docker compose -f docker-compose-lightweight.yaml up -dThe first build takes several minutes as it compiles the Next.js applications. Subsequent starts are much faster.
Check the status of the services:
docker compose -f docker-compose-lightweight.yaml psWait until all services show as
healthybefore proceeding. Thedb-migrateservice will show as exited — this is expected, as it runs once and stops.
Part 2: application configuration
-
Access the applications
- Dashboard:
http://localhost:3000 - Status Page:
http://localhost:3001
Log in to the dashboard using email authentication (magic link). This will create your account and workspace.
- Dashboard:
-
Set workspace limits
Because this is a self-hosted instance, you need to manually set the feature limits for your workspace directly in the database. The following command updates the limits for the workspace with
id = 1:curl -X POST http://localhost:8080/ -H "Content-Type: application/json" \ -d '{"statements":["UPDATE workspace SET limits = '\''{\\"monitors\\":100,\\"periodicity\\":[\\"30s\\",\\"1m\\",\\"5m\\",\\"10m\\",\\"30m\\",\\"1h\\"],\\"multi-region\\":true,\\"data-retention\\":\\"24 months\\",\\"status-pages\\":20,\\"maintenance\\":true,\\"status-subscribers\\":true,\\"custom-domain\\":true,\\"password-protection\\":true,\\"white-label\\":true,\\"notifications\\":true,\\"sms\\":true,\\"pagerduty\\":true,\\"notification-channels\\":50,\\"members\\":\\"Unlimited\\",\\"audit-log\\":true,\\"private-locations\\":true}'\'' WHERE id = 1"]}'You can find your workspace ID by querying the database:
curl -X POST http://localhost:8080/ -H "Content-Type: application/json" \ -d '{"statements":["SELECT id, name FROM workspace"]}' -
Create your status page
In the dashboard, create a new status page, add components for the services you want to display, and publish it. Your status page will be available at
http://localhost:3001.
Service architecture
| Service | Container | Host port | Purpose |
|---|---|---|---|
| libsql | openstatus-libsql | 8080 | Database (HTTP API) |
| db-migrate | openstatus-db-migrate | — | One-shot database migration (exits after completion) |
| dashboard | openstatus-dashboard | 3000 | Admin interface |
| status-page | openstatus-status-page | 3001 | Public status page |
Data persistence
All application data is stored in the openstatus-libsql-data Docker volume.
docker compose downpreserves your data.docker compose down -vdestroys the volume and all data.
For production use, back up this volume regularly.
Troubleshooting
Containers won't start: Check the logs for the failing service:
docker compose -f docker-compose-lightweight.yaml logs <service-name>
Magic link emails not arriving: Verify that RESEND_API_KEY is set correctly in .env.docker.
Dashboard shows errors on first load: The db-migrate service may still be running. Check its status:
docker compose -f docker-compose-lightweight.yaml ps
Port conflicts: If ports 3000, 3001, or 8080 are already in use on your machine, update the host port mappings in docker-compose-lightweight.yaml. For example, change "3000:3000" to "4000:3000" to use port 4000 instead.
Frequently asked questions
Should I self-host my status page?
Self-host if you need the status page inside your own network, have compliance rules about where incident data lives, or want to run it at infrastructure cost rather than per-seat pricing. Do not self-host if the page is your primary outage communication channel and it would share infrastructure with the systems it reports on — a status page that goes down with your product is worse than no status page.
Can I self-host only the status page, without monitoring?
Yes. The lightweight Docker Compose stack runs four services — database, one-shot migration runner, dashboard, and status page — and omits automated monitoring, analytics, the API server, and private location probes. It suits teams who already have monitoring elsewhere and manage incidents manually.
Is self-hosting a status page free?
The software is free and open-source under AGPL-3.0, but running it is not. You pay for the host, the storage backing the database, TLS certificates and a domain, plus your own time for upgrades, backups, and keeping the thing online. For a status page specifically, that last item is the real cost, because it has to stay up precisely when the rest of your infrastructure does not.
Where should I host a self-hosted status page?
Somewhere with no shared failure domain with your production systems — a different provider, or at minimum a different region and account. The entire purpose of the page is to be reachable during an outage, so hosting it next to the thing that breaks defeats it.
Next steps
- Self-host openstatus (full) — add automated monitoring, analytics, and alerting.
- Hosted status page — the same status page without the upgrades, backups, and availability burden.
- Self-hosting: the hurdles then, the experience now — a contributor's account of running it.
- Join our Discord — get help from the community.