Skip to content

Latest commit

 

History

17 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

nurpkgs

My personal NUR repository.

Packages

  • scrobblex — self-hosted Plex-to-Trakt scrobbler.
  • trek — self-hosted, collaborative travel planner (liketrek/TREK).
  • yamtrack — self-hosted media tracker (movies, TV, anime, manga, games, books, ...). Built from source against nixpkgs' Python packages; the package itself does not include the upstream Docker image's nginx/supervisord layer, but nixosModules.yamtrack provides an equivalent co-located proxy of its own — see below.

NixOS modules

  • nixosModules.scrobblex — runs scrobblex as a systemd service.
  • nixosModules.trek — runs TREK as a systemd service.
  • nixosModules.yamtrack — runs Yamtrack's web server, migrations and Celery worker/beat as systemd services.
{
  imports = [ inputs.nur.repos.msaxena.modules.nixos.scrobblex ];

  services.scrobblex = {
    enable = true;
    environmentFile = "/run/secrets/scrobblex";
  };
}
{
  imports = [ inputs.nur.repos.msaxena.modules.nixos.trek ];

  services.trek = {
    enable = true;
    allowedOrigins = [ "https://trek.example.com" ];
    environmentFiles = [ "/run/secrets/trek-env" ]; # ENCRYPTION_KEY, etc.
  };
}

services.trek covers most of upstream's .env.example as typed options (session/cookie settings, OIDC, MCP, Overpass, ...); anything not covered can be set via services.trek.environment (non-secret) or services.trek.environmentFiles (secret). Two things worth calling out:

  • impermanence: state lives entirely under services.trek.dataDir (/var/lib/trek by default), fully managed by systemd's StateDirectory=. Add that one path to your persistence config and nothing else needs to change — the persistent bind mount is already in place before the service starts. One caveat: the service runs as a static trek user with no pinned uid/gid, so if you also wipe /etc on boot, its uid can be reassigned across activations (whenever the set of other uid-less system users on the box changes), and systemd will recursively re-chown the whole state tree the next time it notices a mismatch. Persist /etc/passwd and /etc/group too (a common impermanence pattern already, not unique to this module) or pin users.users.trek.uid/users.groups.trek.gid yourself if you want the uid to never move.
  • sops-nix: environmentFiles takes a list of paths, so [ config.sops.secrets.trek-env.path ] (a templated sops-nix secret combining ENCRYPTION_KEY, OIDC_CLIENT_SECRET, etc.) or one path per sops secret both work directly. Because the service runs as a static trek user (not DynamicUser), sops.secrets.foo.owner = "trek" also works if you ever need a file-based secret outside environmentFiles.

Exposes the app's full configuration surface as typed options; see nixos-modules/yamtrack.nix for the complete list (providers, database, redis, OAuth/social login, etc). Credential-shaped settings (the Django secret key, provider API keys, a remote database password, ...) are deliberately not plain Nix options — they go through environmentFiles, a list of KEY=value files loaded by systemd (EnvironmentFile=), so nothing sensitive ends up in the Nix store. That option's description lists every supported key.

{
  imports = [ inputs.nur.repos.msaxena.modules.nixos.yamtrack ];

  services.yamtrack = {
    enable = true;
    urls = [ "https://yamtrack.example.com" ];
    database.createLocally = true; # local Postgres, peer-authenticated, no password
    environmentFiles = [ config.sops.secrets."yamtrack-env".path ];
  };
}

Proxy included: services.yamtrack.host/port (default 127.0.0.1:8000) are a small co-located Caddy instance the module runs in front of gunicorn — mirroring upstream's own Docker image, which bundles nginx alongside gunicorn for exactly the same reason. It serves /static/ directly from the package's collectstatic output and sets X-Real-IP on the way to gunicorn, which django-allauth's per-IP signup/login rate limiter requires (without it, every registration/login attempt 403s even though every systemd unit reports healthy). Gunicorn itself no longer binds host/port — it's loopback-only on a fixed internal port that isn't part of this module's option surface. Breaking change if upgrading from an older version of this module: host/port used to be gunicorn's own bind address, and every consumer had to put their own reverse proxy in front to get working static assets and correct client-IP detection at all — anything that assumed host:port was gunicorn (firewall rules, an external proxy's upstream target) needs re-checking.

State: with the sqlite default, only /var/lib/yamtrack needs to survive a reboot (add it to your impermanence persistence list); with database.createLocally, persist /var/lib/postgresql instead. Redis holds only cache/broker data and needs no persistence either way. As with trek above, the service runs as a static yamtrack user with no pinned uid/gid — persist /etc/passwd//etc/group too, or pin users.users.yamtrack.uid/users.groups.yamtrack.gid, if you want its identity (and therefore the state tree's ownership) to never move across boots. The static user also means sops.secrets.foo.owner = "yamtrack" works, if environmentFiles alone isn't enough for some future use case.

About

NUR Packages

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages