The crowdsec hub tracks upstream master, but nixpkgs stable's crowdsec
binary is a few versions behind and doesn't know newer expr functions
(LookupFile in particular). When crowdsec-setup re-pulls the hub on
each rebuild, it lands /etc/crowdsec/scenarios/http-technology-probing.yaml
which then crashes the agent at load time with "unknown name LookupFile".
Adds a tiny oneshot ordered between crowdsec-setup and crowdsec that
removes the offending file. RequiredBy crowdsec.service so the hook
always fires even if someone restarts the agent manually. Drop this
unit (and revert the bundled-package fix) once nixpkgs catches up.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This reverts db69615. Not pursuing the Windows-VM workaround for the DR
client mod after all. The server-side AdminCommandHandler exposes a
LevelSelf channel that bypasses the DLL flow entirely, which is a
better path than running a whole guest OS for one game.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Adds libvirtd + virt-manager + OVMFFull (UEFI w/ Secure Boot) + swtpm
(software TPM 2.0) so a Windows 11 VM can install. Brings in virtio-win
ISO for guest drivers and virt-viewer for SPICE console. Adds fred to
the libvirtd group.
Reason: the Dungeon Runners client-side mod (DSOUND.dll inline-hook
trampolines + memory scanner) crashes wine with a guard-page violation
on init regardless of Proton vintage; the only realistic path for
character progression is to run the client on real Windows.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Unity's Win64 build still creates a 1x1 hidden window via Win32 even
under -batchmode -nographics. Wine needs an X display to honor that;
without one, startup fails with "Failed to create batch mode window:
Success." after Mono initializes and PhysX comes up. xvfb-run -a gives
it a virtual display with no real X server cost.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
New service module on FredOS-Mediaserver that launches the friend's
Windows-only Unity server (DR_Server.exe -batchmode -nographics) in a
Win64 wine prefix. wineboot initializes the prefix on first start.
Opens auth/game/queue ports 2110, 2603-2606 (TCP+UDP).
Build files staged separately at ~/dr-server-build on the server;
sudo-move into /var/lib/dr-server/Build after the rebuild.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Adds a stage s02-enrich parser whitelist so events originating from
10.0.0.0/24 (and 127.0.0.1/::1) are dropped before scoring. Without it,
Authelia 401s from a stale browser tab on a LAN client can trip
http-bf / ssh-bf scenarios and the firewall bouncer cuts the LAN host
off from the server — happened today with the gaming desktop.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Two small follow-ups to the SAB module:
- Extend host_whitelist to also include 127.0.0.1 + localhost. SAB's
local-IP bypass usually handles this, but Sonarr/Radarr's "Hostname
verification failed" error becomes a real footgun if it ever flips.
- Add extraGroups = [ "media" ] for parity with sonarr/radarr/qbittorrent.
No functional change since group = "media" already.
Also wires SABnzbd into arr-interconnect: extracts api_key from
sabnzbd.ini and POSTs a Sabnzbd download client into Sonarr (tv-sonarr
category) and Radarr (radarr category). Idempotent like the existing
qBittorrent block; silently skips on first boot before SAB has materialised
its config.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Forgejo's runner spins up a per-workflow Docker network for every job,
which lives on a br-XXXXXX bridge — not docker0. Without this rule, the
in-container git clone (and anything else outbound) hits the forward
chain's default-deny and times out. Match docker0 plus the br-* glob in
both input and forward so any Docker network model works.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Forgejo's runner defaults to fetching `uses: org/repo@vN` from its
instance's mirror (data.forgejo.org), which doesn't host most
GitHub-marketplace actions like cachix/install-nix-action. Pointing
default_actions_url at github.com makes the existing workflow Just Work
without fully-qualified URLs in `uses:` lines.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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.
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.
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>
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>
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.
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>
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>
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>
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>
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>
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>
Enables the CrowdSec agent with sshd/nginx/http-cve hub collections,
acquires logs from nginx, sshd, and Authelia journald, and wires the
firewall bouncer to enforce bans via nftables. Alerts are POSTed to a
self-chosen ntfy.sh topic (URL read from /var/secrets/ntfy-url, falls
back to a placeholder so the repo stays eval-clean without the secret).
Module is self-contained — remove the file + import to uninstall; state
lives under /var/lib/crowdsec.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>