Scheduling and bookings on your own server.
Share a booking link, set your availability, and let invitees pick a time — no back-and-forth email. Runs on your own server, on your own database, with nothing phoning home.
What makes it different
Most of these follow from one decision: it is a real application you run on your own server, not a service someone else hosts.
-
No account to make
Invitees pick a time with a name and an email — no password, no registration wall. The link takes them back to read confirmations and updates.
-
Email that keeps trying
Outgoing mail is queued and retried rather than quietly dropped when your provider has a bad day. No-show reminders and confirmations are durable, not best-effort.
-
Health checks that mean something
GET /api/healthruns a real query against your database — not just whether the process is alive. The container’s own DockerHEALTHCHECKuses it, so a load balancer or uptime monitor sees the same truth your orchestrator does. -
Admin screens where you work
User management, queue state, and platform settings live under
/settings/*inside the dashboard, gated by role. No separate admin panel, no second login. -
Config that refuses to start broken
Every variable is validated at boot. A missing or invalid required value makes the app refuse to start and print exactly which one failed — rather than breaking halfway through a request.
-
Your storage, your way
Local disk in development; S3 or Cloudflare R2 in production, one setting. Your data stays where you put it.
Installing it
You need Docker, and nothing else. No separate Node.js or PostgreSQL install — the images are prebuilt and PostgreSQL comes with them.
-
Get the two files
A compose file and an environment file. That is the whole setup.
curl -O https://raw.githubusercontent.com/stack256org/scheduled/main/docker-compose.yml curl -o .env https://raw.githubusercontent.com/stack256org/scheduled/main/.env.docker.example -
Set three values
APP_SECRET(32+ random characters, fromopenssl rand -hex 32),APP_URL, andDATABASE_URL. Everything else has a working default. -
Start it
This pulls both images, starts PostgreSQL, migrates the database, and leaves the app and worker running.
docker compose up -d -
Open it
First run walks you through creating the admin account. No separate terminal step needed.
http://<this host’s address>/
You need two images. The app
(ghcr.io/stack256org/schduled) serves traffic, and the
worker (ghcr.io/stack256org/schduled-worker) sends
email and runs background jobs — nothing sends without it.
The compose file starts both for you.
What it needs
| Host | Anything that runs containers — Compose, Coolify, Dokploy, Portainer, Kubernetes, Swarm, ECS |
|---|---|
| Images |
ghcr.io/stack256org/schduled and
ghcr.io/stack256org/schduled-worker
|
| Architectures | amd64 and arm64, in every tag |
| Processes | The app, a worker (email and background jobs), and a one-off migrate step |
| Database | PostgreSQL 16+ — bundled, or point it at your own (Neon, Supabase, RDS) |
| File storage | Local disk, S3, or Cloudflare R2 — one setting |
| Health check |
GET /api/health, unauthenticated, reports
database reachability
|
| Licence | MIT |
Have a look at the code
Schduled is the fourth of 256. The README covers full production setup, HTTPS, backups, and everything else in detail.