Docs Self-hosting
Self-hosting Obscenter
Obscenter on your own server, installed by us on request: what the server needs, one SQLite database, environment variables, a reverse proxy, the first admin.
Obscenter is one Node.js program and one SQLite database. There is no npm install, no build step, no message queue and no separate database server. What runs on your server is the same software that runs obscenter.site.
What the server needs
- A Linux server that you control, with an address your sites and servers can reach, and SSH access for the installation.
- Node.js 22.5 or newer, for the built-in
node:sqlitemodule. If the machine's system Node is older and shared with other software, we put a newer Node beside it for Obscenter alone, rather than upgrading the shared one. - A disk for the data directory. Roughly 8 kB per visitor session with resources on. See Data, retention and backups.
- Optional: Chrome, Chromium or Edge, for browser synthetic checks.
- Optional: JMeter, for load tests. Otherwise it is fetched on Linux.
The server has zero npm dependencies. The client's two libraries, Leaflet and rrweb, are vendored and served by the install, never from a CDN. Nothing in the dashboard loads from another host, apart from the map tiles, which you can turn off.
The first administrator
The first account on an install becomes its administrator and owns the first organisation. We create it during the installation, before the address is reachable from the internet, because setup is open only while there are no accounts. The /health endpoint answers with the uptime and whether setup is done.
/demo.html?key=<app key> is a test page with buttons that throw an error, call an API, rage-click and change route.
Configuration
Settings come from the environment, then .env.local, then .env. The real environment wins. .env.example lists the common ones.
| Variable | Default | Meaning |
|---|---|---|
PORT / HOST | 8420 / 0.0.0.0 | Where it listens. Behind a proxy, use 127.0.0.1. |
PUBLIC_URL | none | The address sites, servers and devices reach. It goes into every tag, installer command, mail link and the Google redirect. Wrong here means every snippet points at the wrong place. |
COLLECT_URL | PUBLIC_URL | A separate address for tags to load from and report to. |
DATA_DIR | ./data | The database, the secret and backups. Keep it outside the code directory. |
SECRET | generated | Signs sessions and salts the IP hash. Generated into DATA_DIR/secret if unset. Losing it signs everybody out. |
TRUST_PROXY | 0 | Set to 1 behind a reverse proxy. Without it every visitor is the proxy's address, geo is blank, and the session cookie is not marked Secure. |
RETENTION_RAW_DAYS / RETENTION_AGG_DAYS | 30 / 400 | Raw events, and hourly aggregates. |
SESSION_DAYS | 30 | Dashboard sign-in, renewed on activity. |
STORE_IP | 0 | Store visitors' raw IP addresses. See Privacy. |
ASSET_AUDIT_ALLOW_PRIVATE | 0 | Let the asset audit, synthetic checks, webhooks and workflow requests reach private and LAN addresses. |
MAP_TILES, MAP_ATTRIBUTION, MAP_MAX_ZOOM | OpenStreetMap, its credit, 12 | MAP_TILES=off uses the built-in offline map. |
OBSCENTER_AI_KEY | none | A model provider key, if you add a model under Settings → AI. |
OBSCENTER_GOOGLE_CLIENT_ID, …_SECRET | none | Google sign-in, as an alternative to the settings card. |
OBSCENTER_BROWSER | found | Path to the browser for browser checks. |
LOADTEST_ENGINE_AUTO, JMETER_BIN | on, found | Set the first to 0 to stop fetching JMeter. |
BACKUP_HOURS, BACKUP_KEEP, BACKUP_OFF | 24, 3, unset | Automatic backups. |
NOTIFY_OUTBOUND | on | 0 makes this node send no mail, webhooks or workflow calls. |
Mail is not configured in the environment. The install's first email channel, under Settings → Notifications, sends its confirmations, invitations and alert mail. See Email. Variables for running several nodes are on Nodes and mirrors.
Behind a reverse proxy
Run it on 127.0.0.1 and put nginx, or another proxy, in front with TLS. Set TRUST_PROXY=1, and have the proxy set X-Real-IP from the connection it accepted, plus X-Forwarded-Proto. X-Real-IP is preferred over X-Forwarded-For, because a client can pre-fill the latter. Pass a geo header such as CF-IPCountry if your CDN provides one. A beacon batch can be up to 2 MB and a replay upload up to 8 MB, so allow request bodies of 10 MB.
Running it as a service
The install runs as a systemd service with a watchdog beside it and an nginx vhost in front, the same way obscenter.site runs. The watchdog checks /health every 30 seconds, restarts the service after five missed answers, and stops and asks for a person after two restarts in half an hour.
First steps after the handover
We set PUBLIC_URL and TRUST_PROXY and create the administrator. What is left is yours:
- Add an email channel, so the install can send mail.
- Decide whether registration should stay open. It is open by default: Settings → Accounts → Organisations → Open registration.
- Follow Getting started.
The command line
On the server, in the install's directory:
node server/cli.js setup <email> <password> # an administrator
node server/cli.js users # accounts and active sign-ins
node server/cli.js passwd <email> <password> # set a password
node server/cli.js user:del <email>
node server/cli.js app:add <name> [origins] | apps | snippet <id|key>
node server/cli.js seed [app] [days] # demo traffic
node server/cli.js reset [app] # wipe measurements, keep logins
node server/cli.js rollup | purge
Unlike changing a password in the dashboard, passwd does not end the account's existing sessions.