flake(docs): add a Readme & an example system configuration

This commit is contained in:
Christopher Bacher 2022-12-04 22:36:25 +01:00
parent a8119d7a1b
commit 9d22275025
2 changed files with 175 additions and 0 deletions

70
Readme.md Normal file
View file

@ -0,0 +1,70 @@
# Pi-hole Flake
A NixOS flake providing a [Pi-hole](https://pi-hole.net) container & NixOS module for running it in a (rootless) podman container.
The flake provides a container image for Pi-hole by fetching the `pihole/pihole` image version defined in `pihole-image-base-info.nix`.
Currently the container image can be built for `x64_64-linux` and `aarch64-linux` systems.
Further the flake comes with a NixOS module that can be used to configure & run Pi-hole as a `systemd` service.
Contrary to NixOS' oci-container support this flake allows to run Pi-hole in a rootless container environment---which is also the main reason why this flake exists.
Another benefit of using the provided NixOS module is that it explicitly exposes the supported configuration options of the Pi-hole container.
## Configuring Pi-hole
All configuration options can be found under the key `service.pihole`.
The Pi-hole service can be enabled by setting `services.pihole.enable = true`.
Full descriptions of the configuration options can be found the in the module.
Example configurations can be found in the `examples` folder.
The module options are separate into two parts:
* **Host-specific options** which define how the Pi-hole container should be run on the host
* **Pi-hole-specific options** which configure the Pi-hole service in the container
### Host-specific options
All host-specific options are contained in `services.pihole.hostConfig`.
Among others the `hostConfig` contains the options for exposing the ports of Pi-hole's DNS, DHCP, and web UI components.
Remember if that if you run the service in a rootless container binding to priviledged ports is by default not possible.
To handle this limitation you can either:
* *Access the components on non-privileged ports:* This should be easily possible for the web & DNS components---if your DHCP server supports DNS servers with non-standard ports or if you configure your DNS resolvers to use a non-default port by other means.
If you use Pi-hole's DHCP server then lookup your DHCP client's documentation on how to send DHCP requests to non-standard ports.
* *Use port-fowarding from a privileged to an unprivileged port*
* *Change the range of privileged ports:* see `sysctl net.ipv4.ip_unprivileged_port_start`
Also do not forget to open the exposed ports in NixOS' firewall otherwise you won't be able to access the services.
As the Pi-hole container supports to be run rootless, you need to configure which user should run the Pi-hole container via `services.pihole.hostConfig.user`.
This user needs a [subuid](https://nixos.org/manual/nixos/stable/options.html#opt-users.users._name_.subUidRanges)/[subgid](https://nixos.org/manual/nixos/stable/options.html#opt-users.users._name_.subGidRanges) ranges defined or [automatically configured](https://nixos.org/manual/nixos/stable/options.html#opt-users.users._name_.autoSubUidGidRange) s.t. she can run rootless podman containers.
If you want to persist your Pi-hole configuration (the changes you made via the UI) between container restarts take a look at `services.pihole.hostConfig.persistVolumes` and `services.pihole.hostConfig.volumesPath`.
Running rootless podman containers can be unstable and the systemd service can fail if certain precautions are not taken:
* The user running the Pi-hole container should be allowed to linger after all her sessions are closed.
See `services.pihole.hostConfig.enableLingeringForUser` for details.
* The temporary directory used by rootless podman should be cleaned of any remains on system start.
See `services.pihole.hostConfig.suppressTmpDirWarning` for details.
### Pi-hole options
All options for configuring Pi-hole itself can be found under the key `services.pihole.piholeConfig`.
The exposed options are mainly those listed as the environment variables of the [Docker image](https://github.com/pi-hole/docker-pi-hole#environment-variables) or of [FTLDNS](https://docs.pi-hole.net/ftldns/configfile/).
Though the options have been grouped to provide more structure (see the option declarations in the module for details).
## Updating[^1] the Pi-hole Image
Because this is a NixOS flake, when building the flake the Pi-hole container image that is used must be fixed.
Otherwise the hash of image cannot be known and the flake build would fail.
Therefore the used version of the image must be pinned before building the flake.
The image information is stored in `./pihole-image-info.ARCH.nix` where `ARCH` is either `amd64` or `arm64`.
To update both architectures to the newest Pi-hole image version execute:
```bash
nix develop
update-pihole-image-info --arch amd64
update-pihole-image-info --arch arm64
``
The `update-pihole-image-info` command determines the newest image digest available, pre-fetches the images into the nix-store, and updates the respective `./pihole-image-info.ARCH.nix` files.
[^1]: The image in the upstream repository is not updated regularly. Please use & update your local clone of the flake, instead of using the vanilla upstream version.

View file

@ -0,0 +1,105 @@
## This is an example flake-based NixOS configuration to show the use of the pihole-flake.
## The configuration is not complete and it is assumed that a `./configuration.nix` and `./hardware.nix` exists.
## The example will start Pi-hole in an unprivileged container and expose the DNS & web services on unpriviledged ports.
{
inputs = {
nixpkgs.url = "nixpkgs/nixos-unstable";
# Opinionated: This config defines all (transitive) inputs of all used flakes explicitly
# s.t we are in complete control of which packages & flake versions are used.
# Otherwise it can happed that we use several versions of the same flake
# because different other flakes which depend on it pinned it to different versions.
# Especially with `nixpkgs` this can become a security (outdated packages) & resource problem (storage space).
flake-utils.url = "github:numtide/flake-utils";
# Required for making sure that Pi-hole continues running if the executing user has no active session.
linger = {
url = "github:mindsbackyard/linger-flake";
inputs.flake-utils.follows = "flake-utils";
};
pihole = {
url = "github:mindsbackyard/pihole-flake";
inputs.nixpkgs.follow = "nixpkgs";
inputs.flake-utils.follows = "flake-utils";
inputs.linger.follows = "linger";
};
};
outputs = { self, nixpkgs, linger, pihole, ... }:
let
system = "x86_64-linux";
# use x86_64 packages from nixpkgs
pkgs = nixpkgs.legacyPackages.${system};
in {
nixosConfigurations."nixos-example-system" = nixpkgs.lib.nixosSystem {
# nixosSystem needs to know the system architecture
inherit system;
modules = [
# a small module for enabling nix flakes
{ ... }: {
nix = {
packge = pkgs.nixFlakes;
extraOptions = "experimental-features = nix-command flake";
# Opinionated: use system flake's (locked) `nixpkgs` as default `nixpkgs` for flake commands
# see https://dataswamp.org/~solene/2022-07-20-nixos-flakes-command-sync-with-system.html
registry.nixpkgs.flake = nixpkgs;
};
}
# some existing system & hardware configuration modules; it is assumed that a user named `pihole` is defined here
# and that the user has sub-uids/gids configured (e.g. via the `users.users.pihole.subUidRanges/subGidRanges` options)
./configuration.nix
./hardware.nix
# make the module declared by the linger flake available to our config
linger.nixosModules.${system}.default
pihole.nixosModules.${system}.default
# in another module we can now configure the lingering behaviour (could also be part of ./configuration.nix)
{ ... }: {
# required for stable restarts of the Pi-hole container (try to remove it to see the warning from the pihole-flake)
boot.cleanTmpDir = true;
# the Pi-hole service configuration
services.pihole = {
enable = true;
hostConfig = {
# define the service user for running the rootless Pi-hole container
user = "pihole";
enableLingeringForUser = true;
# we want to persist change to the Pi-hole configuration & logs across service restarts
# check the option descriptions for more information
persistVolumes = true;
# expose DNS & the web interface on unpriviledged ports on all IP addresses of the host
# check the option descriptions for more information
dnsPort = 5335;
webProt = 8080;
};
piholeConfig.ftl = {
# assuming that the host has this (fixed) IP and should resolve "pi.hole" to this address
# check the option description & the FTLDNS documentation for more information
LOCAL_IPV4 = "192.168.0.2";
};
piholeCOnfig.web = {
virtualHost = "pi.hole";
password = "password";
};
};
# we need to open the ports in the firewall to make the service accessible beyond `localhost`
# assuming that Pi-hole is exposed on the host interface `eth0`
networking.firewall.interfaces.eth0 = {
allowedTCPPorts = [ 5335 8080 ];
allowedUDPPorts = [ 5335 ];
};
}
];
};
};
}