How HomeFree is built
This is the entry point for anyone hacking on HomeFree itself — adding new services, fixing bugs, customizing a deployment beyond the installer's options. If you're just running HomeFree on your own box, you don't need anything on this page.
What HomeFree is, technically
HomeFree is a single NixOS configuration that wires together about twenty containerized services behind one reverse proxy, with one identity provider providing SSO across all of them. The whole system is declarative: the running machine is a build artifact of a Nix flake.
The headline pieces:
- NixOS — the base OS. Everything is configured in
*.nixfiles.nixos-rebuild switchis how you change anything. - Podman — runs each app as an isolated container. One container per app (FreshRSS, Immich, Nextcloud, etc.). State lives outside the container at
/var/lib/<app>-podman/. - Caddy — the single reverse proxy. Terminates TLS, fronts every app at its own subdomain (
freshrss.<domain>,immich.<domain>, etc.), and gates web UIs behind the SSO check viaforward_auth. - Zitadel — the identity provider. Native OIDC. Apps integrate either through Caddy's SSO gate (web-only apps) or natively if they support OIDC themselves (FreshRSS, Nextcloud, etc.).
- PostgreSQL — the shared database backend. Each app gets its own role and database, owned by that role. No shared superuser TCP access.
- Headscale — the mesh VPN control plane (Tailscale-compatible).
- Borg + S3 — automated encrypted backups of every app's data + database.
Repo layout
~/homefree is the shared HomeFree source. It's used as-is across many boxes; instance-specific files (your domain, your hostname, your hardware-configuration.nix) live in /etc/nixos on each deployment, not in this repo.
configuration.nix/configuration.example.nix— the entrypoint.module.nix— central options namespace (homefree.*).profiles/— host/role profile compositions.services/— one*.nixper integrated service. Each file declares its container, its Postgres role/db, its Caddy reverse-proxy entry, its Zitadel client, its backup paths.scripts/— operational scripts (build, sync-config, ISO publishing, etc.).web-platform/— the admin UI (FastAPI backend + JS frontend).
SSO model
Every web UI on the box uses Zitadel. There are no local username/password forms anywhere — if you're adding a service, that's a hard requirement.
Two integration patterns:
- Native OIDC (preferred) — the app speaks OIDC directly. Configured with a Zitadel client and the app's own OIDC settings. Used by FreshRSS, Nextcloud, Immich, etc.
- Caddy
forward_authgate (fallback) — for apps that don't speak OIDC. Caddy challenges every request throughoauth2-proxybefore forwarding. The app sees an authenticated user via headers.
For APIs and DAV endpoints that can't do OIDC (mobile sync clients, CalDAV), apps use per-user API passwords or a zitadel-password-shim ROPC wrapper. See services/radicale-podman.nix and services/zitadel-password-shim.nix for the pattern.
Where things live on disk
| Thing | Path |
|---|---|
| Per-app container state | /var/lib/<app>-podman/ |
| Per-app secrets (provisioned PATs, OIDC creds) | /var/lib/homefree-secrets/<app>/ |
| Admin metadata (admin username, etc.) | /var/lib/homefree-admin/ |
| Backups (default) | Whatever homefree.backups.to-path resolves to |
| Caddy state, ACME data | /var/lib/caddy/ |
| Rendered Caddy config | /etc/caddy/caddy_config |
Next
- Advanced installation — build from source / deploy from a workstation Nix install.
TODO.mdin the repo root — current bug list and incoming feature work.#homefree:homefree.hoston Matrix for questions.