Commit graph

997 commits

Author SHA1 Message Date
dad207d19b runner: document tokenFile EnvironmentFile format
The gitea-actions-runner module loads tokenFile as a systemd
EnvironmentFile, so it needs KEY=value lines, not a raw token. Comment
updated to match — the runner failed to start the first time around
because the file just contained the bare registration token.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-01 16:04:32 +01:00
27a4e85693 runner: use forgejo-runner package (renamed in 25.11)
The forgejo-actions-runner attr was renamed to forgejo-runner upstream.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-01 16:00:00 +01:00
29e1185694 runner: add Forgejo Actions runner on the mediaserver
Adds services/forgejo-runner.nix as a host-gated module on the mediaserver
and switches the flake-update workflow from runs-on: ubuntu-latest to the
self-hosted fred-nix label, mapped to catthehacker/ubuntu:act-latest for
GitHub-action compatibility. Token lives at /var/secrets/forgejo-runner-token
so it stays out of the Nix store.

Also drops the stray result/ build symlink from the worktree.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-01 15:58:28 +01:00
af1f5c9a04 Update .forgejo/workflows/update.yml 2026-05-01 07:44:16 -07:00
4683d6953f common: point update alias at Forgejo
Migrating origin from GitHub to a private Forgejo repo at
forg.gregersen.it/rope/nixos. Each host needs the PAT in /root/.git-credentials
(host-local state, set up manually since the repo isn't publicly readable).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-01 15:35:07 +01:00
c1094e7352 Fix proton-vpn rename on Gaming, restore zramSwap
The 25.11 channel renamed proton-vpn to protonvpn-gui; Macbook was
patched in an earlier commit but Gaming wasn't, breaking the build.

zramSwap goes back into common.nix as the cheap OOM-during-uncached-build
safety net — even on stable, --refresh against a freshly-bumped lock can
trigger local builds the box has no swap to absorb.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-01 13:38:27 +01:00
ediblerope
e1c193cdc3 flake: update inputs 2026-05-01 10:29:09 +00:00
f6e711044c
Update flake.nix 2026-05-01 11:27:32 +01:00
07f44724a0
Update flake.nix 2026-05-01 11:25:46 +01:00
7eb03c2245
Update FredOS-Macbook.nix 2026-05-01 11:07:04 +01:00
782054a0ea
Update flake.nix 2026-05-01 11:05:48 +01:00
695ac75daf
Update common.nix
removed some AI crap that's no longer needed on stable.
2026-05-01 11:00:57 +01:00
ediblerope
ab8c3ac92a flake: update inputs 2026-05-01 06:30:49 +00:00
c45811acf9 router: accept docker0 on input chain
Containers connecting to host services on 10.0.0.1 (e.g. Profilarr → Radarr
at 10.0.0.1:7878) hit the input chain, not forward, because the destination
is a local IP. The forward chain already trusts docker0 for outbound; this
adds the matching input rule so the return path stops getting dropped.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-30 20:47:46 +01:00
98ccee2221 profilarr: use Docker Hub image (santiagosayshey), not GHCR
The ghcr.io/dictionarry-hub/profilarr path mentioned in some docs isn't
publicly pullable — anonymous token requests get 403. Canonical image is
santiagosayshey/profilarr:latest on Docker Hub per the upstream README.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-30 20:05:30 +01:00
a9649be705 profilarr: swap recyclarr for Dictionarry's Profilarr
Profilarr replaces the recyclarr/TRaSH-Guides flow with a stateful web
service that owns *arr profiles end-to-end via its own UI. Runs as an
oci-container on 127.0.0.1:6868, fronted by nginx at
profilarr.nordhammer.it behind Authelia (one_factor).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-30 20:00:33 +01:00
ediblerope
91a94adc26 flake: update inputs 2026-04-30 06:21:10 +00:00
728779daab 2026-04-29 20:40:54 +01:00
8fa1e4c112 recyclarr: prefer x265 on 1080p profiles for disk space
Override TRaSH's -10000 ban on x265 (HD) to +500 on Sonarr WEB-1080p
and Radarr HD Bluray + WEB. The Scene/No-RlsGroup/Retags/Obfuscated
custom formats (each at -10000) still filter the truly low-bitrate
x265 trash, so we get smaller files without inviting slop.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-29 20:30:42 +01:00
17ea72e2ed common: drop --source-color-index from matugen update alias
The flag was removed in matugen 3.x; the call now exits with an arg
parse error on every update (caught by '|| true' but noisy). matugen
picks a sensible source color by default, so we just drop the flag.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-29 20:17:01 +01:00
79d7d3f88e adguard: explicitly enable LAN rewrites (schema change on stable)
AdGuard's recent config schema added an enabled flag on each rewrite
that defaults to false. Without it, the *.nordhammer.it -> 10.0.0.1
rules were silently disabled, so LAN clients resolved their own
domains to the public DDNS IP and tripped over NAT loopback.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-29 18:56:11 +01:00
4c80e26431 recyclarr: fix Sonarr UHD template name (web-2160p, not uhd-bluray-web)
The Sonarr 4K profile is sonarr-v4-quality-profile-web-2160p in TRaSH's
recyclarr templates — uhd-bluray-web exists for German content only.
The English UHD profile is WEB-only and named "WEB-2160p", so update
the include list and the AV1-ban score assignment to match.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-29 18:48:19 +01:00
3819cb6820 locale + crowdsec: pin timezone, declare static crowdsec user
Two failing services after the channel switch.

automatic-timezoned has been polkit-blocked since well before the
switch — replace with a static Europe/London timezone. Hosts that
travel can override locally if needed.

The vendored crowdsec module's setup unit chowns its config dir to
the (DynamicUser-allocated) crowdsec user via an ExecStartPre+ hack.
On stable's systemd the dynamic user isn't visible to chown via NSS
at that point, so it fails with 'invalid user'. Declaring crowdsec
as a static system user makes systemd use it (DynamicUser becomes a
no-op) and the chown resolves cleanly.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-29 14:00:41 +01:00
5e1780b4fe mediaserver: pin kernel to 6.12 LTS for NVIDIA 535 compatibility
NVIDIA 535's kernel module won't compile against kernel 7.x — the
DMA mapping API changed in a way the 535 source doesn't handle.
6.12 LTS is the highest kernel branch that's a well-tested combo
with the 535 driver, which we need on stable's nixpkgs to retain
Maxwell support for Jellyfin NVENC.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-29 13:37:48 +01:00
877796173f mediaserver: use nvidia legacy_535 (available on stable channel)
legacy_580 only exists on unstable nixpkgs and isn't backported to
25.11. The Maxwell GM206 (Quadro M2000) is supported through the
535.x branch — last production driver to ship Maxwell support — so
this is a clean swap with no expected impact on Jellyfin's NVENC.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-29 13:31:13 +01:00
34a45af357 flake: split mediaserver onto nixos-25.11, keep desktops on unstable
The mediaserver kept hard-freezing on local builds (gnupg, openldap,
deno/rusty-v8) whenever a fresh unstable revision outran Hydra's
binary cache. It doesn't need bleeding-edge packages — every service
it runs is mature enough that 6-month-old versions are fine — so move
it onto the stable channel where the cache is essentially always
warm. Gaming and Macbook stay on unstable for fresh GPU/kernel work.

Implementation: add nixpkgs-stable + home-manager-stable inputs,
parameterise mkHost to accept a (nixpkgs, home-manager) pair.

Drive-by:
- Switch homepage.nix from environmentFiles (plural, unstable-only)
  to environmentFile (singular, present on both channels).
- Gate the openldap-skip-tests overlay to non-mediaserver hosts so
  it doesn't force a local rebuild on stable, where openldap is
  always cached.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-29 13:26:07 +01:00
47a72a0a81 users: gate bazaar to GUI hosts only
bazaar is a Flathub GUI app store — it has no business on the headless
mediaserver, where it was also pulling flatpak in transitively and
inflating local builds.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-29 11:57:42 +01:00
057d24517f common: cap parallel builds + zramSwap to survive local rebuild storms
The mediaserver (56 cores, 31 GiB RAM, no swap) was hard-freezing on
local builds of gnupg/openldap because Nix defaulted max-jobs=auto and
launched ~56 parallel gcc compilations, blowing past available memory
and OOM-stalling AdGuard.

Cap parallelism (max-jobs=4, cores=8 per build) and add zramSwap as a
compressed in-memory safety net so a build storm can't take services
with it.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-29 11:57:40 +01:00
70ee0fc811 common: cap nix-daemon CPUWeight at 50 to keep services responsive
Heavy local builds (gnupg/openldap checkPhase under a freshly-bumped
nixpkgs lock) were saturating CPU and starving AdGuard on the
mediaserver, making DNS effectively unresponsive until the build
finished or got cancelled.

Halving the daemon's CPU share leaves headroom for latency-sensitive
services without meaningfully slowing builds on an otherwise idle box.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-29 11:17:51 +01:00
3f2c88da94 arr-interconnect: drop manual 1080p quality floors
Recyclarr now manages quality definitions via TRaSH templates, so the
hand-rolled minSize=10 floor is redundant — every sync would overwrite
it anyway.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-29 10:31:17 +01:00
e99bc7cc9b recyclarr: add weekly TRaSH-Guide profile sync for Sonarr & Radarr
Score-based release filtering replaces the brittle "minimum size" approach
— good HEVC encodes from reputable groups now win regardless of file
size, while obfuscated/no-group/lazy-x265 garbage gets banned.

Profiles installed:
  Sonarr: WEB-1080p (default), UHD Bluray + WEB (per-show opt-in)
  Radarr: HD Bluray + WEB (default), UHD Bluray + WEB (per-movie opt-in)

AV1 is banned across all four profiles since the GPU lacks hardware
decode. API keys are extracted at runtime from each *arr's config.xml,
matching the arr-interconnect pattern.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-29 10:31:09 +01:00
ediblerope
9405e4ffb5 flake: update inputs 2026-04-29 06:16:10 +00:00
0e11464390 shell: add desktop-environment module to fastfetch
Shows GNOME version on Gaming/Macbook; module self-skips on headless
hosts.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-28 13:22:42 +01:00
336d9df6a6 common: skip openldap test phase as temp workaround
test017-syncreplication-refresh is timing-flaky and fails reliably on
local builds when Hydra's binary cache hasn't yet served the upstream
artifact. Overlay sets doCheck=false so the build can proceed. Remove
once the substituter catches up to the pinned nixpkgs revision.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-28 13:01:07 +01:00
d0095af4fb gaming: disable IPv6 to stop NetworkManager connectivity flap
LAN has no v6 route, so AAAA lookups succeed but connect fails. NM's
connectivity probe was reporting "limited" at boot (GNOME's "?" icon)
until the next 5-min repoll cleared it.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-28 13:00:59 +01:00
ediblerope
09c994aef7 flake: update inputs 2026-04-28 06:23:38 +00:00
ediblerope
15b6a6125f flake: update inputs 2026-04-27 06:21:41 +00:00
ec32b9b849 router: rename nat table to router-nat so Docker's chains survive rebuilds
NixOS's nftables module rebuilds the tables it owns on every activation,
which previously wiped Docker's DOCKER/PREROUTING chains in ip nat
(both Docker and the router were defining 'ip nat'). Renaming our
table sidesteps the collision — kernel hooks across separate tables
at the same priority all run, so functionality is unchanged.

Eliminates the need to run 'systemctl restart docker' after every
nixos-rebuild to restore container port-forwards.
2026-04-26 19:43:33 +01:00
c1750c8538 router: allow WAN port-forwards to any DNAT target, not just eth0
The forward rule only accepted iifname=eno1 oifname=eth0 ct status=dnat,
which worked when port-forwards always landed on a LAN host. Docker
DNAT routes to docker0, so external traffic to 26900 was being DNAT'd
correctly but then dropped at the forward filter. Drop the oifname
constraint — the prerouting DNAT rule already controls what gets
forwarded; the filter doesn't need to second-guess it.
2026-04-26 19:42:15 +01:00
a124f314d9 common: bake --impure into update alias
CrowdSec reads the ntfy topic URL from /var/secrets/ntfy-url at eval
time via builtins.readFile. Pure flake mode forbids reading paths
outside the source tree, so without --impure the read silently falls
through to the placeholder URL on every rebuild. Adding --impure to
both build and switch keeps the secret-file pattern working.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-26 19:35:32 +01:00
525147aa61 fail2ban: remove — superseded by CrowdSec
CrowdSec covers the same surface (sshd, authelia, nginx, *arr apps,
qBit) with the addition of community-sourced threat intel and ntfy
push alerts. Keeping both was redundant. State at /var/lib/fail2ban
will sit unused until cleaned up by hand.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-26 19:26:24 +01:00
ediblerope
1e32cbded9 flake: update inputs 2026-04-26 06:00:34 +00:00
a0a1d67124 crowdsec: add systemd-journal group so journalctl acquisitions work
DynamicUser can only see its own journald entries by default, so the
sshd + authelia journalctl acquisitions were dying with "insufficient
permissions" and exit status 1 from the spawned journalctl process.
Adding systemd-journal grants the read access journald gates on group
membership, restoring the ssh-bf / authelia-bf detection chain.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-25 20:03:10 +01:00
c4f0e4920e 7dtd-coop: START_MODE=1 (Start), not 2 (Update+STOP)
The vinanrra image's mode numbers are: 0=Install+STOP, 1=Start,
2=Update+STOP, 3=Update+Start, 4=Backup+STOP. I picked 2 thinking
it meant "Only Start", which is why the container kept exiting
cleanly after each update check. Mode 1 just starts the server,
which matches what the main 7dtd container uses.
2026-04-25 19:51:32 +01:00
c1cfa613f7 7dtd-coop: switch to START_MODE=2, seed serverfiles from main install
SteamCMD anonymous install fails with "Missing configuration" on a
fresh coop dir. The main 7dtd works because its binaries were
installed long ago and LinuxGSM skips the SteamCMD step. Same trick
for coop: rsync the binaries over and start-only, no update path.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-25 19:24:01 +01:00
568b815d8d router: allow docker0 forward and expose 7dtd-coop ports
Container outbound (image pulls, LinuxGSM bootstrap fetches) was
dropped by the inet filter forward chain — only eth0 and DNAT'd
WAN traffic were whitelisted. Add iifname "docker0" accept so
containers can reach the internet.

Also add the coop server's 26910/26911-26912 forwards to ports.toml
so WAN players can connect.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-25 15:35:26 +01:00
4d84fe2df3 7dtd: add private coop server on ports 26910-26912
Second container 7dtd-coop with its own /var/lib/7dtd-coop state dir
and a configure unit that patches the server as unlisted, 2-player,
distinct world seed.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-25 15:26:55 +01:00
709b6944ad crowdsec: add nginx group so DynamicUser can read access.log
The agent runs as a systemd DynamicUser and was failing the nginx
acquisition with "No matching files for pattern /var/log/nginx/access.log"
because access.log is nginx:nginx 640 — readOnlyPaths handles sandbox
visibility but not Unix perms. extraGroups = [ "nginx" ] gets it past
the group bit.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-25 15:23:41 +01:00
0125a1deb2 crowdsec: build notification plugins via package override
Upstream nixpkgs builds only cmd/crowdsec and cmd/crowdsec-cli; the
PR #446307 module's setup script expects notification plugins at
\$package/libexec/crowdsec/plugins/notification-*, causing first-start
failure (cannot stat notification-dummy). Add the cmd/notification-*
subpackages and move the resulting binaries into the libexec layout the
module expects.

Drop this override along with the vendored modules once the PR lands —
nixpkgs will need a matching package update for the rewrite to work.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-25 15:16:03 +01:00
a8d163b4a8 crowdsec: vendor PR #446307 rewrite to fix bootstrap
The upstream NixOS crowdsec module fails on first deploy ("no API client
section in configuration") because it doesn't auto-register LAPI
credentials. The rewrite in NixOS/nixpkgs#446307 (TornaxO7's branch) adds
a setup oneshot that runs `cscli machines add --auto` if the credentials
file is missing, and handles DynamicUser StateDirectory permissions
explicitly. The bouncer rewrite gets matching auto-registration.

Vendor both module files locally and disable the upstream copies. Drop
modules/crowdsec/ and the disabledModules+imports lines once the PR
merges into nixpkgs unstable.

Config moves to the new unified `settings` API (no more separate
`localConfig`); LAPI moved to 127.0.0.1:8081 to dodge the qBit collision.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-25 15:00:32 +01:00