forked from lukas/nixos-config
Source now lives in lukas/calendar-web instead of this flake, matching the website/dashboard pattern: pinix checks it out at /var/www/calendar-web, nginx serves the dist/ output directly, and a new gitpull-calendar-web webhook hook does `git pull && npm ci && npm run build` (esbuild) on push. Frontend/style-only changes no longer need a nixos-rebuild. - webhook.nix: new hook + build script - packages.nix: add nodejs (npm needed for the build script) - forgejo.nix: enable ENABLE_PUSH_CREATE_USER, needed to create the new repo by pushing to it rather than via the web UI - web.nix: nginx root points at /var/www/calendar-web/dist - README.md: document the new deploy path Still needs a Forgejo-side webhook added manually in the calendar-web repo settings (no API token available to script it): target http://127.0.0.1:9000/hooks/gitpull-calendar-web, push events on dev.
71 lines
2.9 KiB
Markdown
71 lines
2.9 KiB
Markdown
# Calendar setup
|
|
|
|
The calendar stack runs on `pinix`:
|
|
|
|
- Radicale provides CalDAV on the pinix Tailnet address, port `5002`.
|
|
- Nginx serves a small read-only FullCalendar frontend on the pinix Tailnet
|
|
address, port `5001`.
|
|
- LLDAP authenticates users who edit calendars through CalDAV.
|
|
- Each authenticated LLDAP user owns a private calendar namespace below their
|
|
username and can create calendars there.
|
|
- All authenticated LLDAP users can edit `calendar/public`, but cannot delete
|
|
or overwrite the shared collection itself. Anonymous access remains
|
|
read-only.
|
|
|
|
## Access
|
|
|
|
**Changed 29.07.2026:** `cal.0ff.space` and Radicale used to share the same
|
|
hostname, resolving differently depending on network (frontend externally,
|
|
Radicale directly inside the Tailnet) because two separate Traefik routers
|
|
matched it. That ambiguity was the likely cause of changes not showing up
|
|
consistently (Vikunja `#125`). Now:
|
|
|
|
- `cal.0ff.space` is always the read-only frontend, on both networks.
|
|
- Radicale moved to its own internal-only hostname:
|
|
|
|
```text
|
|
https://calendar.0ff.space
|
|
```
|
|
|
|
Only resolvable inside the Tailnet (AdGuardHome rewrite in
|
|
`hosts/blunix/localServices/adguard.nix`); there is no public route to
|
|
Radicale directly. Point CalDAV clients at `calendar.0ff.space` while on
|
|
the Tailnet.
|
|
|
|
On the public Traefik entrypoint, `cal.0ff.space` serves the read-only calendar
|
|
frontend. Its only data endpoint is:
|
|
|
|
```text
|
|
https://cal.0ff.space/calendar.ics
|
|
```
|
|
|
|
Nginx maps that exact path to Radicale's anonymously readable
|
|
`/calendar/public/` collection. Other public paths are never proxied to
|
|
Radicale, and the proxy removes credentials and cookies.
|
|
|
|
**Changed 30.07.2026:** the frontend's source moved out of this flake into
|
|
its own Forgejo repo, `lukas/calendar-web`. `nginx`'s root for `cal.${domain}`
|
|
now points at `/var/www/calendar-web/dist` on pinix, kept current by the
|
|
`gitpull-calendar-web` webhook hook (`hosts/pinix/localServices/webhook.nix`):
|
|
push to the repo's `dev` branch, the hook `git pull`s, runs `npm ci && npm run
|
|
build` (esbuild bundles FullCalendar + ical.js), done -- no `nixos-rebuild`
|
|
needed for frontend-only changes. This flake still owns the nginx vhost,
|
|
firewall ports, and the CSP/proxy config around it.
|
|
|
|
## Network boundaries
|
|
|
|
Radicale and the frontend listen only on the pinix Tailnet address. The NixOS
|
|
firewall permits ports `5001` and `5002` only on `tailscale0`. Public traffic
|
|
passes through Traefik on `blunix`.
|
|
|
|
## Verification
|
|
|
|
After deployment:
|
|
|
|
1. Check that Radicale and Nginx are active.
|
|
2. Confirm that ports `5001` and `5002` listen only on the pinix Tailnet IP.
|
|
3. Verify that `/calendar.ics` is anonymously readable through the frontend.
|
|
4. Verify an authenticated LLDAP CalDAV login.
|
|
5. Create and delete a temporary event in `calendar/public` with two different
|
|
authenticated accounts.
|
|
6. Create a personal calendar and verify that another account cannot read it.
|