nixos/crab-hole: init (#341598)

Changed files
+473
maintainers
nixos
doc
manual
modules
pkgs
by-name
cr
crab-hole
+6
maintainers/maintainer-list.nix
···
github = "niklaskorz";
githubId = 590517;
+
NiklasVousten = {
+
name = "Niklas Vousten";
+
email = "nixpkgs@vousten.dev";
+
github = "NiklasVousten";
+
githubId = 24965952;
+
};
nikstur = {
email = "nikstur@outlook.com";
name = "nikstur";
+39
nixos/doc/manual/redirects.json
···
"book-nixos-manual": [
"index.html#book-nixos-manual"
],
+
"module-services-crab-hole": [
+
"index.html#module-services-crab-hole"
+
],
+
"module-services-crab-hole-api": [
+
"index.html#module-services-crab-hole-api"
+
],
+
"module-services-crab-hole-configuration": [
+
"index.html#module-services-crab-hole-configuration"
+
],
+
"module-services-crab-hole-dnssec": [
+
"index.html#module-services-crab-hole-dnssec"
+
],
+
"module-services-crab-hole-downstream": [
+
"index.html#module-services-crab-hole-downstream"
+
],
+
"module-services-crab-hole-https": [
+
"index.html#module-services-crab-hole-https"
+
],
+
"module-services-crab-hole-invalid-config": [
+
"index.html#module-services-crab-hole-invalid-config"
+
],
+
"module-services-crab-hole-permission-error": [
+
"index.html#module-services-crab-hole-permission-error"
+
],
+
"module-services-crab-hole-quic": [
+
"index.html#module-services-crab-hole-quic"
+
],
+
"module-services-crab-hole-tls": [
+
"index.html#module-services-crab-hole-tls"
+
],
+
"module-services-crab-hole-troubleshooting": [
+
"index.html#module-services-crab-hole-troubleshooting"
+
],
+
"module-services-crab-hole-udp": [
+
"index.html#module-services-crab-hole-udp"
+
],
+
"module-services-crab-hole-upstream-options": [
+
"index.html#module-services-crab-hole-upstream-options"
+
],
"preface": [
"index.html#preface"
],
+2
nixos/doc/manual/release-notes/rl-2505.section.md
···
- [Traccar](https://www.traccar.org/), a modern GPS Tracking Platform. Available as [services.traccar](#opt-services.traccar.enable).
+
- [crab-hole](https://github.com/LuckyTurtleDev/crab-hole), a cross platform Pi-hole clone written in Rust using hickory-dns/trust-dns. Available as [services.crab-hole](#opt-services.crab-hole.enable).
+
- [Amazon CloudWatch Agent](https://github.com/aws/amazon-cloudwatch-agent), the official telemetry collector for AWS CloudWatch and AWS X-Ray. Available as [services.amazon-cloudwatch-agent](options.html#opt-services.amazon-cloudwatch-agent.enable).
- [agorakit](https://github.com/agorakit/agorakit), an organization tool for citizens' collectives. Available with [services.agorakit](options.html#opt-services.agorakit.enable).
+1
nixos/modules/module-list.nix
···
./services/networking/coredns.nix
./services/networking/corerad.nix
./services/networking/coturn.nix
+
./services/networking/crab-hole.nix
./services/networking/create_ap.nix
./services/networking/croc.nix
./services/networking/dae.nix
+215
nixos/modules/services/networking/crab-hole.md
···
+
# 🦀 crab-hole {#module-services-crab-hole}
+
+
Crab-hole is a cross platform Pi-hole clone written in Rust using [hickory-dns/trust-dns](https://github.com/hickory-dns/hickory-dns).
+
It can be used as a network wide ad and spy blocker or run on your local PC.
+
+
For a secure and private communication, crab-hole has builtin support for DoH(HTTPS), DoQ(QUIC) and DoT(TLS) for down- and upstreams and DNSSEC for upstreams.
+
It also comes with privacy friendly default logging settings.
+
+
## Configuration {#module-services-crab-hole-configuration}
+
As an example config file using Cloudflare as DoT upstream, you can use this [crab-hole.toml](https://github.com/LuckyTurtleDev/crab-hole/blob/main/example-config.toml)
+
+
+
The following is a basic nix config using UDP as a downstream and Cloudflare as upstream.
+
+
```nix
+
{
+
services.crab-hole = {
+
enable = true;
+
+
settings = {
+
blocklist = {
+
include_subdomains = true;
+
lists = [
+
"https://raw.githubusercontent.com/StevenBlack/hosts/master/alternates/fakenews-gambling-porn/hosts"
+
"https://s3.amazonaws.com/lists.disconnect.me/simple_tracking.txt"
+
];
+
};
+
+
downstream = [
+
{
+
protocol = "udp";
+
listen = "127.0.0.1";
+
port = 53;
+
}
+
{
+
protocol = "udp";
+
listen = "::1";
+
port = 53;
+
}
+
];
+
+
upstream = {
+
name_servers = [
+
{
+
socket_addr = "1.1.1.1:853";
+
protocol = "tls";
+
tls_dns_name = "1dot1dot1dot1.cloudflare-dns.com";
+
trust_nx_responses = false;
+
}
+
{
+
socket_addr = "[2606:4700:4700::1111]:853";
+
protocol = "tls";
+
tls_dns_name = "1dot1dot1dot1.cloudflare-dns.com";
+
trust_nx_responses = false;
+
}
+
];
+
};
+
};
+
};
+
}
+
```
+
+
To test your setup, just query the DNS server with any domain like `example.com`.
+
To test if a domain gets blocked, just choose one of the domains from the blocklist.
+
If the server does not return an IP, this worked correctly.
+
+
### Downstream options {#module-services-crab-hole-downstream}
+
There are multiple protocols which are supported for the downstream:
+
UDP, TLS, HTTPS and QUIC.
+
Below you can find a brief overview over the various protocol options together with an example for each protocol.
+
+
#### UDP {#module-services-crab-hole-udp}
+
UDP is the simplest downstream, but it is not encrypted.
+
If you want encryption, you need to use another protocol.
+
***Note:** This also opens a TCP port*
+
```nix
+
{
+
services.crab-hole.settings.downstream = [
+
{
+
protocol = "udp";
+
listen = "localhost";
+
port = 53;
+
}
+
];
+
}
+
```
+
+
#### TLS {#module-services-crab-hole-tls}
+
TLS is a simple encrypted options to serve DNS.
+
It comes with similar settings to UDP,
+
but you additionally need a valid TLS certificate and its private key.
+
The later are specified via a path to the files.
+
A valid TLS certificate and private key can be obtained using services like ACME.
+
Make sure the crab-hole service user has access to these files.
+
Additionally you can set an optional timeout value.
+
```nix
+
{
+
services.crab-hole.settings.downstream = [
+
{
+
protocol = "tls";
+
listen = "[::]";
+
port = 853;
+
certificate = ./dns.example.com.crt;
+
key = "/dns.example.com.key";
+
# optional (default = 3000)
+
timeout_ms = 3000
+
}
+
];
+
}
+
```
+
+
#### HTTPS {#module-services-crab-hole-https}
+
HTTPS has similar settings to TLS, with the only difference being the additional `dns_hostname` option.
+
This protocol might need a reverse proxy if other HTTPS services are to share the same port.
+
Make sure the service has permissions to access the certificate and key.
+
+
***Note:** this config is untested*
+
```nix
+
{
+
services.crab-hole.settings.downstream = [
+
{
+
protocol = "https";
+
listen = "[::]";
+
port = 443;
+
certificate = ./dns.example.com.crt;
+
key = "/dns.example.com.key";
+
# optional
+
dns_hostname = "dns.example.com";
+
# optional (default = 3000)
+
timeout_ms = 3000;
+
}
+
];
+
}
+
```
+
+
#### QUIC {#module-services-crab-hole-quic}
+
QUIC has identical settings to the HTTPS protocol.
+
Since by default it doesn't run on the standard HTTPS port, you shouldn't need a reverse proxy.
+
Make sure the service has permissions to access the certificate and key.
+
```nix
+
{
+
services.crab-hole.settings.downstream = [
+
{
+
protocol = "quic";
+
listen = "127.0.0.1";
+
port = 853;
+
certificate = ./dns.example.com.crt;
+
key = "/dns.example.com.key";
+
# optional
+
dns_hostname = "dns.example.com";
+
# optional (default = 3000)
+
timeout_ms = 3000;
+
}
+
];
+
}
+
```
+
+
### Upstream options {#module-services-crab-hole-upstream-options}
+
You can set additional options of the underlying DNS server. A full list of all the options can be found in the [hickory-dns documentation](https://docs.rs/trust-dns-resolver/0.23.0/trust_dns_resolver/config/struct.ResolverOpts.html).
+
+
This can look like the following example.
+
```nix
+
{
+
services.crab-hole.settings.upstream.options = {
+
validate = false;
+
};
+
}
+
```
+
+
#### DNSSEC Issues {#module-services-crab-hole-dnssec}
+
Due to an upstream issue of [hickory-dns](https://github.com/hickory-dns/hickory-dns/issues/2429), sites without DNSSEC will not be resolved if `validate = true`.
+
Only DNSSEC capable sites will be resolved with this setting.
+
To prevent this, set `validate = false` or omit the `[upstream.options]`.
+
+
### API {#module-services-crab-hole-api}
+
The API allows a user to fetch statistic and information about the crab-hole instance.
+
Basic information is availablee for everyone, while more detailed information is secured by a key, which will be set with the `admin_key` option.
+
+
```nix
+
{
+
services.crab-hole.settings.api = {
+
listen = "127.0.0.1";
+
port = 8080;
+
# optional (default = false)
+
show_doc = true; # OpenAPI doc loads content from third party websites
+
# optional
+
admin_key = "1234";
+
};
+
}
+
+
```
+
+
The documentation can be enabled seperately for the instance with `show_doc`.
+
This will then create an additional webserver, which hosts the API documentation.
+
An additional resource is in work in the [crab-hole repository](https://github.com/LuckyTurtleDev/crab-hole).
+
+
## Troubleshooting {#module-services-crab-hole-troubleshooting}
+
You can check for errors using `systemctl status crab-hole` or `journalctl -xeu crab-hole.service`.
+
+
### Invalid config {#module-services-crab-hole-invalid-config}
+
Some options of the service are in freeform and not type checked.
+
This can lead to a config which is not valid or cannot be parsed by crab-hole.
+
The error message will tell you what config value could not be parsed.
+
For more information check the [example config](https://github.com/LuckyTurtleDev/crab-hole/blob/main/example-config.toml).
+
+
### Permission Error {#module-services-crab-hole-permission-error}
+
It can happen that the created certificates for TLS, HTTPS or QUIC are owned by another user or group.
+
For ACME for example this would be `acme:acme`.
+
To give the crab-hole service access to these files, the group which owns the certificate can be added as a supplementary group to the service.
+
For ACME for example:
+
```nix
+
{
+
services.crab-hole.supplementaryGroups = [ "acme" ];
+
}
+
```
+180
nixos/modules/services/networking/crab-hole.nix
···
+
{
+
config,
+
lib,
+
pkgs,
+
...
+
}:
+
let
+
cfg = config.services.crab-hole;
+
+
settingsFormat = pkgs.formats.toml { };
+
+
checkConfig =
+
file:
+
pkgs.runCommand "check-config"
+
{
+
nativeBuildInputs = [
+
cfg.package
+
pkgs.cacert
+
pkgs.dig
+
];
+
}
+
''
+
ln -s ${file} $out
+
+
ln -s ${file} ./config.toml
+
export CRAB_HOLE_DIR=$(pwd)
+
+
${lib.getExe cfg.package} validate-config
+
'';
+
in
+
{
+
options = {
+
services.crab-hole = {
+
enable = lib.mkEnableOption "Crab-hole Service";
+
+
package = lib.mkPackageOption pkgs "crab-hole" { };
+
+
supplementaryGroups = lib.mkOption {
+
type = lib.types.listOf lib.types.str;
+
default = [ ];
+
example = [ "acme" ];
+
description = "Adds additional groups to the crab-hole service. Can be useful to prevent permission issues.";
+
};
+
+
settings = lib.mkOption {
+
description = "Crab-holes config. See big example https://github.com/LuckyTurtleDev/crab-hole/blob/main/example-config.toml";
+
+
example = {
+
downstream = [
+
{
+
listen = "localhost";
+
port = 8080;
+
protocol = "udp";
+
}
+
{
+
certificate = "dns.example.com.crt";
+
dns_hostname = "dns.example.com";
+
key = "dns.example.com.key";
+
listen = "[::]";
+
port = 8055;
+
protocol = "https";
+
timeout_ms = 3000;
+
}
+
];
+
api = {
+
admin_key = "1234";
+
listen = "127.0.0.1";
+
port = 8080;
+
show_doc = true;
+
};
+
blocklist = {
+
allow_list = [
+
"file:///allowed.txt"
+
];
+
include_subdomains = true;
+
lists = [
+
"https://raw.githubusercontent.com/StevenBlack/hosts/master/alternates/fakenews-gambling-porn/hosts"
+
"https://s3.amazonaws.com/lists.disconnect.me/simple_tracking.txt"
+
"file:///blocked.txt"
+
];
+
};
+
upstream = {
+
name_servers = [
+
{
+
protocol = "tls";
+
socket_addr = "[2606:4700:4700::1111]:853";
+
tls_dns_name = "1dot1dot1dot1.cloudflare-dns.com";
+
trust_nx_responses = false;
+
}
+
{
+
protocol = "tls";
+
socket_addr = "1.1.1.1:853";
+
tls_dns_name = "1dot1dot1dot1.cloudflare-dns.com";
+
trust_nx_responses = false;
+
}
+
];
+
options = {
+
validate = false;
+
};
+
};
+
};
+
+
type = lib.types.submodule {
+
freeformType = settingsFormat.type;
+
options = {
+
blocklist =
+
let
+
listOption =
+
name:
+
lib.mkOption {
+
type = lib.types.listOf (lib.types.either lib.types.str lib.types.path);
+
default = [ ];
+
description = "List of ${name}. If files are added via url, make sure the service has access to them!";
+
apply = map (v: if builtins.isPath v then "file://${v}" else v);
+
};
+
in
+
{
+
include_subdomains = lib.mkEnableOption "Include subdomains";
+
lists = listOption "blocklists";
+
allow_list = listOption "allowlists";
+
};
+
};
+
};
+
};
+
+
configFile = lib.mkOption {
+
type = lib.types.path;
+
description = ''
+
The config file of crab-hole.
+
+
If files are added via url, make sure the service has access to them.
+
Setting this option will override any configuration applied by the settings option.
+
'';
+
};
+
};
+
};
+
+
config = lib.mkIf cfg.enable {
+
# Warning due to DNSSec issue in crab-hole
+
warnings = lib.optional (cfg.settings.upstream.options.validate or false) ''
+
Validate options will ONLY allow DNSSec domains. See https://github.com/LuckyTurtleDev/crab-hole/issues/29
+
'';
+
+
services.crab-hole.configFile = lib.mkDefault (
+
checkConfig (settingsFormat.generate "crab-hole.toml" cfg.settings)
+
);
+
environment.etc."crab-hole.toml".source = cfg.configFile;
+
+
systemd.services.crab-hole = {
+
wantedBy = [ "multi-user.target" ];
+
after = [ "network-online.target" ];
+
wants = [ "network-online.target" ];
+
description = "Crab-hole dns server";
+
environment.HOME = "/var/lib/crab-hole";
+
restartTriggers = [ cfg.configFile ];
+
serviceConfig = {
+
Type = "simple";
+
DynamicUser = true;
+
SupplementaryGroups = cfg.supplementaryGroups;
+
+
StateDirectory = "crab-hole";
+
WorkingDirectory = "/var/lib/crab-hole";
+
+
ExecStart = lib.getExe cfg.package;
+
+
AmbientCapabilities = "CAP_NET_BIND_SERVICE";
+
CapabilityBoundingSet = "CAP_NET_BIND_SERVICE";
+
+
Restart = "on-failure";
+
RestartSec = 1;
+
};
+
};
+
};
+
+
meta.maintainers = [
+
lib.maintainers.NiklasVousten
+
];
+
# Readme from upstream
+
meta.doc = ./crab-hole.md;
+
}
+30
pkgs/by-name/cr/crab-hole/package.nix
···
+
{
+
lib,
+
fetchFromGitHub,
+
rustPlatform,
+
}:
+
+
rustPlatform.buildRustPackage rec {
+
pname = "crab-hole";
+
version = "0.1.10";
+
+
src = fetchFromGitHub {
+
owner = "LuckyTurtleDev";
+
repo = "crab-hole";
+
rev = "refs/tags/v${version}";
+
hash = "sha256-OyZ+GkWU+OMnS6X7yk7H1e1MzfQQQkhOkoxUmWn6k7I=";
+
};
+
+
cargoHash = "sha256-NeVCGN2ZIyrufa3geO8bbwV7ncenguftnr5SClRZLi8=";
+
+
meta = {
+
description = "Pi-Hole clone written in Rust using Hickory DNS";
+
homepage = "https://github.com/LuckyTurtleDev/crab-hole";
+
license = lib.licenses.agpl3Plus;
+
mainProgram = "crab-hole";
+
maintainers = [
+
lib.maintainers.NiklasVousten
+
];
+
platforms = lib.platforms.linux;
+
};
+
}