Do you change DNS?

Just changed mine from plusnet to Quad9 as primary and google as secondary on the router...
Seems a bit nippier loading web pages unless I'm imagining it.
 
Last edited:
I have a Plusnet supply. They have had 2 DNS outages in the last few months which I have read about in the news because the first thing I changed when I got the router was the DNS.
Never hand an issue with cloudflare
 
Just changed mine from plusnet to Quad9 as primary and google as secondary on the router...
Seems a bit nippier loading web pages unless I'm imagining it.
Most OS’s don’t see it as primary or secondary. With most, if the primary is down, DNS won’t work.
 
I have a Plusnet supply. They have had 2 DNS outages in the last few months which I have read about in the news because the first thing I changed when I got the router was the DNS.
Never hand an issue with cloudflare

I use cloudflare too but there has been an outage in the last couple of years.

The way I see it is what's the point in having a primary and secondary DNS if the you still have an outage? I'm referring to cloudflares infrastructure.
 
I use cloudflare too but there has been an outage in the last couple of years.

The way I see it is what's the point in having a primary and secondary DNS if the you still have an outage? I'm referring to cloudflares infrastructure.
I have been tempted to change the backup to another service but just not got round to it.
 
BTW, for those of us self-hosting using Unbound, dnsmasq, bind9, AGH, Pi-Hole, Technitium etc... I have played with all of these and more, and settled primarily on AGH. Recently, I stumbled across Blocky (GITHUB / DOCS), and I have to say I'm impressed. It's a single little standalone cross-platform GO binary, with a single YAML config file - and that's it. It works on Linux, the BSDs, macOS and Windows with no install, no bloat, and no hassles. You can also run it in Docker/Podman, which makes it really easy. Just a config.yml and compose.yml and you're away.

It's noteworthy for having no dependencies, no GUI, no bloat, and no 'extras'. It supports the usual features like DNSSEC, DoH and DoT (upstream and downstream), blocklists, query logging to console or database, caching, configurable prefetch etc etc. Even then, though, it only uses as much functionality as you lay out in the config file. Crucially, for me, it allows per-client blocklists! No other server/resolver does this that I'm aware of (except maybe Technitium?). For me, this means I can have it just block ads, trackers and malware (Hagezi Pro++ and Hagezi TIF) for me and my wife. For our 18 year old, it blocks that plus piracy websites (Hagezi Anti-Piracy) as he has no common sense, and for the kids it blocks all that plus pr0n/NSFW stuff (OISD NSFW). Win!

It's light and fast, using less than a couple of percent CPU usage when under load even on a SBC. RAM usage hovers around 190MB including blocklists, cache and prefetch. It's not bad at all, and optionally supports Grafana + Prometheus for stats and (again optionally, if you activate them) query logs with a nice dashboard. Worth a look! I've been using it for weeks and it is absolutely solid.

Have fun! :)

image.png

image.png


- UPDATED 2nd Feb 2024 to put Blocky, Grafana and Prometheus inside a single Docker Compose file, and have everything run automagically (you'll still need to fill out Blocky's config.yml with your LAN device names, preferred blocklists etc first!). Run the project inside the following folder structure, else it won't work. The paths in the Compose file are relative!

Required folder structure. Names prefaced with a dash (-) are folders, for clarity:

Code:
.. (root folder - can be anything, eg /home/user/docker/blocky-dns)
compose.yml
- blocky
- grafana
    - provisioning
        - datasources
            datasource.yml
- prometheus
    prometheus.yml

Docker compose.yml:
Code:
services:
  blocky:
    image: spx01/blocky
    container_name: blocky
    restart: unless-stopped
    # Optional the instance hostname for logging purpose
    hostname: blocky
    environment:
      - TZ=Europe/London # Optional to synchronize the log timestamp with host
    volumes:
      # Optional to synchronize the log timestamp with host
      - /etc/localtime:/etc/localtime:ro
      # config file
      - ./blocky/config.yml:/app/config.yml
### For DoH and DoT downstream
#      - ./fullchain.pem:/app/fullchain.pem:ro
#      - ./key.pem:/app/key.pem:ro
    network_mode: host
    cap_add:
      - NET_BIND_SERVICE
  prometheus:
    image: prom/prometheus
    container_name: prometheus
    volumes:
      - ./prometheus/:/etc/prometheus/
      - prometheus_data:/prometheus
    command:
      - '--config.file=/etc/prometheus/prometheus.yml'
      - '--storage.tsdb.path=/prometheus'
      - '--web.console.libraries=/usr/share/prometheus/console_libraries'
      - '--web.console.templates=/usr/share/prometheus/consoles'
    network_mode: host
    restart: unless-stopped
  grafana:
    image: grafana/grafana
    container_name: grafana
    depends_on:
      - prometheus
    network_mode: host
    volumes:
      - grafana_data:/var/lib/grafana
      - ./grafana/provisioning/:/etc/grafana/provisioning/
    environment:
      - GF_PANELS_DISABLE_SANITIZE_HTML=true
      - GF_INSTALL_PLUGINS=grafana-piechart-panel
    restart: unless-stopped

volumes:
    prometheus_data: {}
    grafana_data: {}

Example config.yml for Blocky:
Code:
upstreams:
  init:
    # Configure startup behavior.
    # accepted: blocking, failOnError, fast
    # default: blocking
    strategy: blocking
  groups:
    # these external DNS resolvers will be used. Blocky picks 2 random resolvers from the list for each query
    # format for resolver: [net:]host:[port][/path]. net could be empty (default, shortcut for tcp+udp), tcp+udp, tcp, udp, tcp-tls or https (DoH).
    # If port is empty, default port will be used (53 for udp and tcp, 853 for tcp-tls, 443 for https (Doh))
    # this configuration is mandatory, please define at least one external DNS resolver
    default:
    - tcp-tls:unfiltered.adguard-dns.com:853
    - tcp-tls:dns.mullvad.net:853

connectIPVersion: v4

customDNS:
  customTTL: 1h
  filterUnmappedTypes: true
### DNS rewrites so that 'dig device_name' returns the local IP address for stuff on your LAN
  rewrite:
    home:
  mapping:
    router: 10.100.0.1
    core-switch: 10.100.0.2
    my-pc: 10.100.0.10
    my-device: 10.100.0.11
    my-iphone: 10.100.0.12
    ryzen-mini: 10.100.0.15
    mbp-wifi: 10.100.0.19
    wife-iphone: 10.100.0.20
    ipad-pro: 10.100.0.21
    eldest-pc: 10.100.0.30
    eldest-iphone: 10.100.0.32
    child1-ipad: 10.100.0.40
    child1-iphone: 10.100.0.41
    child2-ipad: 10.100.0.50
    child2-iphone: 10.100.0.51
    child3-ipad: 10.100.0.60
    child3-switch: 10.100.0.61
    #... etc etc

