Replace the Podman container and manual YAML templating with the native NixOS module for better system integration and simpler declarative configuration.
156 lines
No EOL
3.8 KiB
Nix
156 lines
No EOL
3.8 KiB
Nix
# AdGuard Home Module
|
|
# Provides: Private DNS-over-HTTPS with ClientID-based access control
|
|
#
|
|
# Usage:
|
|
# myModules.adguard = {
|
|
# enable = true;
|
|
# domain = "dns.example.com";
|
|
# clients = [
|
|
# { name = "phone"; idSecret = "adguard_client_phone"; }
|
|
# ];
|
|
# };
|
|
|
|
{
|
|
config,
|
|
lib,
|
|
pkgs,
|
|
...
|
|
}:
|
|
|
|
let
|
|
cfg = config.myModules.adguard;
|
|
in
|
|
{
|
|
options.myModules.adguard = {
|
|
enable = lib.mkEnableOption "AdGuard Home DNS server";
|
|
|
|
domain = lib.mkOption {
|
|
type = lib.types.str;
|
|
example = "dns.example.com";
|
|
description = "Public domain name for DoH endpoint";
|
|
};
|
|
|
|
port = lib.mkOption {
|
|
type = lib.types.port;
|
|
default = 3000;
|
|
description = "Internal port for AdGuard HTTP/DoH listener";
|
|
};
|
|
|
|
upstreamDoh = lib.mkOption {
|
|
type = lib.types.str;
|
|
default = "https://dns.mullvad.net/dns-query";
|
|
description = "Upstream DoH server URL";
|
|
};
|
|
|
|
bootstrapDns = lib.mkOption {
|
|
type = lib.types.listOf (lib.types.str);
|
|
default = [ "194.242.2.2" "2a07:e340::2" ];
|
|
description = "Bootstrap DNS servers for resolving DoH upstream";
|
|
};
|
|
|
|
clients = lib.mkOption {
|
|
type = lib.types.listOf (lib.types.submodule {
|
|
options = {
|
|
name = lib.mkOption {
|
|
type = lib.types.str;
|
|
description = "Friendly name for client device";
|
|
};
|
|
idSecret = lib.mkOption {
|
|
type = lib.types.str;
|
|
description = "SOPS secret name containing the ClientID";
|
|
};
|
|
};
|
|
});
|
|
default = [ ];
|
|
description = "List of clients with their ClientID secrets";
|
|
};
|
|
};
|
|
|
|
config = lib.mkIf cfg.enable {
|
|
services.adguardhome = {
|
|
enable = true;
|
|
host = "127.0.0.1";
|
|
port = cfg.port;
|
|
settings = {
|
|
dns = {
|
|
upstream_dns = [ cfg.upstreamDoh ];
|
|
bootstrap_dns = cfg.bootstrapDns;
|
|
querylog_enabled = true;
|
|
querylog_file_enabled = true;
|
|
statistics_enabled = true;
|
|
};
|
|
|
|
filtering = {
|
|
protection_enabled = true;
|
|
filtering_enabled = true;
|
|
};
|
|
|
|
safebrowsing = {
|
|
enabled = false;
|
|
};
|
|
|
|
parental = {
|
|
enabled = false;
|
|
};
|
|
|
|
safesearch = {
|
|
enabled = false;
|
|
};
|
|
|
|
log = {
|
|
file = "";
|
|
max_backups = 0;
|
|
max_size = 100;
|
|
compress = false;
|
|
local_time = false;
|
|
verbose = false;
|
|
};
|
|
} // lib.optionalAttrs (lib.length cfg.clients == 0) {
|
|
clients = {
|
|
persistent = [ ];
|
|
};
|
|
};
|
|
};
|
|
|
|
# Auto-declare SOPS secrets for each client
|
|
sops.secrets = lib.mkMerge (
|
|
map (client: {
|
|
${client.idSecret} = { };
|
|
}) cfg.clients
|
|
);
|
|
|
|
# Nginx configuration for DoH endpoint
|
|
services.nginx.virtualHosts."${cfg.domain}" = {
|
|
enableACME = true;
|
|
forceSSL = true;
|
|
|
|
# Regex location to match /dns-query and /dns-query/{clientId}
|
|
locations."~ ^/dns-query" = {
|
|
proxyPass = "http://127.0.0.1:${toString cfg.port}";
|
|
extraConfig = ''
|
|
proxy_http_version 1.1;
|
|
proxy_set_header Host $host;
|
|
proxy_set_header X-Real-IP $remote_addr;
|
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
|
proxy_set_header X-Forwarded-Proto $scheme;
|
|
|
|
# DoH uses POST with application/dns-message
|
|
proxy_pass_request_body on;
|
|
proxy_set_header Content-Type "application/dns-message";
|
|
|
|
# Buffer settings for DNS queries
|
|
proxy_buffers 8 16k;
|
|
proxy_buffer_size 32k;
|
|
'';
|
|
};
|
|
|
|
# Block all other paths including admin UI
|
|
locations."/" = {
|
|
return = "404";
|
|
};
|
|
};
|
|
|
|
# Ensure nginx user can access ACME certs
|
|
users.users.nginx.extraGroups = [ "acme" ];
|
|
};
|
|
} |