Lidarr in the navidrome namespace as a "what is missing" UI: artist
discographies (Wanted -> Missing) and Spotify followed artists / saved
albums / playlists as import lists.
- Mounts navidrome-music-bulk read-write (Lidarr has no read-only root
folder mode); config on ceph-block.
- A reconcile sidecar (same image, curl+jq) reads the API key from
/config/config.xml and on every start sets renameTracks=false,
writeAudioTags=no, no recycle bin, no empty-folder deletes, no
permission changes -- then adds /music as root folder only if absent,
so the automatic library import never runs with file-mutating
settings.
- No download client or indexer.
- AuthenticationMethod=External behind a dedicated lidarr-gate outpost
restricted to a new "Music Librarians" group (k.renner).
- Image automation on the linuxserver build number.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Second named key in apps/ai/wiki-api-keys (OpenBao version 4), mapped to
Auth__ApiKeys__paperclip; writes through the API are attributed to it.
Reloader rolls the pod when the Secret changes.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The cluster-internal name keeps working when runs move to sandbox pods
(option C), where loopback would not reach the server. The name is
added to PAPERCLIP_ALLOWED_HOSTNAMES because the private-hostname guard
otherwise returns 403 for it. Same-namespace traffic is already allowed
by the baseline CNP in both directions.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Upstream derives the agents' PAPERCLIP_API_URL from the public URL, so
agent API calls went out through Traefik to the paperclip-gate outpost.
With intercept_header_auth the outpost treats the agent's Authorization
header as an Authentik credential and returns 401; agents could not
create tasks, post cards or update status.
Agents run in the server pod (option B), so PAPERCLIP_API_URL is set to
http://localhost:3100 (upstream keeps an explicit value and passes it to
every run). Loopback passes the private-hostname guard and agent JWTs
still authenticate each call; the gate stays fully enforced for browser
traffic instead of carving out /api/.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The first admin is claimed, so PAPERCLIP_AUTH_DISABLE_SIGN_UP flips to
true.
Spec: Claude auth is a Paperclip-managed subscription connection created
once via the local sign-in. The server-env CLAUDE_CODE_OAUTH_TOKEN was
never used (stripAiAuthBindings blanks it for managed runs; upstream
accepts no pasted setup-token), so it is dropped from the spec. The
login must run as the node user: exec sessions start as root and
root-owned 0600 credentials are unreadable to the server.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Paperclip's private-hostname guard (authenticated+private) returns 403
for any Host but loopback and the public URL. Kubelet probes send the
pod IP, so the pod could never become Ready. Probes now send
Host: localhost.
- Liveness is a TCP check: /api/health runs SELECT 1, so a Postgres
outage would have restarted the server and killed in-flight runs.
- Baseline CNP allowed world on every port; Cilium unions allows across
CNPs, so the app-level :443 restriction was not enforced. world is
now :443-only in the baseline as well.
- automountServiceAccountToken: false. Every agent shares the pod
filesystem; bots bring their own cluster credentials.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Sign-up stays enabled: upstream's first-admin claim requires an
existing signed-in Better Auth account (routes/access.ts
/bootstrap/claim), so disabling it would lock out the claim. A
follow-up flips PAPERCLIP_AUTH_DISABLE_SIGN_UP after the claim.
- Telemetry is off via PAPERCLIP_TELEMETRY_DISABLED=1, which
resolveTelemetryConfig honours; config.json can't carry it alone
because the schema requires a complete file.
- Container starts as root: docker-entrypoint.sh remaps the node user
and chowns /paperclip before dropping privileges with gosu.
- Image pinned to the amd64 manifest digest of nightly; Flux digest
reflection takes over from there.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
digestReflectionPolicy: Always requires spec.interval on the ImagePolicy
(admission rejects it otherwise); set to 1h to match the ImageRepository.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The public edge is proxy-1/proxy-2; proxy.renner.uno has not pointed at
netbird.renner.uno since the netcup fleet took over. The proxy that kept
running on the management host has served nothing since the controller
moved every service to TLS passthrough (2026-09-07): passthrough routes
live on the proxy's own :443 listener, while the host's Traefik forwards
HostSNI(*) to its :8443 main listener, which answers "unknown domain".
Its watchdog therefore failed every probe round and ran `docker restart`
every ~3 minutes since 2026-09-07 12:53 (last healthy round). Each
restart registered a fresh proxy peer and pushed a network-map update to
every peer in the mesh — ~10 stale proxy-* identities per ingress peer
and a map update every 1-2 minutes.
- netbird-server: drop the proxy service, its Traefik TCP passthrough,
proxy.env and the proxy vars; `compose up --remove-orphans` removes
the container, and one-off tasks stop/remove both watchdogs and delete
the proxy volumes, config and state.
- install-netbird-server.yml no longer applies netbird-proxy-watchdog;
its pipeline no longer triggers on that role.
- Comments that described the management host as a cluster member now
describe the proxy hosts only.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Navidrome (Subsonic API) as the Spotify replacement for phone apps.
- Library PVC on ceph-filesystem-bulk (RWX, 300Gi, mounted read-only);
SQLite data on ceph-block (RWO).
- Web UI behind a dedicated navidrome-gate Authentik proxy outpost;
Navidrome trusts X-Authentik-Username (ExtAuth) and auto-creates the
user on first SSO login (first user = admin).
- /rest and /share routed straight to Navidrome with the identity header
stripped, so Subsonic clients use their Navidrome password.
- Namespace baseline CNP, gate egress CNP, Flux image automation,
Velero daily schedule (09:15), bootstrap wait.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
immich-server mounts /data from immich-library-bulk (EC 2+1) and
/data/thumbs from immich-thumbs (3x replicated). Data was copied with
rsync -aH from immich-library and verified per folder: file counts and
byte totals match for library, upload, encoded-video, profile, backups
and thumbs.
immich-library stays in pvcs.yaml until a Velero backup of the new
volumes has completed; its removal is a separate change.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Adds immich-library-bulk (ceph-filesystem-bulk, EC 2+1, 300Gi) for
the media root and immich-thumbs (ceph-filesystem, 3x, 30Gi) for
thumbs. Thumbnail reads stay on the replicated pool, where CSI read
affinity serves them from the local OSD; an EC read always
reassembles chunks from two OSDs.
Both PVCs start empty and nothing mounts them yet. The data copy and
the server cutover follow separately.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
ImageRepository and ImagePolicy for gitea.renner.uno/konairius/wiki, same
shape as shelly-manager; the deployment carries the setter marker, so the
existing ImageUpdateAutomation bumps the tag on every main build.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Wiki main after PR #12: /facts is one text box; the drafter turns the
statement into a raw source under the signed-in user.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Wiki main after PR #11: /facts deposits a raw source under the signed-in
user through the same use case as the API.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Books live on audiobookshelf-books-bulk since #955; nothing mounts
audiobookshelf-books any more. The PVC has prune disabled, so removing
it from git does not delete it; the PVC, its Retain PV and the CephFS
subvolume are deleted by hand after merge.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Wiki main after PR #10: every typed question rides in the single request
that carries the state, halving TypeSafe input tokens per ask.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Points the audiobookshelf Deployment and the libation CronJob at
audiobookshelf-books-bulk (ceph-filesystem-bulk, EC 2+1). The data was
copied with rsync -aH from the old PVC and verified: 574 files,
87315610958 bytes on both sides.
audiobookshelf-books stays in pvcs.yaml (prune disabled) until the
new volume is confirmed in use; its removal is a separate change.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Enables StripAudibleBrandAudio (Libation trims the branding using Audible's
own chapter offsets, lossless) and OverwriteExisting, so a re-liberated book
replaces its file instead of landing next to it as 'Title (1)'.
Settings.json on the PVC is seeded once and the entrypoint copies it into
ephemeral /config-internal each run, so the flags are applied there with jq
(already in the image; the entrypoint uses it for Books/InProgress).
Only affects books decrypted from now on; existing files need a re-liberate.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Adds a secondary erasure-coded (2+1, failureDomain host) data pool
'bulk' to the cephfs filesystem and a ceph-filesystem-bulk StorageClass
targeting it. data0 stays the default data pool, as Rook requires for
EC CephFS pools. Bulk media at 1.5x instead of 3x raw overhead.
Behaviour matches the existing migration.rgw.buckets.data EC pool:
Rook sets ec_overwrites, min_size 2 (=k), so IO continues through a
single-node reboot without redundancy for that window.
Also provisions an empty audiobookshelf-books-bulk PVC on the new
class. Deployment and libation CronJob still mount audiobookshelf-books;
the data copy and cutover follow separately.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The open3e-esp32 gateway on the Vitocal 250-A internal CAN (ECU 0x6e0,
room setpoints) publishes and listens under open3e/int/#. A separate
broker user keeps its command topic out of edge-1's open3e/cmnd listener
and gives the credential its own lifecycle.
Follows the health credential pattern: OpenBao-backed via ExternalSecret,
Class-A rotator CronJob (quarterly, months 3/6/9/12), per-secret policy
and kubernetes auth role, Reloader annotation on the broker.
Out-of-band steps done on 2026-09-24 with an admin token: policy written,
auth role created, path seeded with a 32-char alphanumeric password.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QNSJsCKwMip9y9YEZhDqxw