From d4aaa1a60cec8e60636931bfbb0515d921ba5e5d Mon Sep 17 00:00:00 2001 From: williamvds Date: Wed, 5 Apr 2023 00:25:31 +0100 Subject: [PATCH] nixos/pihole-web: init Pihole's dashboard is a web app which visualises statistics from pihole-FTL (i.e. dnsmasq), shows query logs, and allows configuration. With this module, configuration is largely declarative and immutable, so settings can't be changed, but they can be viewed from the webpage. The admin page also allows regenerating the DNS ("gravity") database, which requires write access to the pihole state directory, as well as being able to signal pihole-FTL to reload its DNS cache. For the latter, a polkit rule is optionally enabled. --- nixos/modules/module-list.nix | 1 + nixos/modules/services/web-apps/pihole-web.md | 13 ++ .../modules/services/web-apps/pihole-web.nix | 131 ++++++++++++++++++ 3 files changed, 145 insertions(+) create mode 100644 nixos/modules/services/web-apps/pihole-web.md create mode 100644 nixos/modules/services/web-apps/pihole-web.nix diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix index f15a537b10e6a3..ea90378969915a 100644 --- a/nixos/modules/module-list.nix +++ b/nixos/modules/module-list.nix @@ -1323,6 +1323,7 @@ ./services/web-apps/phylactery.nix ./services/web-apps/photoprism.nix ./services/web-apps/pict-rs.nix + ./services/web-apps/pihole-web.nix ./services/web-apps/plantuml-server.nix ./services/web-apps/plausible.nix ./services/web-apps/powerdns-admin.nix diff --git a/nixos/modules/services/web-apps/pihole-web.md b/nixos/modules/services/web-apps/pihole-web.md new file mode 100644 index 00000000000000..329eb0c0bd3d2c --- /dev/null +++ b/nixos/modules/services/web-apps/pihole-web.md @@ -0,0 +1,13 @@ +# Pi-hole Dashboard {#module-services-web-apps-pihole-web} + +The Pi-hole suite provides a web GUI for controlling and monitoring +[pihole-FTL](#module-services-networking-pihole-ftl). + +## Configuration {#module-services-web-apps-pihole-web-configuration} + +The dashboard requires little configuration, because it is largely parsed from +[the Dnsmasq configuration](#module-services-networking-dnsmasq). + +Note that most settings on the *Settings* page are Dnsmasq options. Since the +configuration is immutable and comes from NixOS options, most settings cannot be +changed. diff --git a/nixos/modules/services/web-apps/pihole-web.nix b/nixos/modules/services/web-apps/pihole-web.nix new file mode 100644 index 00000000000000..93174bf5fd9f61 --- /dev/null +++ b/nixos/modules/services/web-apps/pihole-web.nix @@ -0,0 +1,131 @@ +{ pkgs +, lib +, config +, ... +}: + +with { inherit (lib) mdDoc mkOption types; }; + +let + cfg = config.services.pihole-web; + ftlCfg = config.services.pihole-ftl; +in +{ + options.services.pihole-web = { + enable = lib.mkEnableOption (mdDoc "Pi-hole dashboard"); + hostName = mkOption { + type = types.str; + description = mdDoc "Domain name for the website."; + default = "pi.hole"; + }; + package = lib.mkPackageOptionMD pkgs "pihole-web" {}; + dnsServers = mkOption { + type = types.str; + description = mdDoc '' + DNS providers list. + The default value is extracted from [the pihole installation + script](https://github.com/pi-hole/pi-hole/blob/6a45c6a8e027e1ac30d4556a88f31684bc80ccf1/advanced/Scripts/piholeLogFlush.sh#L45-L53). + ''; + default = '' + Google (ECS);8.8.8.8;8.8.4.4;2001:4860:4860:0:0:0:0:8888;2001:4860:4860:0:0:0:0:8844 + OpenDNS (ECS, DNSSEC);208.67.222.222;208.67.220.220;2620:119:35::35;2620:119:53::53 + Level3;4.2.2.1;4.2.2.2;; + Comodo;8.26.56.26;8.20.247.20;; + DNS.WATCH;84.200.69.80;84.200.70.40;2001:1608:10:25:0:0:1c04:b12f;2001:1608:10:25:0:0:9249:d69b + Quad9 (filtered, DNSSEC);9.9.9.9;149.112.112.112;2620:fe::fe;2620:fe::9 + Quad9 (unfiltered, no DNSSEC);9.9.9.10;149.112.112.10;2620:fe::10;2620:fe::fe:10 + Quad9 (filtered + ECS);9.9.9.11;149.112.112.11;2620:fe::11;2620:fe::fe:11 + Cloudflare;1.1.1.1;1.0.0.1;2606:4700:4700::1111;2606:4700:4700::1001 + ''; + }; + theme = mkOption { + type = types.enum [ "default-light" "default-dark" "default-darker" "default-auto" "lcars" ]; + description = mdDoc "Website theme"; + default = "default-light"; + example = "default-dark"; + }; + temperatureUnit = mkOption { + type = types.enum [ "C" "F" ]; + description = mdDoc "Temperature display unit"; + default = "C"; + example = "F"; + }; + enablePolkitRule = mkOption { + type = types.bool; + description = mdDoc '' + Enable a Polkit rule which allows users to restart the pihole-FTL daemon + from the Update Gravity webpage. + ''; + default = true; + }; + }; + + config = lib.mkIf cfg.enable { + services.phpfpm.pools.pihole = { + user = ftlCfg.user; + group = ftlCfg.group; + phpPackage = pkgs.php; + settings = lib.mapAttrs (name: lib.mkDefault) { + "listen.owner" = config.services.nginx.user; + "listen.group" = config.services.nginx.group; + "pm" = "ondemand"; + "pm.max_children" = 5; + }; + }; + + services.nginx.virtualHosts.${cfg.hostName} = { + root = "${cfg.package}/share"; + locations = { + "/".index = "index.php"; + "~ \\.php$".extraConfig = '' + include ${config.services.nginx.package}/conf/fastcgi.conf; + fastcgi_param SERVER_NAME $host; + fastcgi_pass unix:${config.services.phpfpm.pools.pihole.socket}; + fastcgi_intercept_errors on; + fastcgi_request_buffering off; + ''; + "= /favicon.ico".extraConfig = "access_log off; log_not_found off;"; + }; + + # Some inline styles and scripts require the unsafe-inline CSP + # See https://github.com/pi-hole/web/pull/1377 + extraConfig = '' + add_header X-Pi-hole "The Pi-hole Web interface is working!"; + add_header X-Frame-Options "SAMEORIGIN"; + add_header X-XSS-Protection "0"; + add_header X-Content-Type-Options "nosniff"; + add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline';"; + add_header X-Permitted-Cross-Domain-Policies "none"; + add_header Referrer-Policy "same-origin"; + ''; + }; + + # The Update Gravity page requires writing to pihole's state directory + systemd.services.phpfpm-pihole.serviceConfig = { + ReadWritePaths = [ ftlCfg.stateDirectory ftlCfg.logDirectory ]; + }; + + environment.etc."pihole/dns-servers.conf" = { + user = ftlCfg.user; + group = ftlCfg.group; + text = cfg.dnsServers; + }; + + # The Update Gravity page needs to restart pihole-ftl + security.polkit.extraConfig = lib.mkIf cfg.enablePolkitRule '' + polkit.addRule(function(action, subject) { + if (action.id == "org.freedesktop.systemd1.manage-units" && + action.lookup("unit") == "pihole-ftl.service" && + action.lookup("verb") == "restart" && + subject.user == "${ftlCfg.user}") { + return polkit.Result.YES; + } + }); + ''; + }; + + meta = { + doc = ./pihole-web.md; + maintainers = with lib.maintainers; [ williamvds ]; + }; +}