Setup in an existing NixOS configuration¶
This is a reusable module, not a disk installer. Keep the desktop or server host in its existing configuration repository. Add an input and import the module:
{
inputs.nix-homelab.url = "github:nix-forge/nix-homelab";
# Use the project's tested package set, or consciously validate a follows override.
outputs = inputs: {
nixosConfigurations.my-host = inputs.nixpkgs.lib.nixosSystem {
modules = [
inputs.nix-homelab.nixosModules.default
./configuration.nix
./homelab.nix
];
};
};
}
Retain your host's existing nix-seal input and module. Configure its public
administrator catalog, target identity and encrypted sources in the host
repository. No second agenix secret manager is needed. The adapter in
examples/nix-seal.nix declares two user-supplied
secrets and passes their .path values to the VPN and qBittorrent. Import it
after configuring nix-seal. Provision the signed target artifacts using the
pinned
nix-seal preparation workflow
before activation. The homelab project neither creates nor asks to read them.
WireGuard profile¶
Use the media example as a host module. Replace
its documentation addresses and peer key with the user's Mullvad profile. The
profile's private key is the content of the nix-seal VPN secret, never a Nix
string. Map Address to interface.addressIPv4 and optional addressIPv6,
without their prefix lengths. Map DNS to interface.dns, and the peer's
PublicKey and literal Endpoint address/port to peer.publicKey,
peer.endpointHost and peer.endpointPort.
Import the nix-seal adapter instead of leaving the example's runtime key path.
The actual path comes from config.nixSeal.secrets.<name>.path; do not guess
nix-seal's administrator or target directory layout. If copying the two examples
into one host, remove privateKeyFile from the provider example so it has
exactly one definition.
Mullvad has no inbound forwarding, so leave vpn.allowInbound disabled. Confirm
the namespace name and network policy in VPN guidance.
Application credentials and configuration¶
The qBittorrent credential secret is an INI fragment generated from a private qBittorrent configuration:
[Preferences]
WebUI\Username=YOUR_USER
WebUI\Password_PBKDF2=YOUR_GENERATED_QBITTORRENT_HASH
Keep the real values encrypted in nix-seal. The secret is loaded as a systemd credential and merged after generated public settings on every start. Without this file, use the upstream first-run temporary password and then configure a persistent runtime credential before relying on restarts. The public settings file is declarative; do not rely on UI-only configuration changes surviving.
The qBittorrent module enables queueing and defaults to 3 downloads, 5 seeds,
8 active torrents, 200 global peer connections and 20 upload slots. Local peer
discovery is disabled. Override homelab.apps.qbittorrent.resourcePolicy after
measuring the host; bandwidth and seeding/removal policy remain explicit host
choices because a reusable ratio or deletion rule is not safe for every tracker.
Import the integrated media example instead of repeating first-run UI wiring. It installs runtime API keys, creates the movie, TV and music roots, registers qBittorrent and any enabled Usenet client, links Prowlarr to every manager, applies safe media-management and naming policy, configures Bazarr languages, creates Jellyfin libraries and restricted viewer, and onboards Seerr with explicit request quotas. The reconciler updates only declared fields and does not delete objects that disappear from Nix.
Supply runtime files for sonarr-api-key, radarr-api-key, lidarr-api-key,
prowlarr-api-key, bazarr-api-key, qbittorrent-webui-ini,
qbittorrent-username, qbittorrent-password, jellyfin-admin-password and
jellyfin-viewer-password. A 32-character alphanumeric key works with the
Servarr key installer. If SABnzbd is enabled, also supply
sabnzbd-api-key; if NZBGet is enabled, supply nzbget-username and
nzbget-password. Keep each source encrypted and configure nix-seal restart
units for its key installer, application and integration job.
The remaining attended setup is intentionally small: enable native browser authentication before remote access, select real Prowlarr indexers and accounts, choose subtitle providers, and replace the example administrator identity and request quotas. Sonarr's default port is 8989, Radarr 7878, Lidarr 8686, Prowlarr 9696, Bazarr 6767 and Seerr 5055. Seerr is a request portal, not a downloader. Keep paths identical across applications and never expose these administrative listeners directly to the public Internet.
For Usenet, choose SABnzbd or NZBGet instead of enabling both without a reason.
The standard Usenet packages depend on unrar. Explicitly allow only unrar in
the consuming host's nixpkgs.config.allowUnfreePredicate if selecting these
packages. Plex separately requires plexmediaserver.
SABnzbd accepts services.sabnzbd.secretFiles containing runtime INI settings;
ensure its service user can read the nix-seal output or use systemd credentials
and their credential-directory paths. Its settings are declarative even on older
host state versions. NZBGet keeps provider credentials in its private state and
applies declared path and listener overrides on startup. Use provider TLS with
certificate verification. The extras example shows the
shared Recyclarr policy, private autobrr defaults and a node exporter; replace
illustrative secret paths with actual nix-seal .path references.
Autobrr integration supplies the downloader and filter recipe.
Storage and private access¶
Declare the existing media mount in the host and set requiredMounts to that
mount. Check its contents and free space before enabling downloads. Read
storage and recovery for the shared 4 TB media/backup arrangement.
Importing this project does not activate a disk migration.
Use a browser on the desktop for localhost services. Namespace UIs use the host-link address. To access from another computer, configure the host's SSH tunnel, trusted private access network or authenticated TLS reverse proxy. Services with no upstream bind-address option remain protected by the host firewall. This project opens no LAN or public ports for you.
Validate before activation¶
Enable homelab.readiness.enable after supplying the host-owned configuration
described in production-readiness checks. An assertion failure
names the missing credential, integration, operations or acknowledgment.
Evaluate and build through the consuming repository's ordinary workflow. Back up application state before its first upgrade. After activation, verify service health, a real tunnel handshake, blocked traffic with the tunnel down, indexer search, a permitted download, hardlink import, request fulfillment and playback. Check resource use and an isolated restore. Keep the previous system generation and the matching state backup until those checks pass.
Complete application relationships¶
After defining native services and host-owned runtime secrets, use the integration guide and integrated media example to register manager roots, download clients, Prowlarr connections, Jellyfin libraries/accounts and Seerr destinations. Keep every provider endpoint and account explicit. The example's secrets are required inputs, not files this flake creates.
Use audio, Usenet, and optional services for the additional workloads you select. Import operations before relying on persistent application state. Attach its backup preparation to the host's existing Restic job and practice recovery with a separate restore target.
Choose one tool to own each application field. Review Recyclarr changes before applying them; avoid concurrent UI edits while a managed API job changes the same object. Application upgrades still require backup and compatibility review.
Managers receive one writable mount for the dedicated media root. Keep downloads and libraries in separate directories beneath that root on one filesystem; separate mounts can force copies even when both paths report the same device. Keep backup repositories outside this writable media root. Player library views remain read-only, and downloader access is limited to download staging.