blocking:
  blackLists:
    ads:
      - https://raw.githubusercontent.com/hagezi/dns-blocklists/main/wildcard/pro.plus.txt
     #you need the following "- |" line to add custom domains to block in a list below - see the docs for info.
      - |
        2mdn.net
        appcensus.io
        better-replay.com
        covatic.com
        covatic.io
        plausible.io
        replayapp.io
        sparrow.cloudflare.com
        testip.internet-census.org
        tm-awx.com
        dns.google
        dns.opendns.com
    malware:
      - https://raw.githubusercontent.com/hagezi/dns-blocklists/main/wildcard/tif.txt
    piracy:
      - https://raw.githubusercontent.com/hagezi/dns-blocklists/main/wildcard/anti.piracy-onlydomains.txt
    porn:
      - https://nsfw.oisd.nl/domainswild

  whiteLists:
    ads:
      - |
        captive.apple.com
        doh.dns.apple.com
        doh.dns.apple.com.v.aaplimg.com
        mask-api.icloud.com
        mask-api.fe.apple-dns.net
        mask.apple-dns.net
        mask.icloud.com
        mask-h2.icloud.com
        webstats.channel4.com
        xmrig.com

  clientGroupsBlock:
    # The default list of blocklists will be used for all clients, if no special definition for a client name exists.
    # The client names (eldest*, child1* etc) are taken from the hosts list you provided alongside their LAN IP addresses in this file.
    # Alternatively (especially if running from a VPS off-prem) Blocky will take the user ID from part of the URL you connect to for DOT or DOH.
    # This MUST be prefaced with 'id' for Blocky to recognise it, i.e. [icode]id-my-device.dns.domain.com[/icode] but not [icode]my-device.dns.domain.com[/icode].
    # Here we define which blocklists apply to which clients, eg to stop kids seeing pr0n but allow it for yourself.
    default:
      - ads
      - malware
    eldest*:
      - ads
      - malware
      - piracy
    child1*:
      - ads
      - malware
      - piracy
      - porn
    child2*:
      - ads
      - malware
      - piracy
      - porn
    child3*:
      - ads
      - malware
      - piracy
      - porn

  blockType: zeroIp
  # optional: TTL for answers to blocked domains
  # default: 6h
  blockTTL: 1m
  loading:
    # optional: list refresh period in duration format.
    # Set to a value <= 0 to disable.
    # default: 4h
    refreshPeriod: 12h
    # This specifies how many lists to load at once. Low power devices (eg RasPi) with small RAM/CPU need lower values than bigger devices.
    # I suggest 2 for RasPi devices and 8 for higher power devices, but play around.
    concurrency: 4
    # optional: Applies only to lists that are downloaded (HTTP URLs).
    downloads:
      # optional: timeout for list download (each url). Use large values for big lists or slow internet connections
      # default: 5s
      timeout: 3m
      # optional: Maximum download attempts
      # default: 3
      attempts: 5
      # optional: Time between the download attempts
      # default: 500ms
      cooldown: 10s

# optional: configuration for caching of DNS responses
caching:
  # duration how long a response must be cached (min value).
  # If <=0, use response's TTL, if >0 use this value, if TTL is smaller
  # Default: 0
  minTime: 5m
  # duration how long a response must be cached (max value).
  # If <0, do not cache responses
  # If 0, use TTL
  # If > 0, use this value, if TTL is greater
  # Default: 0
  maxTime: 30m
  # Max number of cache entries (responses) to be kept in cache (soft limit). Useful on systems with limited amount of RAM.
  # Default (0): unlimited
  maxItemsCount: 0
  # if true, will preload DNS results for often used queries (default: names queried more than 5 times in a 2-hour time window)
  # this improves the response time for often used queries, but significantly increases external traffic
  # default: false
  prefetching: true
  # prefetch track time window (in duration format)
  # default: 120
  prefetchExpires: 2h
  # name queries threshold for prefetch
  # default: 5
  prefetchThreshold: 2
  # Max number of domains to be kept in cache for prefetching (soft limit). Useful on systems with limited amount of RAM.
  # Default (0): unlimited
  prefetchMaxItemsCount: 0
  # Time how long negative results (NXDOMAIN response or empty result) are cached. A value of -1 will disable caching for negative results.
  # Default: 30m
  cacheTimeNegative: 30m

# optional: configuration of client name resolution
clientLookup:
# optional: custom mapping of client name to IP addresses. Useful if reverse DNS does not work properly or just to have custom client names.
  clients:
    router:
      - 10.100.0.1
    core-switch:
      - 10.100.0.2
    # etc etc - put your LAN device names and IPs in a list here

# optional: write query information (question, answer, client, duration etc.)
#queryLog:
  # optional one of: mysql, postgresql, csv, csv-client. If empty, log to console
#  type:
  # directory (should be mounted as volume in docker) for csv, db connection string for mysql/postgresql
#  target:
  #postgresql target: postgres://user:password@db_host_or_ip:5432/db_name
  # if > 0, deletes log files which are older than ... days
#  logRetentionDays: 1
  # optional: Max attempts to create specific query log writer, default: 3
#  creationAttempts: 1
  # optional: Time between the creation attempts, default: 2s
#  creationCooldown: 2s
  # optional: Which fields should be logged. You can choose one or more from: clientIP, clientName, responseReason, responseAnswer, question, duration. If not defined, it logs all fields
#  fields:

# optional: Mininal TLS version that the DoH and DoT server will use
minTlsServeVersion: 1.3

# if https port > 0: path to cert and key file for SSL encryption. if not set, self-signed certificate will be generated
certFile: /app/fullchain.pem
keyFile: /app/key.pem

# optional: use these DNS servers to resolve blacklist urls and upstream DNS servers. It is useful if no system DNS resolver is configured, and/or to encrypt the bootstrap queries.
bootstrapDns:
  - https://1.1.1.1/dns-query
  - https://9.9.9.9/dns-query

# optional: drop all queries with following query types. Default: empty
#filtering:
#  queryTypes:
#    - AAAA

# optional: ports configuration
ports:
  # optional: DNS listener port(s) and bind ip address(es), default 53 (UDP and TCP). Example: 53, :53, "127.0.0.1:5353,[::1]:5353"
  dns: :53
  # optional: Port(s) and bind ip address(es) for DoT (DNS-over-TLS) listener. Example: 853, 127.0.0.1:853
  tls: :853
  # optional: Port(s) and optional bind ip address(es) to serve HTTPS used for prometheus metrics, pprof, REST API, DoH... If you wish to specify a specific IP, you can do so such as 192.168.0.1:443. Example: 443, :443, 127.0.0.1:443,[::1]:443
  https: :443
  # optional: Port(s) and optional bind ip address(es) to serve HTTP used for prometheus metrics, pprof, REST API, DoH... If you wish to specify a specific IP, you can do so such as 192.168.0.1:4000. Example: 4000, :4000, 127.0.0.1:4000,[::1]:4000
  http: :4000

# optional: logging configuration
log:
  # optional: Log level (one from debug, info, warn, error). Default: info
  level: debug
  # optional: Log format (text or json). Default: text
  format: text
  # optional: log timestamps. Default: true
  timestamp: true
  # optional: obfuscate log output (replace all alphanumeric characters with *) for user sensitive data like request domains or responses to increase privacy. Default: false
  privacy: false

# Enable Prometheus
prometheus:
    enable: true
    path: /metrics

# optional: add EDE error codes to dns response
ede:
  # enabled if true, Default: false
  enable: true

# optional: configure optional Special Use Domain Names (SUDN)
specialUseDomains:
  # optional: block recomended private TLDs
  # default: true
  rfc6762-appendixG: true

# optional: configure extended client subnet (ECS) support
#ecs:
  # optional: if the request ecs option with a max sice mask the address will be used as client ip
#  useAsClient: true
  # optional: if the request contains a ecs option it will be forwarded to the upstream resolver
#  forward: true

Prometheus config file prometheus.yml:
Code:
global:
  scrape_interval:     15s
  evaluation_interval: 15s

scrape_configs:
  - job_name: 'blocky'

    static_configs:
    - targets: ['localhost:4000']

Grafana config file datasource.yml:
Code:
apiVersion: 1
deleteDatasources:
  - name: Prometheus
    orgId: 1

datasources:
- name: Prometheus
  type: prometheus
  access: proxy
  orgId: 1
  url: http://localhost:9090
  isDefault: true
  jsonData:
     graphiteVersion: "1.1"
     tlsAuth: false
     tlsAuthWithCACert: false
  version: 1
  editable: true

