Run Pulsy on your own infrastructure
Pulsy is a small Docker stack: Postgres, a Node server that also runs the check scheduler, and nginx serving the built SPA. Bring it up with four commands, point it at your domain, and every capability is on — no licence key, no tiers, no phone-home.
What you need
Modest. Pulsy runs comfortably on the smallest VPS most providers sell.
- A Linux host with Docker and the Compose plugin installed.
- About 1 GB of RAM and a little disk for Postgres — check history is the only thing that grows.
- A domain name, and a TLS-terminating reverse proxy in front for production.
- Outbound network access, so the checker can reach the endpoints you monitor.
Quickstart
From a clean host to a running instance.
# 1. Clone the repository and create your environment file
git clone https://github.com/SelmiAbderrahim/pulsy.org.git pulsy && cd pulsy
cp .env.example .env
# 2. Generate the two required secrets and paste them into .env
openssl rand -base64 32 # -> ENCRYPTION_KEY
openssl rand -base64 32 # -> BETTER_AUTH_SECRET
# 3. Start the full stack (postgres + server + web)
# The server applies the database schema on startup.
make start
# 4. Seed a demo user and two example monitors
make seedOpen http://localhost:3000 and sign in with the seeded demo account. Tail logs with `make logs`; stop everything with `make stop`. The server applies the database schema on startup, so there is no separate migration step for a fresh install.
Environment variables
All configuration lives in a single root `.env`, copied from `.env.example`.
| Variable | Requirement | Purpose |
|---|---|---|
ENCRYPTION_KEY | Required | AES-256-GCM key protecting email-provider credentials at rest. Generate with `openssl rand -base64 32`. |
BETTER_AUTH_SECRET | Required | Signs session cookies. Generate the same way, and keep it distinct from the encryption key. |
PUBLIC_SERVER_URL | Required | The public address of the API server. Used for links and callbacks. |
PUBLIC_WEB_URL | Required | The public address of the web app. Also the canonical origin for SEO and status pages. |
BETTER_AUTH_URL | Required | The origin better-auth issues and validates sessions against. |
RESEND_API_KEY | Optional | Set it, with `EMAIL_FROM`, to actually send verification and password-reset mail. Left unset, the server logs email metadata only and omits bodies, because they can contain reset tokens. |
Rotating ENCRYPTION_KEY makes any already-encrypted provider secrets unrecoverable. Set it once, back it up, and treat it like a database password.
What actually runs
Three containers on one host. No queue, no external services, nothing to sign up for.
pulsy-postgresThe datastore. Monitors, check logs, incidents, and status-page configuration all live here — this is the only container holding state, so it is the only one you need to back up.
pulsy-serverThe tRPC API, the better-auth handler, and the node-schedule check scheduler. The scheduler runs inside this process, so monitors are checked for exactly as long as this container is up.
pulsy-webThe built React SPA served by nginx, which proxies /api/* to the server so the browser stays same-origin and session cookies just work.
Day two
Upgrading
Pull and restart. The server runs an idempotent schema push on startup, so a version bump does not need a manual migration step. Read the changelog first if you are skipping several releases.
git pull
make start # rebuilds the images and re-applies the schemaBackups
Postgres holds everything that matters. Dump it on whatever schedule your check history is worth, and store the dump off the host — alongside your ENCRYPTION_KEY, without which encrypted provider secrets in that dump cannot be read.
docker compose -f docker/docker-compose.yml --env-file .env \
exec postgres pg_dump -U "$POSTGRES_USER" "$POSTGRES_DB" > pulsy-backup.sqlFrequently asked questions
- Is self-hosted Pulsy limited compared to Pulsy Cloud?
- No. The self-hosted build has no tiers, no feature flags gating capabilities, and no monitor limit. Every notification channel, status pages with custom domains, TLS-expiry alerting, incident tracking, and the full API are all on. Pulsy Cloud runs the same code; what you pay for there is that someone else operates it.
- Do I need a licence key or an account to self-host?
- No. There is no key, no activation, and no phone-home. Clone, configure, and run — the software never contacts pulsy.org.
- How much does it cost to run?
- Whatever your host costs. Pulsy itself is free forever under AGPL-3.0. The stack fits on a small VPS; the only thing that grows over time is Postgres, and check-log retention is configurable.
- Can I move from Pulsy Cloud to self-hosted later, or the other way?
- Yes, in both directions. It is the same software, so nothing is stranded by the move. Cloud data is exportable at any time.
- Where do checks run from when I self-host?
- From wherever you deploy Pulsy. That is an advantage for monitoring internal or firewalled endpoints a hosted service cannot reach, and a limitation if you want multi-region vantage points — for that, deploy more than one instance.
Start monitoring in minutes
Fully-managed uptime monitoring — every channel, status pages, and TLS-expiry alerts included. Start free.