Skip to content

Commit

Permalink
nixos/pihole-adminlte: init
Browse files Browse the repository at this point in the history
Pihole's AdminLTE 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.
  • Loading branch information
williamvds committed May 14, 2023
1 parent 3c193ef commit f1a9471
Show file tree
Hide file tree
Showing 5 changed files with 154 additions and 1 deletion.
2 changes: 1 addition & 1 deletion nixos/doc/manual/release-notes/rl-2305.section.md
Expand Up @@ -124,7 +124,7 @@ In addition to numerous new and upgraded packages, this release has the followin

- [peroxide](https://github.com/ljanyst/peroxide), a fork of the official [ProtonMail bridge](https://github.com/ProtonMail/proton-bridge) that aims to be similar to [Hydroxide](https://github.com/emersion/hydroxide). Available as [services.peroxide](#opt-services.peroxide.enable).

- [Pi-hole](https://pi-hole.net/), a DNS sinkhole for advertisements based on Dnsmasq. Available as [services.pihole-ftl](#opt-services.pihole-ftl.enable).
- [Pi-hole](https://pi-hole.net/), a DNS sinkhole for advertisements based on Dnsmasq. Available as [services.pihole-ftl](#opt-services.pihole-ftl.enable), and [services.pihole-adminlte](#opt-services.pihole-adminlte.enable) for the web GUI.

- [autosuspend](https://github.com/languitar/autosuspend), a python daemon that suspends a system if certain conditions are met, or not met.

Expand Down
1 change: 1 addition & 0 deletions nixos/modules/module-list.nix
Expand Up @@ -1218,6 +1218,7 @@
./services/web-apps/phylactery.nix
./services/web-apps/photoprism.nix
./services/web-apps/pict-rs.nix
./services/web-apps/pihole-adminlte.nix
./services/web-apps/plantuml-server.nix
./services/web-apps/plausible.nix
./services/web-apps/powerdns-admin.nix
Expand Down
3 changes: 3 additions & 0 deletions nixos/modules/services/networking/pihole-ftl.md
Expand Up @@ -46,3 +46,6 @@ https://example.com/adlist.txt**.
Note that in NixOS the script has been patched to remove the reinstallation,
update, and Dnsmasq configuration commands. In NixOS, Pi-hole's configuration is
immutable and must be done with NixOS options.

For more convenient administration and monitoring, see [Pi-hole
AdminLTE](#module-services-web-apps-pihole-adminlte)
22 changes: 22 additions & 0 deletions nixos/modules/services/web-apps/pihole-adminlte.md
@@ -0,0 +1,22 @@
# Pi-hole AdminLTE {#module-services-web-apps-pihole-adminlte}

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-adminlte-configuration}

AdminLTE requires little configuration, because it is largely is largely parsed
from [the Dnsmasq configuration](https://search.nixos.org/options?from=0&size=50&sort=relevance&type=packages&query=services.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.

Example configuration:

```
services.pihole-adminlte = {
enable = true;
theme = "default-darker";
};
```
127 changes: 127 additions & 0 deletions nixos/modules/services/web-apps/pihole-adminlte.nix
@@ -0,0 +1,127 @@
{ pkgs
, lib
, config
, ...
}:

with lib;

let
cfg = config.services.pihole-adminlte;
ftlCfg = config.services.pihole-ftl;
user = ftlCfg.user;
group = ftlCfg.group;
in
{
options.services.pihole-adminlte = {
enable = mkEnableOption (mdDoc "Pi-hole admin dashboard");
hostName = mkOption {
type = types.str;
description = mdDoc "Domain name for the website.";
default = "pi.hole";
};
package = mkPackageOptionMD pkgs "pihole-adminlte" {};
dnsServers = mkOption {
type = types.str;
description = mdDoc ''
DNS providers list.
The default value is extracted from the pihole installation script.
'';
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 website. This can be done from the Update Gravity page.
'';
default = true;
};
};

config = mkIf cfg.enable {
services.phpfpm.pools.pihole = {
inherit user group;
phpPackage = pkgs.php;
settings = mapAttrs (name: 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 = {
"/".extraConfig = "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;";
"~ /\\.".extraConfig = "access_log off; log_not_found off; deny all;";
"~ ~$ ".extraConfig = "access_log off; log_not_found off; deny all;";
};
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' '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 = [ config.services.pihole-ftl.stateDirectory ];
};

environment.etc."pihole/dns-servers.conf" = {
inherit user group;
text = cfg.dnsServers;
mode = "644";
};

# The Update Gravity page needs to restart pihole-ftl
security.polkit.extraConfig = 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 == "${user}") {
return polkit.Result.YES;
}
});
'';
};

meta.doc = ./pihole-adminlte.md;
}

0 comments on commit f1a9471

Please sign in to comment.