Self-hosting
Running your own Happier relay — how to deploy it, how to configure who may sign in, and what the server keeps.
This section is about running your own Happier relay (the sync backend that clients and machines connect to). Everything here is optional: Happier Cloud exists so you do not have to.
Your clients and machines then point at your URL — say https://api.example.com
— instead of the Cloud one. Nothing else about how you use Happier changes.
Pick how to run it
Server quickstart
The minimum production configuration, and which env vars actually matter.
Docker
Compose files for single-container and split API/worker deployments.
Self-host runtime
A managed service on a host or VPS — what the installer and the runner each own.
Run from a monorepo clone
Repo-local mode, for developing or customizing from source.
Proxmox VE
Deploying with the community helper scripts.
If you are unsure: Docker if you already run a supervisor, the self-host runtime if you want a managed service on a plain host, and repo-local if you are changing the server itself.
Configure it
- Environment variables — the complete server runtime surface. The canonical template is
apps/server/.env.example. - API rate limits — every limited endpoint, its default, and the two variables that change it.
Decide who may sign in
This is the part that takes the longest and is the easiest to get subtly wrong, so it has a page per provider rather than one long one.
- Auth overview — the policy model, and how the pieces below combine.
- GitHub — OAuth for signup and connect, plus allowlists.
- OIDC — Okta, Auth0, Entra ID, Keycloak and anything else generic.
- mTLS — client certificates from your MDM, auto-provisioning, and mapping one person's devices to one identity.
- Custom providers — adding your own without forking the core auth logic.
Decide what the server keeps
- Encryption and plaintext storage — whether session content is stored end-to-end encrypted or readable by the server.
- Retention — automatic cleanup. The default is to keep everything forever.
Understand what you are running
- How Happier fits together — the three moving parts, and what that means for a proxy in front of them.
- Protocol — the event contract between clients, the relay and your machines.
Flavors
Both flavors run the same API and the same logic. The difference is only which storage backends they use.
- Full — external Postgres (default) or MySQL 8.0.16+, with S3 or a
compatible store (default;
HAPPIER_FILES_BACKEND=localswitches to disk). Redis is optional and only needed for multi-replica realtime. - Light — SQLite (default) or embedded Postgres (PGlite) on disk, with local
file storage served by the server at
GET /files/*.
Use full for a shared server; use light for the easiest single node.
With SQLite and no DATABASE_URL, the server requires
HAPPIER_SERVER_LIGHT_DATA_DIR and refuses to start without it.
Roles and scaling
One process is the simple case. To split it, set SERVER_ROLE:
SERVER_ROLE | What the process does |
|---|---|
unset (default all) | API, realtime and background work together |
api | API and realtime only — this is what clients connect to |
worker | background work only, no HTTP listener |
Two things about that table are worth knowing before you rely on it:
- An unrecognized value is not an error. Anything other than
apiorworker— including a typo — silently resolves toall. A misspelledSERVER_ROLE=wrokergives you a second full server, not a worker. workerrequires the Redis adapter. The process throws at startup unlessREDIS_URLis set andHAPPIER_SOCKET_ADAPTER=redis-streams, because a worker publishes to rooms it has no direct sockets for.
The converse also holds: once the Redis adapter is on, durable machine-presence
writes move to a worker. An all-api deployment with Redis enabled will log
that it needs one, and presence will not be written durably until you run one.
For multi-replica API deployments, enable Redis fanout and configure sticky sessions at your load balancer. Docker has a working example.
Reverse proxy basics
In production, run the API behind a proxy that:
- terminates TLS,
- supports WebSocket upgrades — Socket.IO realtime lives at
/v1/updates, - uses timeouts long enough for a long-lived connection,
- and keeps secrets in your platform's env or secret manager rather than in git.
If you serve /files/* from the server (light flavor), allow those routes too.
Broken /v1/updates upgrades are the single most common self-hosting failure,
and they do not look like a networking problem: machines register fine and
then sit there offline, reported as machine.none_online. See
Environment variables → Networking.
Related
The local stack CLI can also bootstrap a remote host over SSH, which is often faster than doing it by hand:
- Remote server setup (SSH) — installing the self-host server on a remote host.
- Remote daemon setup (SSH) — installing Happier and pairing credentials on one.