From a18ce54dc4af8333080e8af123a339595411a098 Mon Sep 17 00:00:00 2001 From: Nikolaos Karaolidis Date: Tue, 8 Jul 2025 13:29:40 +0100 Subject: [PATCH] Add adguardhome Signed-off-by: Nikolaos Karaolidis --- hosts/jupiter/configs/tv/default.nix | 148 ++++++++++++++++++ hosts/jupiter/users/nick/default.nix | 1 + .../configs/console/podman/media/default.nix | 2 +- packages/default.nix | 1 + packages/docker/adguardhome/default.nix | 36 +++++ packages/docker/adguardhome/entrypoint.sh | 34 ++++ 6 files changed, 221 insertions(+), 1 deletion(-) create mode 100644 hosts/jupiter/configs/tv/default.nix create mode 100644 packages/docker/adguardhome/default.nix create mode 100644 packages/docker/adguardhome/entrypoint.sh diff --git a/hosts/jupiter/configs/tv/default.nix b/hosts/jupiter/configs/tv/default.nix new file mode 100644 index 0000000..ccb168f --- /dev/null +++ b/hosts/jupiter/configs/tv/default.nix @@ -0,0 +1,148 @@ +{ + config, + inputs, + pkgs, + system, + ... +}: +let + selfPkgs = inputs.self.packages.${system}; + inherit (config.virtualisation.quadlet) volumes; + inboundInterface = "wlo1"; + inboundGateway = "192.168.1.1"; + inboundRangeStart = "192.168.1.2"; + inboundRangeStop = "192.168.1.254"; + inboundRangeMask = "255.255.255.0"; + inboundRangePrefix = 24; + outboundInterface = "enp2s0"; +in +{ + boot.kernel.sysctl."net.ipv4.ip_forward" = 1; + + networking = { + firewall = { + interfaces.${inboundInterface} = { + allowedUDPPorts = [ + 53 + 67 + ]; + + allowedTCPPorts = [ + 53 + 8080 + ]; + }; + + extraCommands = '' + iptables -t nat -A POSTROUTING -o ${outboundInterface} -j MASQUERADE + iptables -A FORWARD -i ${outboundInterface} -o ${inboundInterface} -m state --state RELATED,ESTABLISHED -j ACCEPT + iptables -A FORWARD -i ${inboundInterface} -o ${outboundInterface} -j ACCEPT + iptables -t nat -A PREROUTING -i ${inboundInterface} -p udp --dport 53 -j DNAT --to-destination ${inboundGateway}:53 + ''; + + extraStopCommands = '' + iptables -t nat -D POSTROUTING -o ${outboundInterface} -j MASQUERADE || true + iptables -D FORWARD -i ${outboundInterface} -o ${inboundInterface} -m state --state RELATED,ESTABLISHED -j ACCEPT || true + iptables -D FORWARD -i ${inboundInterface} -o ${outboundInterface} -j ACCEPT || true + iptables -t nat -D PREROUTING -i ${inboundInterface} -p udp --dport 53 -j DNAT --to-destination ${inboundGateway}:53 || true + ''; + }; + + networkmanager.unmanaged = [ "interface-name:${inboundInterface}" ]; + + interfaces.${inboundInterface}.ipv4 = { + addresses = [ + { + address = inboundGateway; + prefixLength = inboundRangePrefix; + } + ]; + }; + }; + + sops = { + secrets = { + "tv/network/password".sopsFile = ../../secrets/secrets.yaml; + "tv/adguard/admin".sopsFile = ../../secrets/secrets.yaml; + }; + + templates.adguard-env.content = '' + ADGUARD_ADMIN_PASSWORD=${config.sops.placeholder."tv/adguard/admin"} + ''; + }; + + services.hostapd = { + enable = true; + radios.${inboundInterface} = { + band = "2g"; + channel = 2; + countryCode = "GB"; + + networks.${inboundInterface} = { + ssid = "jupiter-tv"; + authentication.saePasswords = [ + { passwordFile = config.sops.secrets."tv/network/password".path; } + ]; + }; + }; + }; + + virtualisation.quadlet = { + volumes.tv-adguard = { }; + + containers.tv-adguard = { + containerConfig = { + image = "docker-archive:${selfPkgs.docker-adguardhome}"; + volumes = + let + config = (pkgs.formats.yaml { }).generate "config.yaml.default" { + http.address = "${inboundGateway}:8080"; + + dns = { + bind_hosts = [ inboundGateway ]; + port = 53; + ratelimit = 0; + }; + + dhcp = { + enabled = true; + interface_name = inboundInterface; + local_domain_name = "local"; + + dhcpv4 = { + gateway_ip = inboundGateway; + subnet_mask = inboundRangeMask; + range_start = inboundRangeStart; + range_end = inboundRangeStop; + }; + }; + + filters = [ ]; + whitelist_filters = [ ]; + user_rules = [ + "||*^" + "@@||clients3.google.com^" + "@@||clients.l.google.com^" + "@@||connectivitycheck.gstatic.com^" + "@@||connectivitycheck.android.com^" + ]; + + schema_version = 29; + }; + in + [ + "${config}:/etc/adguard/config.yaml.default" + "${volumes.tv-adguard.ref}:/var/lib/adguard" + ]; + networks = [ "host" ]; + addCapabilities = [ + "NET_RAW" + "NET_ADMIN" + ]; + environmentFiles = [ config.sops.templates.adguard-env.path ]; + }; + + unitConfig.After = [ "sops-nix.service" ]; + }; + }; +} diff --git a/hosts/jupiter/users/nick/default.nix b/hosts/jupiter/users/nick/default.nix index 3426f1c..d59a13e 100644 --- a/hosts/jupiter/users/nick/default.nix +++ b/hosts/jupiter/users/nick/default.nix @@ -9,6 +9,7 @@ in imports = [ (import ../../../common/configs/user { inherit user home; }) + (import ../../../common/configs/user/console/android { inherit user home; }) (import ../../../common/configs/user/console/btop { inherit user home; }) (import ../../../common/configs/user/console/fastfetch { inherit user home; }) (import ../../../common/configs/user/console/git { inherit user home; }) diff --git a/hosts/jupiter/users/storm/configs/console/podman/media/default.nix b/hosts/jupiter/users/storm/configs/console/podman/media/default.nix index 0fe8e9c..09b33c3 100644 --- a/hosts/jupiter/users/storm/configs/console/podman/media/default.nix +++ b/hosts/jupiter/users/storm/configs/console/podman/media/default.nix @@ -12,7 +12,7 @@ let selfPkgs = inputs.self.packages.${system}; hmConfig = config.home-manager.users.${user}; - inherit (hmConfig.virtualisation.quadlet) containers volumes networks; + inherit (hmConfig.virtualisation.quadlet) volumes networks; jellyfinAutheliaClientId = "59TRpNutxEeRRCAZbDsK7rsnrA5NC69HAdAO45CEfc740xl4hgIacDy2u03oiFc89Exb67udBQvmfwxgeAQtJPiNAJxA5OzGmdQf"; in diff --git a/packages/default.nix b/packages/default.nix index a279bd1..76c9687 100644 --- a/packages/default.nix +++ b/packages/default.nix @@ -9,6 +9,7 @@ darktable-hald-clut = import ./darktable/hald-clut { inherit pkgs; }; darktable-lua-scripts = import ./darktable/lua-scripts { inherit pkgs; }; + docker-adguardhome = import ./docker/adguardhome { inherit pkgs; }; docker-authelia = import ./docker/authelia { inherit pkgs; }; docker-base = import ./docker/base { inherit pkgs; }; docker-flaresolverr = import ./docker/flaresolverr { inherit pkgs; }; diff --git a/packages/docker/adguardhome/default.nix b/packages/docker/adguardhome/default.nix new file mode 100644 index 0000000..fd35cb3 --- /dev/null +++ b/packages/docker/adguardhome/default.nix @@ -0,0 +1,36 @@ +{ pkgs, ... }: +let + entrypoint = pkgs.writeTextFile { + name = "entrypoint"; + executable = true; + destination = "/bin/entrypoint"; + text = builtins.readFile ./entrypoint.sh; + }; +in +pkgs.dockerTools.buildImage { + name = "adguardhome"; + fromImage = import ../base { inherit pkgs; }; + + copyToRoot = pkgs.buildEnv { + name = "root"; + paths = with pkgs; [ + entrypoint + adguardhome + apacheHttpd + yq-go + ]; + pathsToLink = [ "/bin" ]; + }; + + config = { + Entrypoint = [ "entrypoint" ]; + ExposedPorts = { + "53/tcp" = { }; + "53/udp" = { }; + "80/tcp" = { }; + }; + Volumes = { + "/var/lib/adguard" = { }; + }; + }; +} diff --git a/packages/docker/adguardhome/entrypoint.sh b/packages/docker/adguardhome/entrypoint.sh new file mode 100644 index 0000000..23a93ff --- /dev/null +++ b/packages/docker/adguardhome/entrypoint.sh @@ -0,0 +1,34 @@ +#!/usr/bin/env sh + +set -o errexit +set -o nounset + +ADGUARD_ADMIN_USERNAME=${ADGUARD_ADMIN_USERNAME:-admin} + +mkdir -p /etc/adguard +touch /etc/adguard/config.yaml + +if [ -f /etc/adguard/config.yaml.default ]; then + cp /etc/adguard/config.yaml.default /etc/adguard/config.yaml +fi + +password="$(htpasswd -B -C 10 -n -b "$ADGUARD_ADMIN_USERNAME" "$ADGUARD_ADMIN_PASSWORD" | cut -d ':' -f2-)" +yq eval -i ".users = [{\"name\": \"$ADGUARD_ADMIN_USERNAME\", \"password\": \"$password\"}]" /etc/adguard/config.yaml + +LOG_PIPE="$(mktemp -u)" +mkfifo "$LOG_PIPE" + +( + while IFS= read -r line; do + if echo "$line" | grep -qEi "\[(WARN|ERROR|FATAL)\]"; then + echo "$line" >&2 + else + echo "$line" + fi + done < "$LOG_PIPE" +) & + +exec AdGuardHome \ + -c /etc/adguard/config.yaml \ + -w /var/lib/adguard \ + "$@" > "$LOG_PIPE" 2>&1