Once your project is running and you've waited a minute or two (for Blocky to load the filter lists, etc), you can visit http://192.168.1.20:3000 (use the appropriate LAN IP of the device!) and the Grafana dashboard login page will load. User and pass are admin:admin by default, and it will ask you to change the password on first login. From there, go to Dashboards > New dashbaord > Import. Paste in the following code:

Code:
{
  "__inputs": [
    {
      "name": "DS_PROMETHEUS",
      "label": "Prometheus",
      "description": "",
      "type": "datasource",
      "pluginId": "prometheus",
      "pluginName": "Prometheus"
    },
    {
      "name": "VAR_BLOCKY_URL",
      "type": "constant",
      "label": "blocky API URL",
      "value": "",
      "description": ""
    }
  ],
  "__elements": [],
  "__requires": [
    {
      "type": "grafana",
      "id": "grafana",
      "name": "Grafana",
      "version": "8.3.3"
    },
    {
      "type": "panel",
      "id": "heatmap",
      "name": "Heatmap",
      "version": ""
    },
    {
      "type": "panel",
      "id": "piechart",
      "name": "Pie chart",
      "version": ""
    },
    {
      "type": "datasource",
      "id": "prometheus",
      "name": "Prometheus",
      "version": "1.0.0"
    },
    {
      "type": "panel",
      "id": "stat",
      "name": "Stat",
      "version": ""
    },
    {
      "type": "panel",
      "id": "text",
      "name": "Text",
      "version": ""
    },
    {
      "type": "panel",
      "id": "timeseries",
      "name": "Time series",
      "version": ""
    }
  ],
  "annotations": {
    "list": [
      {
        "builtIn": 1,
        "datasource": "-- Grafana --",
        "enable": true,
        "hide": true,
        "iconColor": "rgba(0, 211, 255, 1)",
        "name": "Annotations & Alerts",
        "target": {
          "limit": 100,
          "matchAny": false,
          "tags": [],
          "type": "dashboard"
        },
        "type": "dashboard"
      }
    ]
  },
  "editable": true,
  "fiscalYearStartMonth": 0,
  "graphTooltip": 0,
  "id": null,
  "iteration": 1641070862290,
  "links": [
    {
      "icon": "external link",
      "tags": [],
      "title": "blocky @ GitHub",
      "tooltip": "open GitHub repo",
      "type": "link",
      "url": "https://github.com/0xERR0R/blocky"
    }
  ],
  "liveNow": false,
  "panels": [
    {
      "description": "current service state",
      "fieldConfig": {
        "defaults": {
          "mappings": [
            {
              "options": {
                "0": {
                  "text": "down"
                },
                "1": {
                  "text": "up"
                }
              },
              "type": "value"
            }
          ],
          "thresholds": {
            "mode": "absolute",
            "steps": [
              {
                "color": "#d44a3a",
                "value": null
              },
              {
                "color": "rgba(237, 129, 40, 0.89)",
                "value": 1
              },
              {
                "color": "#299c46",
                "value": 1
              }
            ]
          },
          "unit": "none"
        },
        "overrides": []
      },
      "id": 26,
      "links": [],
      "maxDataPoints": 100,
      "options": {
        "colorMode": "value",
        "graphMode": "none",
        "justifyMode": "auto",
        "orientation": "horizontal",
        "reduceOptions": {
          "calcs": [
            "lastNotNull"
          ],
          "fields": "",
          "values": false
        },
        "textMode": "auto"
      },
      "pluginVersion": "8.3.3",
      "targets": [
        {
          "datasource": {
            "type": "prometheus",
            "uid": "${DS_PROMETHEUS}"
          },
          "exemplar": false,
          "expr": "sum(up{job=~\"$job\"})",
          "format": "table",
          "instant": true,
          "interval": "",
          "legendFormat": "",
          "refId": "A"
        }
      ],
      "title": "State",
      "transparent": true,
      "type": "stat"
    },
    {
      "description": "Is blocking enabled?",
      "fieldConfig": {
        "defaults": {
          "mappings": [
            {
              "options": {
                "0": {
                  "text": "off"
                },
                "1": {
                  "text": "on"
                }
              },
              "type": "value"
            }
          ],
          "thresholds": {
            "mode": "absolute",
            "steps": [
              {
                "color": "#d44a3a",
                "value": null
              },
              {
                "color": "rgba(237, 129, 40, 0.89)",
                "value": 1
              },
              {
                "color": "#299c46",
                "value": 1
              }
            ]
          },
          "unit": "none"
        },
        "overrides": []
      },
      "gridPos": {
        "h": 3,
        "w": 6,
        "x": 6,
        "y": 0
      },
      "id": 43,
      "links": [],
      "maxDataPoints": 100,
      "options": {
        "colorMode": "value",
        "graphMode": "none",
        "justifyMode": "auto",
        "orientation": "horizontal",
        "reduceOptions": {
          "calcs": [
            "lastNotNull"
          ],
          "fields": "",
          "values": false
        },
        "textMode": "value"
      },
      "pluginVersion": "8.3.3",
      "targets": [
        {
          "datasource": {
            "type": "prometheus",
            "uid": "${DS_PROMETHEUS}"
          },
          "exemplar": false,
          "expr": "blocky_blocking_enabled",
          "format": "table",
          "instant": true,
          "interval": "",
          "legendFormat": "",
          "refId": "A"
        }
      ],
      "title": "Blocking",
      "transparent": true,
      "type": "stat"
    },
    {
      "datasource": {
        "uid": "${DS_PROMETHEUS}"
      },
      "description": "Enable Ad disable blocking",
      "gridPos": {
        "h": 5,
        "w": 12,
        "x": 12,
        "y": 0
      },
      "id": 42,
      "options": {
        "content": "<style>\n\n.blocky_btn {\n    border: none;\n  cursor: pointer; \n    padding: 12px;\n  font-size: 16px;\n  min-width: 100px\n}\n\n.blocky_greenbtn { \n  background-color: #4CAF50;\n  color: white;\n}\n\n.blocky_redbtn { \n  background-color: #AF504C;\n  color: white;\n}\n\n\n.blocky_alert {\n  font-size: 14px\n}\n</style>\n<div class=\"blocky_alert blocky_alert-warning fade in\">\n  <a href=\"#\" class=\"close\" data-dismiss=\"blocky_alert\" aria-label=\"close\" style=\"text-decoration:none\">&times;</a>Done!\n</div>\n<div>\n   <button class=\"blocky_btn blocky_greenbtn\" onclick=\"blocky_status_enable()\">On</button>\n   <button class=\"blocky_btn blocky_redbtn\" onclick=\"blocky_status_disable5m()\">Off 5m</button>\n   <button class=\"blocky_btn blocky_redbtn\" onclick=\"blocky_status_disable30m()\">Off 30m</button>\n<div>\n\n\n<script type=\"text/javascript\">\n\nfunction blocky_status_disable() {\n  blocky_status_switch(false, 0)\n}\n\nfunction blocky_status_disable5m() {\n  blocky_status_switch(false, 5*60)\n}\n\nfunction blocky_status_disable30m() {\n  blocky_status_switch(false, 30*60)\n}\n\nfunction blocky_status_enable() {\n  blocky_status_switch(true, 0)\n}\n\nfunction blocky_status_switch(enable, duration) {\n  var url = '$blocky_url';\n  op = enable ? 'enable' : 'disable?duration='+duration+\"s\"\n  $.get(url + '/api/blocking/'+op, function(data) {\n    showAlert()\n  })\n   .fail(function() {\n    alert( \"error\" );\n  })\n}\n\nvar showAlert = function() {\n\t// first show the alert\n  $('.blocky_alert').show().fadeTo(500, 1);\n  \n  // Now set a timeout to hide it\n  window.setTimeout(function() {\n    $(\".blocky_alert\").fadeTo(500, 0).slideUp(500, function() {\n      $(this).hide();\n    });\n  }, 3000);\n}\n\n// start with the alert hidden\n$('.blocky_alert').hide();\n\n</script>",
        "mode": "html"
      },
      "pluginVersion": "8.3.3",
      "title": "Blocking status",
      "transparent": true,
      "type": "text"
    },
    {
      "description": "Blocky [version](https://github.com/0xERR0R/blocky) number",
      "fieldConfig": {
        "defaults": {
          "mappings": [],
          "thresholds": {
            "mode": "absolute",
            "steps": [
              {
                "color": "green",
                "value": null
              },
              {
                "color": "red",
                "value": 80
              }
            ]
          }
        },
        "overrides": []
      },
      "gridPos": {
        "h": 3,
        "w": 6,
        "x": 0,
        "y": 3
      },
      "id": 55,
      "options": {
        "colorMode": "value",
        "graphMode": "area",
        "justifyMode": "center",
        "orientation": "auto",
        "reduceOptions": {
          "calcs": [
            "lastNotNull"
          ],
          "fields": "/^version$/",
          "values": false
        },
        "textMode": "auto"
      },
      "pluginVersion": "8.3.3",
      "repeatDirection": "v",
      "targets": [
        {
          "datasource": {
            "type": "prometheus",
            "uid": "${DS_PROMETHEUS}"
          },
          "exemplar": false,
          "expr": "blocky_build_info ",
          "format": "table",
          "instant": true,
          "interval": "",
          "legendFormat": "",
          "refId": "A"
        }
      ],
      "title": "Version",
      "transformations": [
        {
          "id": "labelsToFields",
          "options": {}
        },
        {
          "id": "merge",
          "options": {}
        }
      ],
      "transparent": true,
      "type": "stat"
    },
    {
      "datasource": {
        "uid": "${DS_PROMETHEUS}"
      },
      "description": "Average query response time for all query types",
      "fieldConfig": {
        "defaults": {
          "mappings": [
            {
              "options": {
                "match": "null",
                "result": {
                  "text": "N/A"
                }
              },
              "type": "special"
            }
          ],
          "thresholds": {
            "mode": "absolute",
            "steps": [
              {
                "color": "green",
                "value": null
              },
              {
                "color": "red",
                "value": 80
              }
            ]
          },
          "unit": "ms"
        },
        "overrides": []
      },
      "gridPos": {
        "h": 3,
        "w": 6,
        "x": 6,
        "y": 3
      },
      "id": 24,
      "links": [],
      "maxDataPoints": 100,
      "options": {
        "colorMode": "value",
        "graphMode": "area",
        "justifyMode": "auto",
        "orientation": "horizontal",
        "reduceOptions": {
          "calcs": [
            "lastNotNull"
          ],
          "fields": "",
          "values": false
        },
        "textMode": "auto"
      },
      "pluginVersion": "8.3.3",
      "targets": [
        {
          "datasource": {
            "type": "prometheus",
            "uid": "${DS_PROMETHEUS}"
          },
          "exemplar": true,
          "expr": "sum(increase(blocky_request_duration_ms_sum[$__range])) / sum(increase(blocky_request_duration_ms_count[$__range]))",
          "format": "table",
          "instant": false,
          "interval": "",
          "legendFormat": "",
          "refId": "A"
        }
      ],
      "title": "Avg response time",
      "transparent": true,
      "type": "stat"
    },
    {
      "datasource": {
        "uid": "${DS_PROMETHEUS}"
      },
      "description": "Number of blacklist entries",
      "fieldConfig": {
        "defaults": {
          "mappings": [
            {
              "options": {
                "match": "null",
                "result": {
                  "text": "N/A"
                }
              },
              "type": "special"
            }
          ],
          "thresholds": {
            "mode": "absolute",
            "steps": [
              {
                "color": "green",
                "value": null
              }
            ]
          },
          "unit": "none"
        },
        "overrides": []
      },
      "gridPos": {
        "h": 3,
        "w": 6,
        "x": 12,
        "y": 5
      },
      "id": 30,
      "links": [],
      "maxDataPoints": 100,
      "options": {
        "colorMode": "value",
        "graphMode": "area",
        "justifyMode": "auto",
        "orientation": "horizontal",
        "reduceOptions": {
          "calcs": [
            "lastNotNull"
          ],
          "fields": "",
          "values": false
        },
        "textMode": "auto"
      },
      "pluginVersion": "8.3.3",
      "targets": [
        {
          "datasource": {
            "type": "prometheus",
            "uid": "${DS_PROMETHEUS}"
          },
          "exemplar": true,
          "expr": "sum(blocky_blacklist_cache) / sum(up{job=~\"$job\"})",
          "format": "table",
          "instant": false,
          "interval": "",
          "legendFormat": "",
          "refId": "A"
        }
      ],
      "title": "Blacklist entries total",
      "transparent": true,
      "type": "stat"
    },
    {
      "datasource": {
        "uid": "${DS_PROMETHEUS}"
      },
      "fieldConfig": {
        "defaults": {
          "decimals": 2,
          "mappings": [
            {
              "options": {
                "match": "null",
                "result": {
                  "text": "N/A"
                }
              },
              "type": "special"
            }
          ],
          "thresholds": {
            "mode": "absolute",
            "steps": [
              {
                "color": "green",
                "value": null
              }
            ]
          },
          "unit": "bytes"
        },
        "overrides": []
      },
      "gridPos": {
        "h": 3,
        "w": 6,
        "x": 6,
        "y": 12
      },
      "id": 28,
      "links": [],
      "maxDataPoints": 100,
      "options": {
        "colorMode": "value",
        "graphMode": "area",
        "justifyMode": "auto",
        "orientation": "horizontal",
        "reduceOptions": {
          "calcs": [
            "lastNotNull"
          ],
          "fields": "",
          "values": false
        },
        "textMode": "auto"
      },
      "pluginVersion": "8.3.3",
      "targets": [
        {
          "datasource": {
            "type": "prometheus",
            "uid": "${DS_PROMETHEUS}"
          },
          "exemplar": true,
          "expr": "sum(go_memstats_sys_bytes{job=~\"$job\"})/sum(up{job=~\"$job\"})",
          "format": "table",
          "instant": false,
          "interval": "",
          "legendFormat": "",
          "refId": "A"
        }
      ],
      "title": "Memory allocated",
      "transparent": true,
      "type": "stat"
    },
    {
      "datasource": {
        "uid": "${DS_PROMETHEUS}"
      },
      "description": "Percentage of blocked queries",
      "fieldConfig": {
        "defaults": {
          "decimals": 2,
          "mappings": [
            {
              "options": {
                "match": "null",
                "result": {
                  "text": "N/A"
                }
              },
              "type": "special"
            }
          ],
          "max": 1,
          "min": 0,
          "thresholds": {
            "mode": "absolute",
            "steps": [
              {
                "color": "green",
                "value": null
              },
              {
                "color": "red",
                "value": 80
              }
            ]
          },
          "unit": "percentunit"
        },
        "overrides": []
      },
      "gridPos": {
        "h": 3,
        "w": 6,
        "x": 6,
        "y": 6
      },
      "id": 34,
      "links": [],
      "maxDataPoints": 100,
      "options": {
        "colorMode": "value",
        "graphMode": "area",
        "justifyMode": "auto",
        "orientation": "horizontal",
        "reduceOptions": {
          "calcs": [
            "lastNotNull"
          ],
          "fields": "",
          "values": false
        },
        "textMode": "auto"
      },
      "pluginVersion": "8.3.3",
      "targets": [
        {
          "datasource": {
            "type": "prometheus",
            "uid": "${DS_PROMETHEUS}"
          },
          "exemplar": true,
          "expr": "sum(increase(blocky_response_total{response_type=\"BLOCKED\"}[$__range])) / sum(increase(blocky_query_total[$__range])) ",
          "format": "table",
          "instant": false,
          "interval": "",
          "legendFormat": "",
          "refId": "A"
        }
      ],
      "title": "Queries blocked",
      "transparent": true,
      "type": "stat"
    },
    {
      "datasource": {
        "uid": "${DS_PROMETHEUS}"
      },
      "description": "Number of all queries. Shows the last value",
      "fieldConfig": {
        "defaults": {
          "mappings": [
            {
              "options": {
                "match": "null",
                "result": {
                  "text": "N/A"
                }
              },
              "type": "special"
            }
          ],
          "thresholds": {
            "mode": "absolute",
            "steps": [
              {
                "color": "green",
                "value": null
              }
            ]
          },
          "unit": "none"
        },
        "overrides": []
      },
      "gridPos": {
        "h": 3,
        "w": 6,
        "x": 0,
        "y": 6
      },
      "hideTimeOverride": true,
      "id": 4,
      "links": [],
      "maxDataPoints": 100,
      "options": {
        "colorMode": "value",
        "graphMode": "area",
        "justifyMode": "auto",
        "orientation": "horizontal",
        "reduceOptions": {
          "calcs": [
            "lastNotNull"
          ],
          "fields": "",
          "values": false
        },
        "textMode": "auto"
      },
      "pluginVersion": "8.3.3",
      "targets": [
        {
          "datasource": {
            "type": "prometheus",
            "uid": "${DS_PROMETHEUS}"
          },
          "exemplar": true,
          "expr": "ceil(sum(increase(blocky_query_total[$__range]))) ",
          "format": "table",
          "instant": false,
          "interval": "",
          "legendFormat": "",
          "refId": "A"
        }
      ],
      "title": "Query Count Total",
      "transparent": true,
      "type": "stat"
    },
    {
      "datasource": {
        "uid": "${DS_PROMETHEUS}"
      },
      "description": "Number of entries in the cache. Shows the last value",
      "fieldConfig": {
        "defaults": {
          "mappings": [],
          "thresholds": {
            "mode": "absolute",
            "steps": [
              {
                "color": "green",
                "value": null
              }
            ]
          }
        },
        "overrides": []
      },
      "gridPos": {
        "h": 3,
        "w": 6,
        "x": 12,
        "y": 8
      },
      "id": 45,
      "options": {
        "colorMode": "value",
        "graphMode": "area",
        "justifyMode": "auto",
        "orientation": "auto",
        "reduceOptions": {
          "calcs": [
            "last"
          ],
          "fields": "",
          "values": false
        },
        "textMode": "auto"
      },
      "pluginVersion": "8.3.3",
      "targets": [
        {
          "datasource": {
            "type": "prometheus",
            "uid": "${DS_PROMETHEUS}"
          },
          "exemplar": true,
          "expr": "sum(blocky_cache_entry_count)/ sum(up{job=~\"$job\"})",
          "format": "table",
          "instant": false,
          "interval": "",
          "legendFormat": "",
          "refId": "A"
        }
      ],
      "title": "Cache entries count",
      "transparent": true,
      "type": "stat"
    },
    {
      "datasource": {
        "uid": "${DS_PROMETHEUS}"
      },
      "description": "Cache Hit/Miss ratio. 100 % means, all queries could be answered from the cache, 0% - all queries must be resolved via external DNS",
      "fieldConfig": {
        "defaults": {
          "color": {
            "mode": "thresholds"
          },
          "mappings": [],
          "max": 1,
          "min": 0,
          "thresholds": {
            "mode": "absolute",
            "steps": [
              {
                "color": "green",
                "value": null
              }
            ]
          },
          "unit": "percentunit"
        },
        "overrides": []
      },
      "gridPos": {
        "h": 3,
        "w": 6,
        "x": 18,
        "y": 8
      },
      "id": 47,
      "options": {
        "colorMode": "value",
        "graphMode": "area",
        "justifyMode": "auto",
        "orientation": "auto",
        "reduceOptions": {
          "calcs": [
            "mean"
          ],
          "fields": "",
          "values": false
        },
        "textMode": "auto"
      },
      "pluginVersion": "8.3.3",
      "targets": [
        {
          "datasource": {
            "type": "prometheus",
            "uid": "${DS_PROMETHEUS}"
          },
          "exemplar": true,
          "expr": "sum(increase(blocky_cache_hit_count[$__range])) / (sum(increase(blocky_cache_hit_count[$__range])) + sum(increase(blocky_cache_miss_count[$__range])))",
          "format": "table",
          "instant": false,
          "interval": "",
          "legendFormat": "",
          "refId": "A"
        }
      ],
      "title": "Cache Hit/Miss ratio",
      "transparent": true,
      "type": "stat"
    },
    {
      "datasource": {
        "uid": "${DS_PROMETHEUS}"
      },
      "description": "Number of occured errors",
      "fieldConfig": {
        "defaults": {
          "decimals": 0,
          "mappings": [
            {
              "options": {
                "match": "null",
                "result": {
                  "text": "N/A"
                }
              },
              "type": "special"
            }
          ],
          "thresholds": {
            "mode": "absolute",
            "steps": [
              {
                "color": "#299c46",
                "value": null
              },
              {
                "color": "rgba(237, 129, 40, 0.89)",
                "value": 1
              },
              {
                "color": "#d44a3a"
              }
            ]
          },
          "unit": "short"
        },
        "overrides": []
      },
      "gridPos": {
        "h": 3,
        "w": 6,
        "x": 0,
        "y": 12
      },
      "id": 36,
      "links": [],
      "maxDataPoints": 100,
      "options": {
        "colorMode": "value",
        "graphMode": "area",
        "justifyMode": "auto",
        "orientation": "horizontal",
        "reduceOptions": {
          "calcs": [
            "lastNotNull"
          ],
          "fields": "",
          "values": false
        },
        "textMode": "auto"
      },
      "pluginVersion": "8.3.3",
      "targets": [
        {
          "datasource": {
            "type": "prometheus",
            "uid": "${DS_PROMETHEUS}"
          },
          "exemplar": true,
          "expr": "sum(increase(blocky_error_total[$__range]))",
          "format": "table",
          "instant": false,
          "interval": "",
          "legendFormat": "",
          "refId": "A"
        }
      ],
      "title": "Error count",
      "transparent": true,
      "type": "stat"
    },
    {
      "datasource": {
        "uid": "${DS_PROMETHEUS}"
      },
      "description": "Amount of performed DNS queries to prefetch cached queries",
      "fieldConfig": {
        "defaults": {
          "mappings": [],
          "thresholds": {
            "mode": "absolute",
            "steps": [
              {
                "color": "green",
                "value": null
              }
            ]
          }
        },
        "overrides": []
      },
      "gridPos": {
        "h": 3,
        "w": 6,
        "x": 0,
        "y": 9
      },
      "id": 53,
      "options": {
        "colorMode": "value",
        "graphMode": "area",
        "justifyMode": "auto",
        "orientation": "auto",
        "reduceOptions": {
          "calcs": [
            "lastNotNull"
          ],
          "fields": "",
          "values": false
        },
        "textMode": "auto"
      },
      "pluginVersion": "8.3.3",
      "targets": [
        {
          "datasource": {
            "type": "prometheus",
            "uid": "${DS_PROMETHEUS}"
          },
          "exemplar": true,
          "expr": "ceil(sum(increase(blocky_prefetch_count[$__range])))",
          "format": "table",
          "interval": "",
          "legendFormat": "",
          "refId": "A"
        }
      ],
      "title": "Prefetch count",
      "transparent": true,
      "type": "stat"
    },
    {
      "datasource": {
        "uid": "${DS_PROMETHEUS}"
      },
      "description": "Amount of prefetch queries per minute",
      "fieldConfig": {
        "defaults": {
          "mappings": [],
          "thresholds": {
            "mode": "absolute",
            "steps": [
              {
                "color": "green",
                "value": null
              },
              {
                "color": "red",
                "value": 80
              }
            ]
          }
        },
        "overrides": []
      },
      "gridPos": {
        "h": 3,
        "w": 6,
        "x": 12,
        "y": 11
      },
      "id": 51,
      "options": {
        "colorMode": "value",
        "graphMode": "area",
        "justifyMode": "auto",
        "orientation": "auto",
        "reduceOptions": {
          "calcs": [
            "lastNotNull"
          ],
          "fields": "",
          "values": false
        },
        "textMode": "auto"
      },
      "pluginVersion": "8.3.3",
      "targets": [
        {
          "datasource": {
            "type": "prometheus",
            "uid": "${DS_PROMETHEUS}"
          },
          "exemplar": true,
          "expr": "sum(rate(blocky_prefetch_count[5m])) * 60",
          "format": "table",
          "interval": "",
          "legendFormat": "",
          "refId": "A"
        }
      ],
      "title": "Prefetch rate per min",
      "transparent": true,
      "type": "stat"
    },
    {
      "datasource": {
        "uid": "${DS_PROMETHEUS}"
      },
      "description": "How many of cached entries were prefetched automatically",
      "fieldConfig": {
        "defaults": {
          "color": {
            "mode": "thresholds"
          },
          "mappings": [],
          "max": 1,
          "min": 0,
          "thresholds": {
            "mode": "absolute",
            "steps": [
              {
                "color": "green",
                "value": null
              }
            ]
          },
          "unit": "percentunit"
        },
        "overrides": []
      },
      "gridPos": {
        "h": 3,
        "w": 6,
        "x": 18,
        "y": 11
      },
      "id": 58,
      "options": {
        "colorMode": "value",
        "graphMode": "area",
        "justifyMode": "auto",
        "orientation": "auto",
        "reduceOptions": {
          "calcs": [
            "mean"
          ],
          "fields": "",
          "values": false
        },
        "textMode": "auto"
      },
      "pluginVersion": "8.3.3",
      "targets": [
        {
          "datasource": {
            "type": "prometheus",
            "uid": "${DS_PROMETHEUS}"
          },
          "exemplar": true,
          "expr": "sum(increase(blocky_prefetch_hit_count[$__range])) / (sum(increase(blocky_cache_hit_count[$__range])))",
          "format": "table",
          "instant": false,
          "interval": "",
          "legendFormat": "",
          "refId": "A"
        }
      ],
      "title": "Prefetch Hit ratio",
      "transparent": true,
      "type": "stat"
    },
    {
      "description": "Time since last list refresh",
      "fieldConfig": {
        "defaults": {
          "decimals": 0,
          "mappings": [],
          "thresholds": {
            "mode": "absolute",
            "steps": [
              {
                "color": "green",
                "value": null
              }
            ]
          },
          "unit": "s"
        },
        "overrides": []
      },
      "gridPos": {
        "h": 3,
        "w": 6,
        "x": 18,
        "y": 5
      },
      "id": 57,
      "options": {
        "colorMode": "value",
        "graphMode": "area",
        "justifyMode": "auto",
        "orientation": "auto",
        "reduceOptions": {
          "calcs": [
            "lastNotNull"
          ],
          "fields": "",
          "values": false
        },
        "textMode": "auto"
      },
      "pluginVersion": "8.3.3",
      "targets": [
        {
          "datasource": {
            "type": "prometheus",
            "uid": "${DS_PROMETHEUS}"
          },
          "exemplar": false,
          "expr": "sum(time() -blocky_last_list_group_refresh)/ sum(up{job=~\"$job\"})",
          "format": "table",
          "instant": true,
          "interval": "",
          "legendFormat": "",
          "refId": "A"
        }
      ],
      "title": "Last list refresh",
      "transparent": true,
      "type": "stat"
    },
    {
      "datasource": {
        "uid": "${DS_PROMETHEUS}"
      },
      "description": "Amount of unique domains in the prefetched cache",
      "fieldConfig": {
        "defaults": {
          "mappings": [],
          "thresholds": {
            "mode": "absolute",
            "steps": [
              {
                "color": "green",
                "value": null
              }
            ]
          }
        },
        "overrides": []
      },
      "gridPos": {
        "h": 3,
        "w": 6,
        "x": 6,
        "y": 9
      },
      "id": 49,
      "options": {
        "colorMode": "value",
        "graphMode": "area",
        "justifyMode": "auto",
        "orientation": "auto",
        "reduceOptions": {
          "calcs": [
            "lastNotNull"
          ],
          "fields": "",
          "values": false
        },
        "textMode": "auto"
      },
      "pluginVersion": "8.3.3",
      "targets": [
        {
          "datasource": {
            "type": "prometheus",
            "uid": "${DS_PROMETHEUS}"
          },
          "exemplar": true,
          "expr": "sum(blocky_prefetch_domain_name_cache_count)/ sum(up{job=~\"$job\"})",
          "format": "table",
          "interval": "",
          "legendFormat": "",
          "refId": "A"
        }
      ],
      "title": "Prefetch domain count",
      "transparent": true,
      "type": "stat"
    },
    {
      "fieldConfig": {
        "defaults": {
          "color": {
            "mode": "palette-classic"
          },
          "custom": {
            "axisLabel": "avg requests / min",
            "axisPlacement": "auto",
            "barAlignment": 0,
            "drawStyle": "line",
            "fillOpacity": 10,
            "gradientMode": "none",
            "hideFrom": {
              "legend": false,
              "tooltip": false,
              "viz": false
            },
            "lineInterpolation": "linear",
            "lineWidth": 1,
            "pointSize": 5,
            "scaleDistribution": {
              "type": "linear"
            },
            "showPoints": "never",
            "spanNulls": true,
            "stacking": {
              "group": "A",
              "mode": "none"
            },
            "thresholdsStyle": {
              "mode": "off"
            }
          },
          "links": [],
          "mappings": [],
          "thresholds": {
            "mode": "absolute",
            "steps": [
              {
                "color": "green",
                "value": null
              },
              {
                "color": "red",
                "value": 80
              }
            ]
          },
          "unit": "short"
        },
        "overrides": []
      },
      "gridPos": {
        "h": 7,
        "w": 24,
        "x": 0,
        "y": 15
      },
      "id": 10,
      "options": {
        "legend": {
          "calcs": [],
          "displayMode": "hidden",
          "placement": "bottom"
        },
        "tooltip": {
          "mode": "single"
        }
      },
      "pluginVersion": "8.3.3",
      "targets": [
        {
          "datasource": {
            "type": "prometheus",
            "uid": "${DS_PROMETHEUS}"
          },
          "exemplar": true,
          "expr": "sum(rate(blocky_query_total[5m])) * 60",
          "format": "time_series",
          "instant": false,
          "interval": "",
          "legendFormat": " ",
          "refId": "A"
        }
      ],
      "title": "Request rate",
      "transparent": true,
      "type": "timeseries"
    },
    {
      "fieldConfig": {
        "defaults": {
          "color": {
            "mode": "palette-classic"
          },
          "custom": {
            "axisLabel": "avg requests / min",
            "axisPlacement": "auto",
            "barAlignment": 0,
            "drawStyle": "bars",
            "fillOpacity": 100,
            "gradientMode": "none",
            "hideFrom": {
              "legend": false,
              "tooltip": false,
              "viz": false
            },
            "lineInterpolation": "linear",
            "lineWidth": 1,
            "pointSize": 5,
            "scaleDistribution": {
              "type": "linear"
            },
            "showPoints": "never",
            "spanNulls": true,
            "stacking": {
              "group": "A",
              "mode": "none"
            },
            "thresholdsStyle": {
              "mode": "off"
            }
          },
          "links": [],
          "mappings": [],
          "thresholds": {
            "mode": "absolute",
            "steps": [
              {
                "color": "green",
                "value": null
              },
              {
                "color": "red",
                "value": 80
              }
            ]
          },
          "unit": "short"
        },
        "overrides": []
      },
      "gridPos": {
        "h": 7,
        "w": 24,
        "x": 0,
        "y": 22
      },
      "id": 52,
      "options": {
        "legend": {
          "calcs": [],
          "displayMode": "list",
          "placement": "bottom"
        },
        "tooltip": {
          "mode": "single"
        }
      },
      "pluginVersion": "8.3.3",
      "targets": [
        {
          "datasource": {
            "type": "prometheus",
            "uid": "${DS_PROMETHEUS}"
          },
          "exemplar": true,
          "expr": "sum by (client) (rate(blocky_query_total[5m])) * 60",
          "format": "time_series",
          "instant": false,
          "interval": "",
          "legendFormat": " {{client}}",
          "refId": "A"
        }
      ],
      "title": "Request rate per client",
      "transparent": true,
      "type": "timeseries"
    },
    {
      "cards": {},
      "color": {
        "cardColor": "#FADE2A",
        "colorScale": "sqrt",
        "colorScheme": "interpolateYlOrBr",
        "exponent": 0.5,
        "mode": "opacity"
      },
      "dataFormat": "tsbuckets",
      "gridPos": {
        "h": 9,
        "w": 24,
        "x": 0,
        "y": 29
      },
      "heatmap": {},
      "hideZeroBuckets": false,
      "highlightCards": true,
      "id": 22,
      "legend": {
        "show": true
      },
      "reverseYBuckets": false,
      "targets": [
        {
          "datasource": {
            "type": "prometheus",
            "uid": "${DS_PROMETHEUS}"
          },
          "exemplar": true,
          "expr": "sum(increase(blocky_request_duration_ms_bucket{response_type=\"RESOLVED\"}[$__range])) by (le)",
          "format": "heatmap",
          "instant": false,
          "interval": "",
          "legendFormat": "{{le}}",
          "refId": "A"
        }
      ],
      "title": "request duration (upstream)",
      "tooltip": {
        "show": true,
        "showHistogram": false
      },
      "transparent": true,
      "type": "heatmap",
      "xAxis": {
        "show": true
      },
      "yAxis": {
        "format": "ms",
        "logBase": 1,
        "show": true
      },
      "yBucketBound": "auto"
    },
    {
      "fieldConfig": {
        "defaults": {
          "color": {
            "mode": "palette-classic"
          },
          "custom": {
            "hideFrom": {
              "legend": false,
              "tooltip": false,
              "viz": false
            }
          },
          "decimals": 0,
          "mappings": [],
          "unit": "short"
        },
        "overrides": []
      },
      "gridPos": {
        "h": 8,
        "w": 12,
        "x": 0,
        "y": 38
      },
      "id": 2,
      "links": [],
      "maxDataPoints": 3,
      "options": {
        "legend": {
          "calcs": [],
          "displayMode": "table",
          "placement": "right",
          "values": [
            "value",
            "percent"
          ]
        },
        "pieType": "donut",
        "reduceOptions": {
          "calcs": [
            "sum"
          ],
          "fields": "",
          "values": false
        },
        "tooltip": {
          "mode": "single"
        }
      },
      "pluginVersion": "6.6.2",
      "targets": [
        {
          "datasource": {
            "type": "prometheus",
            "uid": "${DS_PROMETHEUS}"
          },
          "exemplar": false,
          "expr": " sort_desc(sum by (type) (ceil(increase(blocky_query_total[$__range]))))",
          "format": "time_series",
          "instant": true,
          "interval": "",
          "legendFormat": "{{ type }}",
          "refId": "A"
        }
      ],
      "title": "Query by type",
      "transparent": true,
      "type": "piechart"
    },
    {
      "fieldConfig": {
        "defaults": {
          "color": {
            "mode": "palette-classic"
          },
          "custom": {
            "hideFrom": {
              "legend": false,
              "tooltip": false,
              "viz": false
            }
          },
          "decimals": 0,
          "mappings": [],
          "unit": "short"
        },
        "overrides": []
      },
      "gridPos": {
        "h": 8,
        "w": 12,
        "x": 12,
        "y": 38
      },
      "id": 8,
      "links": [],
      "maxDataPoints": 3,
      "options": {
        "legend": {
          "calcs": [],
          "displayMode": "table",
          "placement": "right",
          "values": [
            "value",
            "percent"
          ]
        },
        "pieType": "donut",
        "reduceOptions": {
          "calcs": [
            "lastNotNull"
          ],
          "fields": "",
          "values": false
        },
        "tooltip": {
          "mode": "single"
        }
      },
      "pluginVersion": "6.6.2",
      "targets": [
        {
          "datasource": {
            "type": "prometheus",
            "uid": "${DS_PROMETHEUS}"
          },
          "exemplar": false,
          "expr": "sort_desc(sum by (client) (ceil(increase(blocky_query_total[$__range]))))",
          "format": "time_series",
          "instant": true,
          "interval": "",
          "legendFormat": "{{ client }}",
          "refId": "A"
        }
      ],
      "title": "Query per Client",
      "transparent": true,
      "type": "piechart"
    },
    {
      "fieldConfig": {
        "defaults": {
          "color": {
            "mode": "palette-classic"
          },
          "custom": {
            "hideFrom": {
              "legend": false,
              "tooltip": false,
              "viz": false
            }
          },
          "decimals": 0,
          "mappings": [],
          "unit": "short"
        },
        "overrides": []
      },
      "gridPos": {
        "h": 8,
        "w": 12,
        "x": 0,
        "y": 46
      },
      "id": 32,
      "links": [],
      "maxDataPoints": 3,
      "options": {
        "legend": {
          "calcs": [],
          "displayMode": "table",
          "placement": "right",
          "values": [
            "value"
          ]
        },
        "pieType": "donut",
        "reduceOptions": {
          "calcs": [
            "lastNotNull"
          ],
          "fields": "",
          "values": false
        },
        "tooltip": {
          "mode": "single"
        }
      },
      "pluginVersion": "6.6.2",
      "targets": [
        {
          "datasource": {
            "type": "prometheus",
            "uid": "${DS_PROMETHEUS}"
          },
          "exemplar": false,
          "expr": "topk(1, blocky_blacklist_cache) by (group)",
          "format": "time_series",
          "instant": true,
          "interval": "",
          "legendFormat": "{{ group }}",
          "refId": "A"
        }
      ],
      "title": "Blacklist by group",
      "transparent": true,
      "type": "piechart"
    },
    {
      "fieldConfig": {
        "defaults": {
          "color": {
            "mode": "palette-classic"
          },
          "custom": {
            "hideFrom": {
              "legend": false,
              "tooltip": false,
              "viz": false
            }
          },
          "decimals": 0,
          "mappings": [],
          "unit": "short"
        },
        "overrides": []
      },
      "gridPos": {
        "h": 8,
        "w": 12,
        "x": 12,
        "y": 46
      },
      "id": 14,
      "links": [],
      "maxDataPoints": 3,
      "options": {
        "legend": {
          "calcs": [],
          "displayMode": "table",
          "placement": "right",
          "values": [
            "value",
            "percent"
          ]
        },
        "pieType": "donut",
        "reduceOptions": {
          "calcs": [
            "lastNotNull"
          ],
          "fields": "",
          "values": false
        },
        "tooltip": {
          "mode": "single"
        }
      },
      "targets": [
        {
          "datasource": {
            "type": "prometheus",
            "uid": "${DS_PROMETHEUS}"
          },
          "exemplar": false,
          "expr": " sort_desc(sum by (reason) (ceil(increase(blocky_response_total[$__range]))))",
          "format": "time_series",
          "instant": true,
          "interval": "",
          "legendFormat": "{{reason}}",
          "refId": "A"
        }
      ],
      "title": "Response Reasons",
      "transparent": true,
      "type": "piechart"
    },
    {
      "fieldConfig": {
        "defaults": {
          "color": {
            "mode": "palette-classic"
          },
          "custom": {
            "hideFrom": {
              "legend": false,
              "tooltip": false,
              "viz": false
            }
          },
          "decimals": 0,
          "mappings": [],
          "unit": "short"
        },
        "overrides": []
      },
      "gridPos": {
        "h": 8,
        "w": 12,
        "x": 0,
        "y": 54
      },
      "id": 38,
      "interval": "",
      "links": [],
      "maxDataPoints": 3,
      "options": {
        "legend": {
          "calcs": [],
          "displayMode": "table",
          "placement": "right",
          "values": [
            "value",
            "percent"
          ]
        },
        "pieType": "donut",
        "reduceOptions": {
          "calcs": [
            "sum"
          ],
          "fields": "",
          "values": false
        },
        "tooltip": {
          "mode": "single"
        }
      },
      "targets": [
        {
          "datasource": {
            "type": "prometheus",
            "uid": "${DS_PROMETHEUS}"
          },
          "exemplar": false,
          "expr": " sort_desc(sum by (response_type) (ceil(increase(blocky_response_total[$__range]))))",
          "format": "time_series",
          "instant": true,
          "interval": "",
          "legendFormat": "{{response_type}}",
          "refId": "A"
        }
      ],
      "title": "Response Type",
      "transparent": true,
      "type": "piechart"
    },
    {
      "fieldConfig": {
        "defaults": {
          "color": {
            "mode": "palette-classic"
          },
          "custom": {
            "hideFrom": {
              "legend": false,
              "tooltip": false,
              "viz": false
            }
          },
          "decimals": 0,
          "mappings": [],
          "unit": "short"
        },
        "overrides": []
      },
      "gridPos": {
        "h": 8,
        "w": 12,
        "x": 12,
        "y": 54
      },
      "id": 12,
      "links": [],
      "maxDataPoints": 3,
      "options": {
        "legend": {
          "calcs": [],
          "displayMode": "table",
          "placement": "right",
          "values": [
            "value",
            "percent"
          ]
        },
        "pieType": "donut",
        "reduceOptions": {
          "calcs": [
            "lastNotNull"
          ],
          "fields": "",
          "values": false
        },
        "tooltip": {
          "mode": "single"
        }
      },
      "targets": [
        {
          "datasource": {
            "type": "prometheus",
            "uid": "${DS_PROMETHEUS}"
          },
          "exemplar": false,
          "expr": " sort_desc(sum by (response_code) (ceil(increase(blocky_response_total[$__range]))))",
          "format": "time_series",
          "instant": true,
          "interval": "",
          "legendFormat": "{{response_code}}",
          "refId": "A"
        }
      ],
      "title": "Response status",
      "transparent": true,
      "type": "piechart"
    }
  ],
  "refresh": false,
  "schemaVersion": 34,
  "style": "dark",
  "tags": [],
  "templating": {
    "list": [
      {
        "hide": 2,
        "label": "blocky API URL",
        "name": "blocky_url",
        "query": "${VAR_BLOCKY_URL}",
        "skipUrlSync": false,
        "type": "constant",
        "current": {
          "value": "${VAR_BLOCKY_URL}",
          "text": "${VAR_BLOCKY_URL}",
          "selected": false
        },
        "options": [
          {
            "value": "${VAR_BLOCKY_URL}",
            "text": "${VAR_BLOCKY_URL}",
            "selected": false
          }
        ]
      },
      {
        "current": {},
        "datasource": {
          "type": "prometheus"
        },
        "definition": "label_values(blocky_blocking_enabled,job)",
        "hide": 0,
        "includeAll": true,
        "label": "job",
        "multi": false,
        "name": "job",
        "options": [],
        "query": {
          "qryType": 1,
          "query": "label_values(blocky_blocking_enabled,job)",
          "refId": "PrometheusVariableQueryEditor-VariableQuery"
        },
        "refresh": 1,
        "regex": "",
        "skipUrlSync": false,
        "sort": 1,
        "type": "query"
      }
    ]
  },
  "time": {
    "from": "now-3h",
    "to": "now"
  },
  "timepicker": {
    "refresh_intervals": [
      "5s",
      "10s",
      "30s",
      "1m",
      "5m",
      "15m",
      "30m",
      "1h",
      "2h",
      "1d"
    ]
  },
  "timezone": "",
  "title": "blocky",
  "uid": "JvOqE4gRk",
  "version": 1,
  "weekStart": ""
}

