Nextcloud “Drive” with Tailscale identity — spec
Status
Design approved 2026-08-31. This is the design of record; implementation plan derived separately. Do not commit changes to the vault per owner preference.
Goal
A self-hosted Google-Drive replacement on telep-mainframe: file uploads, folders, sharing, previews, and in-browser Office editing — with identity provisioned from Tailscale (no passwords), and the CAD export directory surfaced as a first-class folder plus a Taildrive mount.
Decisions (locked)
- Platform: Nextcloud (adopt, not build).
- Identity: Tailscale headers only — auto-provisioned SSO for tailnet users; tailnet-only access.
- Scope: consolidate into Nextcloud. The earlier separate
cad:8080type-aware browser is dropped; the CAD dir becomes a Nextcloud folder. 3D files deep-link to Online3DViewer. - Taildrive ACLs: already provisioned in the tailnet policy (
drive:share/drive:access).
Components
Docker Compose stack at /home/levander/nextcloud/, data on the root LVM (/ has 2.8 TB free). Follows the existing per-service /home/levander/<service>/ convention.
| Container | Purpose |
|---|---|
nextcloud (fpm or apache image) | The Drive app |
postgres | Database |
redis | Memory cache + transactional file locking |
onlyoffice/documentserver | In-browser docx/xlsx/pptx editing |
| reverse proxy (identity injector) | Tailscale whois → Remote-User header |
Resource budget: box has 62 GiB RAM (45 free), 20+ cores — comfortable for this stack.
Identity — Tailscale → auto-provisioned SSO (highest-risk piece)
- Dedicated Tailscale node
drive(tailscaled-drive, matching the existing per-service tsnet sidecar pattern, e.g.board-tsnet,tailscaled-bambuddy), userspace, own socket/statedir. tailscale serveon that node fronts the stack.- A thin reverse proxy resolves each request’s source tailnet IP → user via the Tailscale whois LocalAPI (
/localapi/v0/whois?addr=) and injectsRemote-User: <tailscale-login>(candidate implementations:caddy-tailscale, atsnetGo proxy, or nginx + a whois sidecar — chosen during the build spike). - Nextcloud consumes the header via the
user_samlapp in “environment variable” (SSO) mode (readsREMOTE_USER/mapped header) → tailnet users are auto-created + logged in on first request. A break-glass local admin is retained for config.
Validate first
This chain is the fiddly part. Build order stands it up and proves a real tailnet login before anything else is built.
CAD integration
/home/levander/freecad/exports/mounted as Nextcloud External Storage (Local), read-write → a “CAD” folder. New exports (from the cad-designer pipeline) appear automatically; edits flow back to disk → visible via Taildrive + the Mac~/cad-exports/sync.- 3D (step/stl/3mf/obj/gltf) → deep-link to Online3DViewer (
https://cad.taild4189d.ts.net:8090/o3dv/#model=…). Link-out, not an inline viewer (no good native STEP/STL preview exists). - Office (docx/xlsx/pptx) → OnlyOffice, edits save back.
- Images / PDF / CSV / text / markdown → Nextcloud native previews.
Taildrive — the whole Drive
The entire Nextcloud storage is exposed via Taildrive, not just CAD — a raw-filesystem view of the whole Drive on the tailnet.
- On the mainframe:
tailscale drive share drive /home/levander/nextcloud/data(the Nextcloud data dir; per-user files live under<datadir>/<user>/files/…). - Access on the Mac: Finder → Connect to Server →
http://100.100.100.100:8080/<tailnet>/telep-mainframe/drive. - Complementary to the Nextcloud web app (raw filesystem mount vs browser), same underlying storage.
Write-back consistency
Files written into the Nextcloud data dir out-of-band (via the Taildrive mount, or by the CAD pipeline) are invisible to Nextcloud until an
occ files:scan. Plan: a lightweight periodic/inotifyfiles:scanso Taildrive-side additions surface in the web UI. Ownership must match the Nextcloud runtime user (www-data).
CAD reconciliation
To keep CAD files inside the Taildrive-mounted Drive and preserve the existing freecad/exports pipeline (O3DV :8090, exports browser :8080, Mac ~/cad-exports/ sync all read that path), the default is:
- Keep
/home/levander/freecad/exports/as the CAD source of truth, mounted into Nextcloud as External Storage (Local, read-write) → shows as a “CAD” folder in the Drive UI. - Add a second Taildrive share for it:
tailscale drive share cad /home/levander/freecad/exports. - Net: the Drive (uploads) is Taildrive share
drive; CAD is Taildrive sharecad; both mount on the Mac. (Alternative considered: relocate CAD output into the Nextcloud data dir for a single share — rejected in v1 because it breaks the existing CAD consumers.)
Access
- Primary:
https://drive.taild4189d.ts.net(tailnet, via thedrivenode). - Optional LAN:
drive.telep.lanCaddy vhost (split-horizon, like the other services). - Tailnet-only — identity depends on the tailnet source IP; no public/off-tailnet login.
Out of scope (v1) / follow-ups
- Backups of the Nextcloud DB + data dir — flagged, not built in v1.
- Off-tailnet access / Pocket-ID OIDC fallback.
- Mobile/desktop sync-client rollout (works out of the box; not a build task).
- Inline 3D preview inside Nextcloud.
Build order (risk-first)
- Identity spike —
drivetsnet node + whois→header proxy + minimal Nextcloud +user_samlenv mode. Gate: log in as a real tailnet user, auto-provisioned. - Full stack — Postgres + Redis + Nextcloud tuning (cron, caching, trusted proxies/domains).
- OnlyOffice Document Server + Nextcloud connector.
- CAD external storage (read-write) + 3D deep-link action.
- Taildrive share + verify Mac mount.
- LAN vhost (optional) + docs.
Success criteria
- A tailnet user hits
drive.taild4189d.ts.net, is auto-logged-in as their Tailscale identity, no password. - Upload/download/share/folder operations work.
- CAD folder shows live exports; a
.stepopens in O3DV; a.docxopens+edits+saves in OnlyOffice. - The
driveTaildrive share mounts on the Mac and exposes the whole Nextcloud storage as a filesystem; thecadshare exposes the CAD dir. A file dropped via the Taildrive mount appears in the Nextcloud web UI after a scan.