Self-hosting overview
What runs in a Kalendee deployment, the three supported ways to run it, and how to pick between them.
What runs
Kalendee is one Ktor JVM service plus a PostgreSQL database. Everything else is optional.
| Component | Required | Notes |
|---|---|---|
| Kalendee server (Ktor + Netty, JVM 21) | Yes | Serves the web UI at /, the JSON API at /api/v1, and the built web pack bundled inside the jar. |
| PostgreSQL 17 | Yes | System of record. Flyway migrations run automatically on startup. |
| Object storage | No | Avatars. Defaults to a local directory (/data/avatars in the container); S3/R2 is optional. See Object storage. |
| Mail transport | No | SMTP or a Cloudflare Email Routing Worker. If unconfigured, mail is logged and dropped. See Email. |
| Reverse proxy | No, but expected in production | Terminates TLS. See Reverse proxy. |
The container image runs as an unprivileged user, binds 0.0.0.0:8080, persists
avatars under /data, and reads an operator config file from
/config/application.conf. The web UI is not a separate process: the Svelte/
Keel pack (kalendee.feb) is compiled into the server jar at build time, so
there is no Node runtime in production.
Deployment options
| Path | Best for | Entry point |
|---|---|---|
| Docker Compose | Most self-hosters; the supported default | docker compose up -d with the published image and a bundled PostgreSQL container. |
| Standalone binary | Hosts that do not want containers, or want to run under systemd | The fat jar (server-all.jar) or the distZip release, plus your own PostgreSQL. |
| NixOS | Declarative, reproducible fleets | The services.kalendee flake module running the published OCI image. |
All three run the same server artifact and accept the same configuration.
Decision guide
- You want the shortest working path. Use Docker Compose: copy
.env.exampleandapplication.conf.example, edit the secrets and public URL, and rundocker compose up -d. See Docker Compose. - You already run PostgreSQL and a process supervisor. Use the standalone binary with a systemd unit. See Standalone binary.
- You manage hosts with Nix flakes. Use the NixOS module. It runs the published image and expects you to provide PostgreSQL yourself. See NixOS.
- You want a fully managed image on another orchestrator (Kubernetes, Nomad, Docker Swarm). Run the published image directly; the Compose page documents the ports, volumes, health check, and configuration precedence you need.
- You only need avatars and mail to stay on your host. Any path works; S3 and external mail are independent of how the server is deployed.
What every deployment needs
- A PostgreSQL 17 database and a role/password for it. The server refuses to
start without
KALENDEE_DATABASE_PASSWORD(an empty value is allowed for trust auth). See Database. - A public base URL. Set
app.baseUrl(orKALENDEE_PUBLIC_URL) to the externally reachablehttps://URL. It is used in verification and invite emails, RSS links, and OAuth redirect URIs. There is no safe inferred default in production. - An admin seed. Set
auth.adminPassword(and optionallyauth.adminUsername, defaultadmin) so the first startup creates an admin. See Administration. - Secrets kept out of source. Put them in
.env(Compose), a runtime environment file (NixOS), or the process environment (binary) — never in a committed HOCON file. See Security.
How configuration works
Configuration is HOCON-file-first. The server loads one HOCON file; environment
variables are ${?VAR} fallbacks inside that file, so a setting can live in
either place, and an unset variable leaves the file’s default in place.
For the container, the entrypoint chooses the file in this order (highest priority first):
-config=<path>already present in the container arguments.KALENDEE_CONFIGfrom the environment./config/application.conf, if mounted./app/application.conf, baked into the image.- Otherwise, defaults embedded in the jar.
Docker Compose mounts ./application.conf at step 3. The full key reference and
precedence rules live in Configuration and
Environment variables.
Where to go next
| Topic | Page |
|---|---|
| Host, database, JVM, and network prerequisites | Requirements |
| The primary deployment path | Docker Compose |
| Running the server without containers | Standalone binary |
| Declarative NixOS deployment | NixOS |
| TLS, headers, and proxying | Reverse proxy |
| Data protection and version upgrades | Backups and upgrades |
| Users, groups, and registration | Administration |
| Hardening and the AGPL source obligation | Security |
| When something is broken | Troubleshooting |