4 Commits

Author SHA1 Message Date
674e6f1d3c Fix tinyproxy starting before VPN bridge is configured
Some checks failed
Check Flake / check-flake (push) Has been cancelled
tinyproxy binds to the bridge IP but had no ordering dependency on
systemd-networkd, so it could start before the bridge existed.
2026-03-01 13:20:56 -08:00
7ec85cb406 Move s0 to using systemd networkd 2026-03-01 12:36:10 -08:00
e9e925eb46 Fix annoying 'refused connection' logs spamming dmesg due to spotify connect 2026-03-01 12:36:10 -08:00
2ed58e1ec5 Update flake inputs; drop navidrome; fix noto-fonts subset glob
- Update nixpkgs (Feb 27), home-manager, microvm, nix-index-database,
  claude-code-nix, dailybot
- Remove navidrome service, nginx proxy, dashy entry, and gatus monitor
- Add noto-fonts-subset patch for libreoffice/collabora (noto-fonts
  2026.02.01 switched from variable to static font filenames)
- Add incus-lts writableTmpDirAsHomeHook overlay for sandbox HOME fix
- Add samba4Full overlay to disable CephFS (ceph pinned to python3.11)
2026-03-01 12:36:10 -08:00
14 changed files with 163 additions and 82 deletions

View File

@@ -1,6 +1,6 @@
---
name: update-flake
description: Update nix flake inputs to latest versions, fix build breakage from upstream changes, build all NixOS machines, and run garbage collection. Use when the user wants to update nixpkgs, update flake inputs, upgrade packages, or refresh the flake lockfile.
description: Update nix flake inputs to latest versions, fix build breakage from upstream changes, and build all NixOS machines. Use when the user wants to update nixpkgs, update flake inputs, upgrade packages, or refresh the flake lockfile.
---
# Update Flake
@@ -35,12 +35,6 @@ nix build .#nixosConfigurations.<hostname>.config.system.build.toplevel --no-lin
Fix any build failures before continuing.
### 4. Garbage Collection
```bash
nix store gc
```
### 5. Summary
### 4. Summary
Report: inputs updated, fixes applied, nextcloud changes, and anything needing user attention.

View File

@@ -187,8 +187,7 @@ in
# Enable systemd-networkd for bridge management
systemd.network.enable = true;
# TODO: re-enable once primary networking uses networkd
systemd.network.wait-online.enable = false;
systemd.network.wait-online.anyInterface = true;
# Tell NetworkManager to ignore VPN bridge and container interfaces
networking.networkmanager.unmanaged = mkIf config.networking.networkmanager.enable [
@@ -231,7 +230,11 @@ in
Port = cfg.proxyPort;
};
};
systemd.services.tinyproxy.before = [ "container@pia-vpn.service" ];
systemd.services.tinyproxy = {
before = [ "container@pia-vpn.service" ];
after = [ "systemd-networkd.service" ];
requires = [ "systemd-networkd.service" ];
};
# WireGuard interface creation (host-side oneshot)
# Creates the interface in the host namespace so encrypted UDP stays in host netns.

View File

@@ -86,6 +86,9 @@ in
services.gnome.gnome-keyring.enable = true;
security.pam.services.googlebot.enableGnomeKeyring = true;
# Spotify Connect discovery
networking.firewall.allowedTCPPorts = [ 57621 ];
# Mount personal SMB stores
services.mount-samba.enable = true;

View File