Set the datasource to Prometheus:9090 (should be there automatically in the drop down box), and the API url (for Blocky) to http://localhost:4000. Save the dashboard and voilà! You should be up and running, though it will take a few mins for the dash to properly populate as Blocky starts to be used. Any questions, feel free to reply here or PM me! :)
 
Last edited:
Nice @Rainmaker - what are you running it on? Does it support DNS rewrite/custom host entries?
Currently on my Radxa Rock 5 model B (8 core Big+LITTLE, 16GB RAM, 1TB Sabrent Rocket NVMe) in Docker to make auto-(re)start painless and keep the logs tidy without messing with a database. If you look at the (admittedly longish) config.yml you'll see a section for host rewrites, and you can also tell it to incorporate /etc/hosts if you like. It's not 'pretty' or trendy, but it *is* solid, dependable and highly configurable. Being able to stop the kids seeing things they shouldn't without making life harder for, *ahem*, the neighbours?... and to block them from common encrypted DNS, VPNs and proxies while being able to use them myself is the icing on the cake. It's not perfect, but it's damn close.
 
Thanks, I might look into it myself, I have a NUC Extreme running 24/7 with some VMs on it. I currently run AGH in Oracle Cloud but it doesn't do a client breakdown as it only sees my public IP.
 
Thanks, I might look into it myself, I have a NUC Extreme running 24/7 with some VMs on it. I currently run AGH in Oracle Cloud but it doesn't do a client breakdown as it only sees my public IP.
You can fix that by using named clients and/or a wildcard cert (eg with Lego or acme.sh), though you'd need to use DNS challenge. Generate a cert for *.dns.domain.xyz, dns.domain.xyz and then use named subdomains for each client relying on the wildcard. I know I can't teach you of all people to suck eggs, but don't forget to add A and AAAA records for dns.domain.xyz and a CNAME for *.dns.domain.xyz in your DNS provider!

On AdGuard (app), DNSCloak, browsers, Android devices et al. you can just type the subdomain based address in directly, but for iOS and macOS type iDevices you need to generate a profile inside AGH and install that to the device to ensure that the encrypted DNS is respected. That way you can set up your individual devices like:

Code:
tls://chris-desktop.dns.domain.xyz:853
https://chris-vmware.dns.domain.xyz/dns-query
quic://wife-ipad.dns.domain.xyz:853
# You can also do it this way without using a subdomain or needing a wildcard cert, but they are still easier!
https://dns.domain.xyz/dns-query/device-name

Just in case you weren't aware. If you set up each named client under Settings > Client settings in AGH (set the identifier to just device-name) you're away to the races, and AGH will now recognise all individual clients despite being behind one public IP and having many roadwarrior clients. It was a quiet day today (usually we average ~120K QPD) as I got some new stuff to play with and used a custom DNS server, but you can see it in action on my Oracle VPS here (live screenshot):

Screenshot-2024-01-25-at-18-29-07.png
 
Back
Top Bottom