{"id":15148321,"url":"https://github.com/shoenig/donutdns","last_synced_at":"2025-10-24T03:31:42.866Z","repository":{"id":41615364,"uuid":"413113225","full_name":"shoenig/donutdns","owner":"shoenig","description":"Block ads, trackers, and malicious sites with donutdns - simple alternative to pihole. Run as a docker container, standalone executable or core DNS plugin. Supply custom domain block/allow lists in addition to builtin lists maintained by the ad-blocking community. ","archived":true,"fork":false,"pushed_at":"2023-11-04T14:25:05.000Z","size":292,"stargazers_count":88,"open_issues_count":8,"forks_count":6,"subscribers_count":6,"default_branch":"main","last_synced_at":"2025-01-01T15:11:45.939Z","etag":null,"topics":["ads","block","dns","dns-server","pihole","pihole-blocklists","trackers","tracking"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-3-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/shoenig.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null}},"created_at":"2021-10-03T15:12:50.000Z","updated_at":"2024-12-15T20:02:27.000Z","dependencies_parsed_at":"2023-11-04T16:31:10.269Z","dependency_job_id":null,"html_url":"https://github.com/shoenig/donutdns","commit_stats":null,"previous_names":[],"tags_count":12,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/shoenig%2Fdonutdns","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/shoenig%2Fdonutdns/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/shoenig%2Fdonutdns/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/shoenig%2Fdonutdns/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/shoenig","download_url":"https://codeload.github.com/shoenig/donutdns/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":237910078,"owners_count":19385829,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ads","block","dns","dns-server","pihole","pihole-blocklists","trackers","tracking"],"created_at":"2024-09-26T13:02:50.966Z","updated_at":"2025-10-24T03:31:37.530Z","avatar_url":"https://github.com/shoenig.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# donutdns\n\n\u003cimg align=\"right\" width=\"240\" height=\"244\" src=\"https://i.imgur.com/1cEeZ3L.png\"\u003e\n\nBlock online ads by intercepting DNS queries\n\n[![License](https://img.shields.io/badge/License-BSD%203--Clause-blue.svg)](https://opensource.org/licenses/BSD-3-Clause)\n[![Run CI Tests](https://github.com/shoenig/donutdns/actions/workflows/ci.yaml/badge.svg)](https://github.com/shoenig/donutdns/actions/workflows/ci.yaml)\n\n## Project Overview\n\nThe `github.com/shoenig/donutdns` module provides a [CoreDNS](https://coredns.io) plugin\nas well as a standalone executable DNS server that can be used to block DNS queries to\ndomains used by online advertisers, trackers, scammers, and crypto miners. The project\nis meant to be a simpler alternative to the venerable [Pi-Hole](https://pi-hole.net). In\nparticular, `donutdns` is easy to run as a **non-root** [Docker container](https://hub.docker.com/r/shoenig/donutdns)\nwith little to no configuration.\n\n#### sample logs\n\n```\n[INFO] plugin/donutdns: BLOCK query (A) for www.google-analytics.com.\n[INFO] plugin/donutdns: BLOCK query (A) for www-google-analytics.l.google.com.\n[INFO] plugin/donutdns: BLOCK query (AAAA) for stats.wp.com.\n[INFO] plugin/donutdns: BLOCK query (A) for www.googletagservices.com.\n[INFO] plugin/donutdns: BLOCK query (A) for tpc.googlesyndication.com.\n[INFO] plugin/donutdns: BLOCK query (A) for c.amazon-adsystem.com.\n[INFO] plugin/donutdns: BLOCK query (AAAA) for static.ads-twitter.com.\n```\n\n## Domain Block/Allow Lists\n\nThe default set of blocked domains are retrieved from the source lists in [sources.json](sources/statics/sources.json).\nThese lists are compiled and maintained by volunteers; see their respective headers\nfor more information about terms of use and other metadata. Thank you to those who\ncontribute to these domain block lists.\n\nThe blocking of the default set of domains can be disabled by setting `DONUT_DNS_NO_DEFAULT=1`.\n\nAdditional domains can be blocked by `donutdns` by setting any of the `DONUT_DNS_BLOCK`,\n`DONUT_DNS_BLOCK_FILE`, `DONUT_DNS_BLOCK_DIR` environment variables.\n\nLikewise, domains can be explicitly allowed by setting the `DONUT_DNS_ALLOW`,\n`DONUT_DNS_ALLOW_FILE`, `DONUT_DNS_ALLOW_DIR` environment variables. The allow lists \ntake precedense over the block lists.\n\nFor nasty companies like Facebook with dynamic subdomains, `donutdns` supports blocking\ndomains by suffix matching. By setting any of the `DONUT_DNS_SUFFIX`, `DONUT_DNS_SUFFIX_FILE`,\n`DONUT_DNS_SUFFIX_DIR` any query matching the given suffix(es) will be blocked.\n\n## Getting Started\n\n`donutdns` can be used as a CoreDNS Plugin or standalone DNS Server.\n\n#### Install \n\nThe `donutdns` standalone DNS Server is written in Go.\n\nPre-compiled binaries are available for download from the [Releases](https://github.com/shoenig/donutdns/releases) page.\n\nDocker images are available from [Docker Hub](https://hub.docker.com/r/shoenig/donutdns).\n\nWith the Go toolchain, `donutdns` standalone can be compiled and installed in one step:\n\n```\ngo install github.com/shoenig/donutdns@latest\n```\n\n#### DNS Server\n\nThe `donutdns` executable uses environment variables for configuration.\n\n| Environment Variable | Description | Default |\n| -------------------- | ----------- | ------- |\n| `DONUT_DNS_PORT` | The port to listen on | `5301` |\n| `DONUT_DNS_NO_DEBUG` | Disable CoreDNS debug logging | unset |\n| `DONUT_DNS_NO_LOG` | Disable CoreDNS logging | unset |\n| `DONUT_DNS_ALLOW` | Comma separated list of domains to NOT block | unset |\n| `DONUT_DNS_ALLOW_FILE` | File with list of domains to NOT block | unset |\n| `DONUT_DNS_ALLOW_DIR` | Directory with one or more files of list of domains to NOT block | unset |\n| `DONUT_DNS_BLOCK` | Comma separated list of domains to block | unset |\n| `DONUT_DNS_BLOCK_FILE` | File with list of domains to block | unset |\n| `DONUT_DNS_BLOCK_DIR` | Directory with one or more files of list of domains to block | unset |\n| `DONUT_DNS_SUFFIX` | Comma separated list of domains to block by suffix | unset |\n| `DONUT_DNS_SUFFIX_FILE` | File with list of domains to block by suffix | unset |\n| `DONUT_DNS_SUFFIX_DIR` | Directory with one or more files of list of domains to block by suffix | unset |\n| `DONUT_DNS_NO_DEFAULTS` | Disable blocking of default domain block lists | unset |\n| `DONUT_DNS_UPSTREAM_1` | Fallback DNS Server for non-blocked queries |`1.1.1.1` |\n| `DONUT_DNS_UPSTREAM_2` | Fallback DNS Server for non-blocked queries | `1.0.0.1` |\n| `DONUT_DNS_UPSTREAM_NAME` | Fallback DNS Server TLS name | `cloudflare-dns.com` |\n\n#### CoreDNS Plugin\n\nThe `donutdns` CoreDNS plugin is configured using the `donutdns` block in a standard\n[CoreConfig](https://coredns.io/manual/toc/#configuration) configuration file.\n\nMinimal `donutdns` plugin configuration. `defaults` can be set to `true` or `false`\nto enable or disable the use of default domain block lists.\n\n```\ndonutdns {\n  defaults true\n}\n```\n\nThis configuration uses `block_file` to explicitly block a set of domains listed\nin a file on local disk.\n\n```\ndonutdns {\n  defaults false\n  block_file /etc/blocked-domains.txt\n}\n```\n\nThis configuration uses `block` and `allow` to explicitly block and allow certain\ndomains.\n\n```\ndonutdns {\n  defaults true\n  block facebook.com,www.facebook.com,m.facebook.com,fb.com\n  allow example.com\n}\n```\n\nWhen using `donutdns` as a CoreDNS plugin, the fallthrough behavior must be configured\nas desired using one or more other plugins. To recreate the same recursive behavior\nas the standalone executable, use the [`forward`](https://coredns.io/plugins/forward/) plugin.\n\n```\nforward . 1.1.1.1 1.0.0.1 {\n  tls_servername cloudflare-dns.com\n}\n```\n\n#### Custom block file\n\nThe file format for `block_file` or `DONUT_DNS_BLOCK_FILE` is simply a newline\ndelimited list of domains. Empty lines and lines beginning with `#` are always\nignored. All other lines are scanned with a regular expression to find the first\nplausible domain name in the line. [social-media.list](hack/social-media.list)\ncontains an example file for blocking facebook, instagram, and whatsapp.\n\n```\n# An example block list\nexample.com\nwww.example.com\n```\n\n## Subcommands\n\n#### check\n\nUse the `check` command to simulate whether a DNS query would be blocked or allowed.\n\nUsage: `donutdns check [-quiet] [-defaults] \u003cdomain\u003e`\n\n`-quiet` will suppress verbose debug logging output\n\n`-defaults` will activate the built-in block lists (which is slow)\n\n## Run\n\n#### as an executable\n\nWith no configuration, `donutdns` will use the built-in domain block lists\nby default.\n\n```\n$ donutdns\n```\n\nUse the environment variables described above to configure things.\n\n```\n$ DONUT_DNS_PORT=5533 DONUT_DNS_NO_DEBUG=1 donutdns\n```\n\n#### as a systemd unit\n\nThe [donutdns.service](donutdns.service) file provides an example Systemd Service Unit file for running\ndonutdns via systemd.\n\n```\n● donutdns.service - Block ads, trackers, and malicioius sites using DonutDNS.\n     Loaded: loaded (/etc/systemd/system/donutdns.service; enabled; preset: enabled)\n     Active: active (running) since Sun 2023-02-12 05:09:45 UTC; 13s ago\n   Main PID: 8117 (donutdns)\n      Tasks: 17 (limit: 18269)\n     Memory: 36.1M (max: 42.0M available: 5.8M)\n        CPU: 1.428s\n     CGroup: /system.slice/donutdns.service\n             └─8117 /opt/bin/donutdns\n```\n\n```\n# A minimal unit file, see donutdns.service for more.\n\n[Unit]\nDescription=Block ads, trackers, and malicioius sites using DonutDNS.\n\n[Service]\nType=simple\nUser=nobody\nExecStart=/opt/bin/donutdns\nEnvironment=DONUT_DNS_PORT=53\nEnvironment=DONUT_DNS_SUFFIX_DIR=/etc/blocklists.d\nMemoryMax=128M\nCPUWeight=90\n\n[Install]\nWantedBy=multi-user.target\n```\n\nTypically this file would be created at `/etc/systemd/system/donutdns.service`.\n\nConfigure systemd to run the new service.\n\n```shell\nsudo systemctl daemon-reload           # update systemd configurations\nsudo systemctl enable donutdns.service # enable donutdns service in systemd\nsudo systemctl start donutdns          # start donutdns service in systemd\nsudo systemctl status donutdns         # inspect status of donutdns service in systemd\n```\n\n#### bind to port 53\n\nWhen running as non-root user, we must set CAP_NET_BIND on the donutdns binary.\n\n```\nsudo setcap CAP_NET_BIND_service+eip /opt/bin/donutdns\n```\n\n#### as a docker container\n\n`donutdns` is available from [Docker Hub](https://hub.docker.com/repository/docker/shoenig/donutdns/general)\n\nThis will run the `donutdns` Docker container as the `nobody` user, mapping traffic from port 53. \n```\ndocker run --rm -p 53:5301 -u nobody shoenig/donutdns:v0.3.2\n```\n\n#### as a Nomad job\n\n\u003cdetails\u003e\u003csummary\u003eusing docker driver\u003c/summary\u003e\n  \n```hcl\njob \"donutdns\" {\n  datacenters = [\"dc1\"]\n\n  group \"donut\" {\n    network {\n      mode = \"bridge\"\n      port \"dns\" {\n        static       = 53\n        to           = 5301\n        host_network = \"public\"\n      }\n    }\n\n    task \"dns\" {\n      driver = \"docker\"\n      user   = \"nobody\"\n\n      resources {\n        cpu    = 120\n        memory = 64\n        disk   = 128\n      }\n\n      env {\n        DONUT_DNS_NO_DEBUG   = 1\n        DONUT_DNS_BLOCK_FILE = \"/local/blocks.txt\"\n      }\n\n      config {\n        image = \"shoenig/donutdns:v0.3.2\"\n      }\n\n      template {\n        destination = \"local/blocks.txt\"\n        change_mode = \"restart\"\n        perms       = \"644\"\n        data        = \u003c\u003cEOH\n# [example]\nexample.com\nwww.example.com\nEOH\n      }\n    }\n  }\n}\n```\n\u003c/details\u003e\n\n## Troubleshooting\n\nCertain systems (looking at you RHEL/CentOS) make running a useable DNS server particularly\ndifficult. On my homelab CentOS 9 system I had to disable ipv6 at the kernel level, disable\nSELinux, and disable firewalld. You may need to do something similar (ideally updating rules\nrather than disabling things) on your system.\n\n### ubuntu 22.04\n\nNeed to disable `systemd-resolved` first, which binds to `:53` out of the box.\n```\nsudo systemctl disable systemd-resolved\nsudo systemctl stop systemd-resolved\n```\n\n## Contributing\n\nThe `github.com/shoenig/donutdns` module is always improving with new features\nand bug fixes. For contributing such bug fixes and new features please file an issue.\n\n## License\n\nThe `github.com/shoenig/donutdns` module is open source under the [BSD-3-Clause](LICENSE) license.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fshoenig%2Fdonutdns","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fshoenig%2Fdonutdns","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fshoenig%2Fdonutdns/lists"}