@@ -120,16 +120,6 @@ in
];
alerts = [{ type = "ntfy"; }];
}
{
name = "Navidrome";
group = "services";
url = "https://navidrome.neet.cloud";
interval = "5m";
conditions = [
"[STATUS] == 200"
];
alerts = [{ type = "ntfy"; }];
}
{
name = "Roundcube";
group = "services";

50
flake.lock generated
View File

@@ -53,11 +53,11 @@
]
},
"locked": {
"lastModified": 1771632347,
"narHash": "sha256-kNm0YX9RUwf7GZaWQu2F71ccm4OUMz0xFkXn6mGPfps=",
"lastModified": 1772252645,
"narHash": "sha256-SVP3BYv/tY19P7mh0aG2Pgq4M/CynQEnV4y+57Ed91g=",
"owner": "sadjow",
"repo": "claude-code-nix",
"rev": "ec90f84b2ea21f6d2272e00d1becbc13030d1895",
"rev": "42c9207e79f1e6b8b95b54a64c10452275717466",
"type": "github"
},
"original": {
@@ -76,11 +76,11 @@
]
},
"locked": {
"lastModified": 1739947126,
"narHash": "sha256-JoiddH5H9up8jC/VKU8M7wDlk/bstKoJ3rHj+TkW4Zo=",
"lastModified": 1772394520,
"narHash": "sha256-9c0sHyzoVtvufkSqVNGGydsgjpKv5Zf7062LmOm4Gsc=",
"ref": "refs/heads/master",
"rev": "ea1ad60f1c6662103ef4a3705d8e15aa01219529",
"revCount": 20,
"rev": "d07483c17bf31d416de3642a2faec484ea1810ed",
"revCount": 21,
"type": "git",
"url": "https://git.neet.dev/zuckerberg/dailybot.git"
},
@@ -228,11 +228,11 @@
]
},
"locked": {
"lastModified": 1771756436,
"narHash": "sha256-Tl2I0YXdhSTufGqAaD1ySh8x+cvVsEI1mJyJg12lxhI=",
"lastModified": 1772380461,
"narHash": "sha256-O3ukj3Bb3V0Tiy/4LUfLlBpWypJ9P0JeUgsKl2nmZZY=",
"owner": "nix-community",
"repo": "home-manager",
"rev": "5bd3589390b431a63072868a90c0f24771ff4cbb",
"rev": "f140aa04d7d14f8a50ab27f3691b5766b17ae961",
"type": "github"
},
"original": {
@@ -250,11 +250,11 @@
"spectrum": "spectrum"
},
"locked": {
"lastModified": 1771802632,
"narHash": "sha256-UAH8YfrHRvXAMeFxUzJ4h4B1loz1K1wiNUNI8KiPqOg=",
"lastModified": 1772338235,
"narHash": "sha256-9XcwtSIL/c+pkC3SBNuxCJuSktFOBV1TLvvkhekyB8I=",
"owner": "astro",
"repo": "microvm.nix",
"rev": "b67e3d80df3ec35bdfd3a00ad64ee437ef4fcded",
"rev": "9d1ff9b53532908a5eba7707931c9093508b6b92",
"type": "github"
},
"original": {
@@ -270,11 +270,11 @@
]
},
"locked": {
"lastModified": 1771734689,
"narHash": "sha256-/phvMgr1yutyAMjKnZlxkVplzxHiz60i4rc+gKzpwhg=",
"lastModified": 1772341813,
"narHash": "sha256-/PQ0ubBCMj/MVCWEI/XMStn55a8dIKsvztj4ZVLvUrQ=",
"owner": "Mic92",
"repo": "nix-index-database",
"rev": "8f590b832326ab9699444f3a48240595954a4b10",
"rev": "a2051ff239ce2e8a0148fa7a152903d9a78e854f",
"type": "github"
},
"original": {
@@ -285,11 +285,11 @@
},
"nixos-hardware": {
"locked": {
"lastModified": 1771423359,
"narHash": "sha256-yRKJ7gpVmXbX2ZcA8nFi6CMPkJXZGjie2unsiMzj3Ig=",
"lastModified": 1771969195,
"narHash": "sha256-qwcDBtrRvJbrrnv1lf/pREQi8t2hWZxVAyeMo7/E9sw=",
"owner": "NixOS",
"repo": "nixos-hardware",
"rev": "740a22363033e9f1bb6270fbfb5a9574067af15b",
"rev": "41c6b421bdc301b2624486e11905c9af7b8ec68e",
"type": "github"
},
"original": {
@@ -301,11 +301,11 @@
},
"nixpkgs": {
"locked": {
"lastModified": 1771369470,
"narHash": "sha256-0NBlEBKkN3lufyvFegY4TYv5mCNHbi5OmBDrzihbBMQ=",
"lastModified": 1772198003,
"narHash": "sha256-I45esRSssFtJ8p/gLHUZ1OUaaTaVLluNkABkk6arQwE=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "0182a361324364ae3f436a63005877674cf45efb",
"rev": "dd9b079222d43e1943b6ebd802f04fd959dc8e61",
"type": "github"
},
"original": {
@@ -344,11 +344,11 @@
]
},
"locked": {
"lastModified": 1770659507,
"narHash": "sha256-RVZno9CypFN3eHxfULKN1K7mb/Cq0HkznnWqnshxpWY=",
"lastModified": 1772064816,
"narHash": "sha256-ks1D9Rtmopd5F/8ENjEUJpSYYMxv603/v6TRen9Hq54=",
"owner": "simple-nixos-mailserver",
"repo": "nixos-mailserver",
"rev": "781e833633ebc0873d251772a74e4400a73f5d78",
"rev": "ea4dc17f4bc0f65eed082fa394509e4543072b56",
"type": "gitlab"
},
"original": {

View File

@@ -137,6 +137,7 @@
src = nixpkgs;
patches = [
./patches/dont-break-nix-serve.patch
./patches/libreoffice-noto-fonts-subset.patch
];
};
patchedNixpkgs = nixpkgs.lib.fix (self: (import "${patchedNixpkgsSrc}/flake.nix").outputs { self = nixpkgs; });

View File

@@ -79,12 +79,6 @@
# proxied web services
services.nginx.enable = true;
services.nginx.virtualHosts."navidrome.neet.cloud" = {
enableACME = true;
forceSSL = true;
locations."/".proxyPass = "http://s0.koi-bebop.ts.net:4533";
};
# TODO replace with a proper file hosting service
services.nginx.virtualHosts."tmp.neet.dev" = {
enableACME = true;

View File

@@ -115,15 +115,6 @@
statusCheck = false;
id = "5_1956_bazarr";
};
navidrome = {
title = "Navidrome";
description = "Play Music";
icon = "hl-navidrome";
url = "https://music.s0.neet.dev";
target = "sametab";
statusCheck = false;
id = "6_1956_navidrome";
};
transmission = {
title = "Transmission";
description = "Torrenting";
@@ -142,7 +133,6 @@
mediaItems.lidarr
mediaItems.prowlarr
mediaItems.bazarr
mediaItems.navidrome
mediaItems.transmission
];
in

View File

@@ -41,16 +41,6 @@
# samba
services.samba.enable = true;
# navidrome
services.navidrome = {
enable = true;
settings = {
Address = "0.0.0.0";
Port = 4533;
MusicFolder = "/data/samba/Public/Media/Music";
};
};
# allow access to transmisson data
users.users.googlebot.extraGroups = [ "transmission" ];
users.groups.transmission.gid = config.ids.gids.transmission;
@@ -234,7 +224,6 @@
(mkVirtualHost "prowlarr.s0.neet.dev" "http://servarr.containers:9696")
(mkVirtualHost "transmission.s0.neet.dev" "http://transmission.containers:8080")
(mkVirtualHost "unifi.s0.neet.dev" "https://localhost:8443")
(mkVirtualHost "music.s0.neet.dev" "http://localhost:4533")
(mkVirtualHost "jellyfin.s0.neet.dev" "http://localhost:8096")
(mkStaticHost "s0.neet.dev" config.services.dashy.finalDrv)
{
@@ -275,7 +264,6 @@
"prowlarr.s0.neet.dev"
"transmission.s0.neet.dev"
"unifi.s0.neet.dev"
# "music.s0.neet.dev" # messes up navidrome
"jellyfin.s0.neet.dev"
"s0.neet.dev"
# "ha.s0.neet.dev" # messes up home assistant

View File

@@ -60,16 +60,55 @@
### networking ###
# systemd.network.enable = true;
systemd.network.enable = true;
networking = {
# useNetworkd = true;
dhcpcd.enable = true;
interfaces."eth0".useDHCP = true;
interfaces."eth1".useDHCP = true;
useNetworkd = true;
useDHCP = false;
dhcpcd.enable = false;
};
defaultGateway = {
address = "192.168.1.1";
# eth0 — native VLAN 5 (main), default route, internet
# useDHCP generates the base 40-eth0 networkd unit and drives initrd DHCP for LUKS unlock.
networking.interfaces."eth0".useDHCP = true;
systemd.network.networks."40-eth0" = {
dhcpV4Config.RouteMetric = 100; # prefer eth0 over VLAN interfaces for default route
linkConfig.RequiredForOnline = "routable"; # wait-online succeeds once eth0 has a route
};
# eth1 — trunk port (no IP on the raw interface)
systemd.network.networks."10-eth1" = {
matchConfig.Name = "eth1";
networkConfig = {
VLAN = [ "vlan-iot" "vlan-mgmt" ];
LinkLocalAddressing = "no";
};
linkConfig.RequiredForOnline = "carrier";
};
# VLAN 2 — IoT (cameras, smart home)
systemd.network.netdevs."20-vlan-iot".netdevConfig = { Name = "vlan-iot"; Kind = "vlan"; };
systemd.network.netdevs."20-vlan-iot".vlanConfig.Id = 2;
systemd.network.networks."20-vlan-iot" = {
matchConfig.Name = "vlan-iot";
networkConfig.DHCP = "yes";
dhcpV4Config = {
UseGateway = false;
RouteMetric = 200;
};
linkConfig.RequiredForOnline = "no";
};
# VLAN 4 — Management
systemd.network.netdevs."20-vlan-mgmt".netdevConfig = { Name = "vlan-mgmt"; Kind = "vlan"; };
systemd.network.netdevs."20-vlan-mgmt".vlanConfig.Id = 4;
systemd.network.networks."20-vlan-mgmt" = {
matchConfig.Name = "vlan-mgmt";
networkConfig.DHCP = "yes";
dhcpV4Config = {
UseGateway = false;
RouteMetric = 300;
};
linkConfig.RequiredForOnline = "no";
};
powerManagement.cpuFreqGovernor = "schedutil";

View File

@@ -24,6 +24,10 @@
# Music assistant (must be exposed so local devices can fetch the audio stream from it)
8095
8097
# Music assistant: Spotify Connect zeroconf discovery (one per librespot instance)
44200
44201
];
services.zigbee2mqtt = {

View File

@@ -4,4 +4,23 @@ final: prev:
let
system = prev.system;
in
{ }
{
# Disable CephFS support in samba to work around upstream nixpkgs bug:
# ceph is pinned to python3.11 which is incompatible with sphinx >= 9.1.0.
# https://github.com/NixOS/nixpkgs/issues/442652
samba4Full = prev.samba4Full.override { enableCephFS = false; };
# Fix incus-lts doc build: `incus manpage` tries to create
# ~/.config/incus, but HOME is /homeless-shelter in the nix sandbox.
incus-lts = prev.incus-lts.overrideAttrs (old: {
nativeBuildInputs = (old.nativeBuildInputs or [ ]) ++ [ prev.writableTmpDirAsHomeHook ];
});
# Add --zeroconf-port support to Spotify Connect plugin so librespot
# binds to a fixed port that can be opened in the firewall.
music-assistant = prev.music-assistant.overrideAttrs (old: {
patches = (old.patches or [ ]) ++ [
../patches/music-assistant-zeroconf-port.patch
];
});
}

View File

@@ -0,0 +1,16 @@
Fix notoSubset glob for noto-fonts >= 2026.02.01.
noto-fonts switched from variable fonts (NotoSansArabic[wdth,wght].ttf)
to static fonts (NotoSansArabic.ttf). The old glob pattern only matched
files with brackets in the name, causing the cp to fail.
--- a/pkgs/applications/office/libreoffice/default.nix
+++ b/pkgs/applications/office/libreoffice/default.nix
@@ -191,7 +191,7 @@
runCommand "noto-fonts-subset" { } ''
mkdir -p "$out/share/fonts/noto/"
${concatMapStrings (x: ''
- cp "${noto-fonts}/share/fonts/noto/NotoSans${x}["*.[ot]tf "$out/share/fonts/noto/"
+ cp "${noto-fonts}/share/fonts/noto/NotoSans${x}"*.[ot]tf "$out/share/fonts/noto/"
'') suffixes}
'';

View File

@@ -0,0 +1,40 @@
diff --git a/music_assistant/providers/spotify_connect/__init__.py b/music_assistant/providers/spotify_connect/__init__.py
index 1111111..2222222 100644
--- a/music_assistant/providers/spotify_connect/__init__.py
+++ b/music_assistant/providers/spotify_connect/__init__.py
@@ -51,6 +51,7 @@ CONNECT_ITEM_ID = "spotify_connect"
CONF_PUBLISH_NAME = "publish_name"
CONF_ALLOW_PLAYER_SWITCH = "allow_player_switch"
+CONF_ZEROCONF_PORT = "zeroconf_port"
# Special value for auto player selection
PLAYER_ID_AUTO = "__auto__"
@@ -117,6 +118,15 @@ async def get_config_entries(
description="How should this Spotify Connect device be named in the Spotify app?",
default_value="Music Assistant",
),
+ ConfigEntry(
+ key=CONF_ZEROCONF_PORT,
+ type=ConfigEntryType.INTEGER,
+ label="Zeroconf port",
+ description="Fixed TCP port for Spotify Connect discovery (zeroconf). "
+ "Set to a specific port and open it in your firewall to allow "
+ "devices on the network to discover this player. 0 = random port.",
+ default_value=0,
+ ),
# ConfigEntry(
# key=CONF_HANDOFF_MODE,
# type=ConfigEntryType.BOOLEAN,
@@ -677,6 +687,11 @@ class SpotifyConnectProvider(PluginProvider):
"--onevent",
str(EVENTS_SCRIPT),
"--emit-sink-events",
+ *(
+ ["--zeroconf-port", str(zeroconf_port)]
+ if (zeroconf_port := int(self.config.get_value(CONF_ZEROCONF_PORT) or 0)) > 0
+ else []
+ ),
]
self._librespot_proc = librespot = AsyncProcess(
args, stdout=False, stderr=True, name=f"librespot[{self.name}]", env=env