Migrate Jellyfin on lyra back to the native NixOS service #30
Labels
No labels
area:authentication
area:flake-utilities
area:performance
area:tbd
host:chaos
host:electra
host:fleet
host:lyra
host:nova
host:vega
investigation
phase:cutover
phase:deploy
phase:mcp
phase:module
phase:packaging
phase:prep
phase:validation
priority:high
priority:medium
project:attic-postgres-lyra-rollout
project:auto-update-reliability
project:auto-update-remediation
project:declarative-purity-cleanup
project:external-review
project:fleet-boundary-cleanup
project:host-facts-refactor
project:lyra-nixos-deploy
project:lyra-service-stack-migration
project:nebula-mesh-network
project:nixos-build-deployment-pipeline
project:security-hardening
project:service-stack-migration
project:vega-sillytavern-cutover
project:wiki-rebuild
repo:numtide/flake-utils
repo:numtide/nix-auth
repo:numtide/nixos-passthru-cache
repo:numtide/nix-relay
service:auto-update
service:mem0
service:nix
service:sillytavern
service:slskd
service:synthseek
No milestone
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
nimmo/nixos-config#30
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Goal
Revisit the earlier Jellyfin migration on
lyraand complete it as a native NixOS service without repeating the mount and state-handling mistakes that led to the Docker reversion.Acceptance Checklist
lyraactually uses.Context
This host previously had a native Jellyfin attempt that was later reverted in favour of Docker. The issue is not whether NixOS can run Jellyfin; it can. The real risk is the network-backed storage and GPU wiring around it.
Guardrails
placeholderto Migrate Jellyfin on lyra back to the native NixOS servicePreparation update (2026-08-24)
Remaining cutover prerequisites:
Path migration preparation is now included in the staged native Jellyfin module. Inventory of the stopped 10.11 snapshot found 30,802 Docker-rooted values in dedicated columns and 7,077 occurrences embedded in BaseItems.Data across 7,075 rows. The one-time importer rewrites /config/data, /config/cache, /config/log, and remaining /config prefixes transactionally in the copied jellyfin.db, migrates copied XML/JSON/NFO text files, retains a pre-migration database copy, and runs before/after integrity plus zero-remaining-path checks. /media and /metadata mount paths remain stable; 49,473 /media item rows were deliberately unchanged. A disposable copy test reached zero old paths, preserved PRAGMA integrity_check=ok, and produced an identical checksum on a second pass. The evaluated importer passes bash syntax validation and nix flake check passes. The module remains disabled; no live database or Docker service was changed by this step.
Cutover layout revised after the first test activation. Jellyfin now uses upstream NixOS defaults: data /var/lib/jellyfin, config /var/lib/jellyfin/config, cache /var/cache/jellyfin, and logs /var/lib/jellyfin/log. Lyra owns a shared read-only NFS mount at /mnt/media for Jellyfin and future native services. The separate /metadata CIFS mount and invalid sops-nix.service dependency were removed: the active Docker system.xml, database, and logs prove current metadata lives under /config/data/metadata, and the stopped snapshot contains 5.4 GiB / 54,125 metadata files that will import to /var/lib/jellyfin/metadata. The migration now rewrites anchored /config roots and /media -> /mnt/media across dedicated columns, BaseItems.Data, text config, and the prerolls.video provider value. Disposable tests reached zero legacy roots, preserved SQLite integrity, and were checksum-idempotent on a second pass; text rewrites were also byte-idempotent. nix flake check passes. No new activation has been run after this correction; /srv/services/jellyfin is no longer referenced. The encrypted Jellyfin CIFS secret is retained but unused pending user direction.
First native
just teststopped safely injellyfin-state-import.service. The database migration itself completed: direct predicates against/var/lib/jellyfin/data/jellyfin.dbfound zero remaining Docker-rooted/configor/mediavalues, and the pre-migration rollback database remains alongside it. The failure was a false-positive audit: literal double quotes inside a shell double-quoted SQL argument were removed by Bash, so the/media/check also matched migrated/mnt/media/JSON and reported 6,459 rows. The audit now constructs JSON quote boundaries with SQLitechar(34). The importer is also resumable via a completion marker: a recognized partial import with its rollback database is revalidated and completed without copying state again; ownership is secured before validation and the marker is written only after database/text audits and integrity checks pass.nix flake checkpasses. Next step is rerunningjust teston Lyra.Live validation is complete: Jellyfin started from the imported native state, read media from
/mnt/media, and an observed Firefox Android playback session successfully used CUDA decoding,scale_cuda, and RTX 4070hevc_nvencencoding. The one-time migration machinery has now been removed from the working configuration: noimportSource, database/text rewrite script, completion-marker logic, orjellyfin-state-import.serviceremains. The evaluated Lyra configuration confirmshasImporter = false; native Jellyfin still requiresmnt-media.mount. The imported state and stopped source snapshot were left untouched. Fullnix flake checkpasses.Before commit, the shared
/mnt/mediadefinition was extracted fromhosts/lyra/default.nixinto reusablemodules/services/media-library.nix. The module exposesnixosConfig.mediaLibrary.{enable,mountPoint,source}, defaults to/mnt/mediaand192.168.8.238:/volume1/media, preserves the read-only NFS 4.1 mount policy, and owns NFS filesystem support plus mountpoint creation. Lyra now imports and enables it; future hosts can do the same without duplicating NAS details. Evaluated Lyra config preserves the mount and Jellyfin still requiresmnt-media.mount. Fullnix flake checkpasses.