Add Pi-hole DNS blocking + TV lockdown, new services, flake upgrade
- Enable pihole-ftl/pihole-web for network-wide DNS ad-blocking on the LAN/Tailscale side, keeping nixserve's own resolution untouched - Seed a dedicated Pi-hole group that locks the smart TV (by MAC) to resolving only *.maybec.at, denying everything else - Add pingvin-share, frigate, mosquitto, and homeassistant docker services with matching nginx vhosts and firewall port for Home Assistant - Disable immich (unused for now), add proxySsl option to proxyVhost - Bump flake.lock (nixpkgs/home-manager upgrade) Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Generated
+13
-13
@@ -6,11 +6,11 @@
|
|||||||
"rust-overlay": "rust-overlay"
|
"rust-overlay": "rust-overlay"
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1787536184,
|
"lastModified": 1790589489,
|
||||||
"narHash": "sha256-BElMdZnbe7Trt7Rs0u5utMbLm8Fydq6g0XhRHQCixAU=",
|
"narHash": "sha256-Sn9W64W4KOga829nzathqymFvtwZsb/klyQFS/3Nq1A=",
|
||||||
"owner": "ogulcancelik",
|
"owner": "ogulcancelik",
|
||||||
"repo": "herdr",
|
"repo": "herdr",
|
||||||
"rev": "7d56b4c51b046a5d477439bcea4512339f8841aa",
|
"rev": "7f89b11a11160874ba89f3be7c64b29960bd2df3",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -26,11 +26,11 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1787377438,
|
"lastModified": 1790215976,
|
||||||
"narHash": "sha256-Sxu1NLTD/Ern6hFGLlZmtKCSct3YQXZI/lls8RE1XeM=",
|
"narHash": "sha256-VkR1rMGyjU9jtw8ISFx5uqR9e+LEaOlhHwrseFkiIVk=",
|
||||||
"owner": "nix-community",
|
"owner": "nix-community",
|
||||||
"repo": "home-manager",
|
"repo": "home-manager",
|
||||||
"rev": "65258d5c65a250189fde2e35f490d15e064c4c62",
|
"rev": "a6631107a83ceab5872f298a2ea710859c80c4cb",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -42,11 +42,11 @@
|
|||||||
},
|
},
|
||||||
"nixpkgs": {
|
"nixpkgs": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1779357205,
|
"lastModified": 1779911860,
|
||||||
"narHash": "sha256-cCO8aTqss5x9Ky8GWkpY0Hy5fyTZEbtifSUV8QjSzic=",
|
"narHash": "sha256-ubcLAcKBDCZjhxw/kH5DL5GdBZQdzLqpkTe7HonvJVs=",
|
||||||
"owner": "NixOS",
|
"owner": "NixOS",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "f83fc3c307e74bc5fd5adb7eb6b8b13ffd2a36e1",
|
"rev": "c0a89c379b4ac67c7b13b051ddbd4e0dbc9b0eaf",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -58,11 +58,11 @@
|
|||||||
},
|
},
|
||||||
"nixpkgs_2": {
|
"nixpkgs_2": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1787414105,
|
"lastModified": 1790533781,
|
||||||
"narHash": "sha256-8FnH9CMQCQ9i7d7xrXK30SBjgODxlkltCa0thsRgrxg=",
|
"narHash": "sha256-hzJtu90JIQXnmgxKeP23CAx86G4L+dcQ+GHB1JK04qA=",
|
||||||
"rev": "a9e6d84f9c2f9012f5fe7d964a7851352300e61a",
|
"rev": "cf5e76507c6e23b59f7e0ffcc7baa2a39ddd8442",
|
||||||
"type": "tarball",
|
"type": "tarball",
|
||||||
"url": "https://releases.nixos.org/nixos/26.05/nixos-26.05.8255.a9e6d84f9c2f/nixexprs.tar.xz"
|
"url": "https://releases.nixos.org/nixos/26.05/nixos-26.05.10769.cf5e76507c6e/nixexprs.tar.zst"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
"id": "nixpkgs",
|
"id": "nixpkgs",
|
||||||
|
|||||||
@@ -47,7 +47,7 @@
|
|||||||
users.groups.media = {};
|
users.groups.media = {};
|
||||||
users.users.jellyfin.extraGroups = [ "media" ];
|
users.users.jellyfin.extraGroups = [ "media" ];
|
||||||
|
|
||||||
networking.firewall.allowedTCPPorts = [ 80 443 /* HTTP */ 111 2049 4000 4001 4002 20048 /* NFS */ 3923 /* copyparty */ ];
|
networking.firewall.allowedTCPPorts = [ 80 443 /* HTTP */ 111 2049 4000 4001 4002 20048 /* NFS */ 3923 /* copyparty */ 8123 /* Home Assistant (LAN devices, e.g. Cast TTS fetch) */ ];
|
||||||
networking.firewall.allowedUDPPorts = [ 111 2049 4000 4001 4002 20048 /* NFS */ ];
|
networking.firewall.allowedUDPPorts = [ 111 2049 4000 4001 4002 20048 /* NFS */ ];
|
||||||
networking.firewall.trustedInterfaces = [ "tailscale0" ];
|
networking.firewall.trustedInterfaces = [ "tailscale0" ];
|
||||||
|
|
||||||
|
|||||||
+111
-6
@@ -3,7 +3,7 @@
|
|||||||
let
|
let
|
||||||
rssdownloader = pkgs.callPackage ./rssdownloader.nix { src = rssdownloader-src; };
|
rssdownloader = pkgs.callPackage ./rssdownloader.nix { src = rssdownloader-src; };
|
||||||
|
|
||||||
proxyVhost = { upstream, websockets ? true, maxBodySize ? "1g" }: {
|
proxyVhost = { upstream, websockets ? true, maxBodySize ? "1g", proxySsl ? false }: {
|
||||||
forceSSL = true;
|
forceSSL = true;
|
||||||
enableACME = true;
|
enableACME = true;
|
||||||
locations."/" = {
|
locations."/" = {
|
||||||
@@ -18,7 +18,9 @@ let
|
|||||||
proxy_send_timeout 3600;
|
proxy_send_timeout 3600;
|
||||||
proxy_buffering off;
|
proxy_buffering off;
|
||||||
client_max_body_size ${maxBodySize};
|
client_max_body_size ${maxBodySize};
|
||||||
'';
|
'' + (if proxySsl then ''
|
||||||
|
proxy_ssl_verify off;
|
||||||
|
'' else "");
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -82,10 +84,10 @@ in
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
services.immich = {
|
#services.immich = {
|
||||||
enable = true;
|
# enable = true;
|
||||||
mediaLocation = "/media/immich";
|
# mediaLocation = "/media/immich";
|
||||||
};
|
#};
|
||||||
|
|
||||||
users.users.git = {
|
users.users.git = {
|
||||||
isSystemUser = true;
|
isSystemUser = true;
|
||||||
@@ -127,6 +129,82 @@ in
|
|||||||
pools = [ "media" ];
|
pools = [ "media" ];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
# DNS ad-blocking for other LAN/Tailscale clients only.
|
||||||
|
# nixserve's own DNS resolution is untouched (Tailscale MagicDNS via resolv.conf).
|
||||||
|
services.pihole-ftl = {
|
||||||
|
enable = true;
|
||||||
|
openFirewallDNS = true;
|
||||||
|
openFirewallWebserver = true;
|
||||||
|
|
||||||
|
lists = [
|
||||||
|
{ url = "https://raw.githubusercontent.com/StevenBlack/hosts/master/hosts"; description = "StevenBlack unified hosts"; }
|
||||||
|
];
|
||||||
|
|
||||||
|
settings = {
|
||||||
|
dns.upstreams = [ "1.1.1.1" "1.0.0.1" ];
|
||||||
|
webserver.api.cli_pw = true;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
services.pihole-web = {
|
||||||
|
enable = true;
|
||||||
|
ports = [ "8081o" ];
|
||||||
|
};
|
||||||
|
|
||||||
|
# Lock the smart TV down to *.maybec.at only: everything else fails to resolve.
|
||||||
|
# This seeds Pi-hole's gravity.db (groups/clients/rules) declaratively on every
|
||||||
|
# boot/rebuild -- that data lives outside pihole.toml so it isn't covered by
|
||||||
|
# services.pihole-ftl.settings.
|
||||||
|
systemd.services.pihole-tv-lockdown = {
|
||||||
|
description = "Seed Pi-hole gravity.db with smart TV DNS lockdown rules";
|
||||||
|
# gravity.db's group/client/rule tables are queried live per DNS lookup
|
||||||
|
# (not cached at FTL startup), so this only needs to run after FTL has
|
||||||
|
# created the database -- no need to race it to run "before" FTL starts.
|
||||||
|
after = [ "pihole-ftl.service" ];
|
||||||
|
wantedBy = [ "multi-user.target" ];
|
||||||
|
serviceConfig = {
|
||||||
|
Type = "oneshot";
|
||||||
|
RemainAfterExit = true;
|
||||||
|
User = config.services.pihole-ftl.user;
|
||||||
|
Group = config.services.pihole-ftl.group;
|
||||||
|
};
|
||||||
|
script = ''
|
||||||
|
set -euo pipefail
|
||||||
|
${pkgs.sqlite}/bin/sqlite3 "${config.services.pihole-ftl.stateDirectory}/gravity.db" <<'SQL'
|
||||||
|
INSERT OR IGNORE INTO "group" (name, enabled, description)
|
||||||
|
VALUES ('tv-only', 1, 'Smart TV: only *.maybec.at may resolve');
|
||||||
|
|
||||||
|
INSERT OR IGNORE INTO domainlist (type, domain, enabled, comment)
|
||||||
|
VALUES (2, '.*', 1, 'tv-only: deny everything');
|
||||||
|
INSERT OR IGNORE INTO domainlist (type, domain, enabled, comment)
|
||||||
|
VALUES (3, '(^|\.)maybec\.at$', 1, 'tv-only: allow maybec.at and subdomains');
|
||||||
|
|
||||||
|
INSERT OR IGNORE INTO domainlist_by_group (domainlist_id, group_id)
|
||||||
|
SELECT d.id, g.id FROM domainlist d, "group" g
|
||||||
|
WHERE d.domain IN ('.*', '(^|\.)maybec\.at$') AND g.name = 'tv-only';
|
||||||
|
|
||||||
|
INSERT OR IGNORE INTO client (ip, comment)
|
||||||
|
VALUES ('20:28:bc:15:1d:c0', 'Smart TV (locked to maybec.at only)');
|
||||||
|
|
||||||
|
INSERT OR IGNORE INTO client_by_group (client_id, group_id)
|
||||||
|
SELECT c.id, g.id FROM client c, "group" g
|
||||||
|
WHERE c.ip = '20:28:bc:15:1d:c0' AND g.name = 'tv-only';
|
||||||
|
|
||||||
|
-- Pi-hole auto-links every new domainlist/client row into the Default
|
||||||
|
-- group (tr_domainlist_add / tr_client_add triggers). Strip that back
|
||||||
|
-- out, otherwise the deny-all regex applies to every client on the
|
||||||
|
-- network instead of just the TV.
|
||||||
|
DELETE FROM domainlist_by_group
|
||||||
|
WHERE group_id = 0
|
||||||
|
AND domainlist_id IN (SELECT id FROM domainlist WHERE domain IN ('.*', '(^|\.)maybec\.at$'));
|
||||||
|
|
||||||
|
DELETE FROM client_by_group
|
||||||
|
WHERE group_id = 0
|
||||||
|
AND client_id IN (SELECT id FROM client WHERE ip = '20:28:bc:15:1d:c0');
|
||||||
|
SQL
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
virtualisation.docker = {
|
virtualisation.docker = {
|
||||||
enable = true;
|
enable = true;
|
||||||
enableOnBoot = true;
|
enableOnBoot = true;
|
||||||
@@ -180,6 +258,30 @@ in
|
|||||||
dir = "/home/ulve/code/colony-archive";
|
dir = "/home/ulve/code/colony-archive";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
systemd.services.pingvin-share = dockerService {
|
||||||
|
name = "pingvin-share";
|
||||||
|
description = "Pingvin Share file sharing service";
|
||||||
|
dir = "/home/ulve/code/pingvin-share";
|
||||||
|
};
|
||||||
|
|
||||||
|
systemd.services.frigate = dockerService {
|
||||||
|
name = "frigate";
|
||||||
|
description = "Frigate NVR";
|
||||||
|
dir = "/home/ulve/code/frigate";
|
||||||
|
};
|
||||||
|
|
||||||
|
systemd.services.mosquitto = dockerService {
|
||||||
|
name = "mosquitto";
|
||||||
|
description = "Mosquitto MQTT broker";
|
||||||
|
dir = "/home/ulve/code/mosquitto";
|
||||||
|
};
|
||||||
|
|
||||||
|
systemd.services.homeassistant = dockerService {
|
||||||
|
name = "homeassistant";
|
||||||
|
description = "Home Assistant";
|
||||||
|
dir = "/home/ulve/code/homeassistant";
|
||||||
|
};
|
||||||
|
|
||||||
systemd.services.dozzle = {
|
systemd.services.dozzle = {
|
||||||
description = "Dozzle Docker log viewer";
|
description = "Dozzle Docker log viewer";
|
||||||
after = [ "docker.service" "network.target" ];
|
after = [ "docker.service" "network.target" ];
|
||||||
@@ -208,5 +310,8 @@ virtualHosts."aftersummer.maybec.at" = proxyVhost { upstream = "http://127.0.0.
|
|||||||
virtualHosts."photos.maybec.at" = proxyVhost { upstream = "http://[::1]:2283"; maxBodySize = "50g"; };
|
virtualHosts."photos.maybec.at" = proxyVhost { upstream = "http://[::1]:2283"; maxBodySize = "50g"; };
|
||||||
virtualHosts."colony.maybec.at" = proxyVhost { upstream = "http://127.0.0.1:3333"; };
|
virtualHosts."colony.maybec.at" = proxyVhost { upstream = "http://127.0.0.1:3333"; };
|
||||||
virtualHosts."git.maybec.at" = proxyVhost { upstream = "http://127.0.0.1:3001"; maxBodySize = "10g"; };
|
virtualHosts."git.maybec.at" = proxyVhost { upstream = "http://127.0.0.1:3001"; maxBodySize = "10g"; };
|
||||||
|
virtualHosts."share.maybec.at" = proxyVhost { upstream = "http://127.0.0.1:8090"; maxBodySize = "10g"; };
|
||||||
|
virtualHosts."cam.maybec.at" = proxyVhost { upstream = "https://127.0.0.1:8971"; proxySsl = true; };
|
||||||
|
virtualHosts."home.maybec.at" = proxyVhost { upstream = "http://127.0.0.1:8123"; };
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user