1
0
Fork 0
forked from lukas/nixos-config
nixos-config/hosts/pinix/localServices/calendar
pijukka 609c27ce15 calendar: move calendar-web frontend to its own Forgejo repo
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.
2026-07-30 09:28:41 +02:00
..
default.nix host(pinix): replace OWC with calendar frontend 2026-07-28 14:50:35 +02:00
H+9wX expose public calendar 2025-09-20 09:08:10 +02:00
radicale.nix prosody: agent@ turntaking; migrate agent listener to codex worker on blunix; calendar personal feed 2026-07-29 23:29:59 +02:00
README.md calendar: move calendar-web frontend to its own Forgejo repo 2026-07-30 09:28:41 +02:00
web.nix calendar: move calendar-web frontend to its own Forgejo repo 2026-07-30 09:28:41 +02:00

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:

    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:

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 pulls, 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.