{ config, lib, ... }: with lib; let cfg = config.modules.services.blocky; in { options.modules.services.blocky = { enable = mkEnableOption ""; realHost = mkOption { type = types.str; default = "127.0.0.1"; }; }; config = mkIf cfg.enable { services.blocky = { enable = true; settings = { ports = { # Safety: NixOS firewall should block public access to 53. # Only machines connected to the tailscale is able to reach the service. dns = 53; http = 4000; }; upstreams = { groups.default = [ "https://dns.quad9.net/dns-query" "https://one.one.one.one/dns-query" ]; timeout = "10s"; }; # For initially solving DoH/DoT Requests when no system Resolver is available bootstrapDns = { upstream = "https://dns.quad9.net/dns-query"; ips = [ "9.9.9.9" "149.112.112.112" ]; }; caching = { minTime = "0m"; maxTime = "12h"; cacheTimeNegative = "1m"; prefetching = true; }; prometheus.enable = true; queryLog.type = "console"; conditional = { fallbackUpstream = true; }; # use Tailscale MagicDNS to resolve client names clientLookup.upstream = "100.100.100.100"; blocking = { blackLists = { ads = [ "https://raw.githubusercontent.com/blocklistproject/Lists/master/ads.txt" ]; phishing = [ "https://raw.githubusercontent.com/blocklistproject/Lists/master/phishing.txt" ]; tracking = [ "https://raw.githubusercontent.com/blocklistproject/Lists/master/tracking.txt" ]; }; whiteLists = rec { # Blocky will block all domains except ones in the whitelist # IF there is no matching entry in blacklists falsePositives = [ "https://gist.githubusercontent.com/sefidel/7c7a8dbbc912bcd665d9005e2ba120e1/raw" ]; ads = falsePositives; phishing = falsePositives; tracking = falsePositives; }; clientGroupsBlock = { default = [ "ads" "phishing" "tracking" ]; }; }; }; }; services.prometheus = { enable = true; globalConfig.scrape_interval = "15s"; globalConfig.evaluation_interval = "15s"; scrapeConfigs = [{ job_name = "blocky"; static_configs = [{ targets = [ "127.0.0.1:4000" ]; }]; }]; }; services.grafana = { settings = { # Required for blocky panel panels.disable_sanitize_html = true; }; provision = { enable = true; datasources.settings = { datasources = [{ name = "Prometheus"; type = "prometheus"; access = "proxy"; orgId = 1; uid = "5Z0Y8D3GXAMDODSF"; url = "http://127.0.0.1:${toString config.services.prometheus.port}"; isDefault = true; jsonData = { graphiteVersion = "1.1"; tlsAuth = false; tlsAuthWithCACert = false; }; version = 1; editable = true; }]; }; dashboards.settings = { providers = [{ name = "My Dashboards"; options.path = "/etc/grafana-dashboards"; }]; }; }; }; environment.etc."grafana-dashboards/blocky_rev3.json" = { text = replaceStrings ["\${VAR_BLOCKY_URL}"] ["https://${cfg.realHost}"] (builtins.readFile ./grafana_blocky_rev3.json); group = "grafana"; user = "grafana"; }; }; }