GoAway puts a DNS sinkhole and its dashboard in one Go binary
Lightweight DNS sinkhole written in Go with a modern dashboard client
At a glance
- What is it?
- GoAway is a lightweight DNS sinkhole for blocking unwanted domains at the network level, with a web dashboard, SQLite storage and a Docker image. It is still on a 0.x version line with breaking changes between releases, and it needs either higher privileges or a capability to bind port 53.
- Who is it for?
- GoAway suits a home lab or a small network where you want domain blocking on a single host with a dashboard you can open in a browser, and where a Docker image is easier to maintain than a full stack of separate services. It does not suit an environment where you cannot grant it the ability to bind port 53, and the README is explicit that the project is still in version 0.x.x and subject to major changes from version to version.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 127 days ago.
- What is it written in?
- Mainly TypeScript, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.
Editorial analysis
Domain blocking for a network rather than for one browser
GoAway answers a specific problem: unwanted domains should not reach the devices on your network at all. The README describes it as a lightweight DNS sinkhole for blocking unwanted domains at the network level, so that ads, trackers and malicious domains are blocked before they reach your devices. That is a different place to intervene from a browser extension, and the difference matters for the devices you do not control. A phone on the wifi, a smart television, a guest laptop: none of them run your extension, but all of them use your resolver. The feature list is short and specific, and it says more about the intended use than a longer one would. DNS level domain blocking, a web based admin dashboard, cross platform and Docker support, customizable blocking rules, real time statistics and a low resource footprint are the named features. The resource claim is quantified in the same document, with memory usage typically under 50MB depending on usage. The audience is therefore a self hosted operator on a home network or a small office, not an enterprise resolver deployment.
A Go backend with a TypeScript dashboard compiled into the release
The repository layout shows a two part project. The Go side lives in backend/, with cmd/ holding the command entry points, main.go at the root and go.mod defining the module as goaway on Go 1.26.2. The dashboard lives in client/, a TypeScript front end built with pnpm, since the Makefile build target runs pnpm -C client install and pnpm -C client build, and the lint target combines pnpm -C client lint with golangci-lint run ./backend/.... The Makefile also has separate dev-server and dev-website targets, the first using air to reload the Go process and the second running the pnpm dev server, so the two halves can be developed apart and assembled at release time. The dependency list shows the plumbing. DNS handling comes from codeberg.org/miekg/dns, the HTTP layer from gin with CORS and gzip support, persistence from gorm with the glebarez SQLite driver, so the blocklists and statistics live in a local database rather than in a separate server. Authentication uses golang-jwt/jwt and golang.org/x/crypto, the admin interface is served by gin, and gorilla/websocket carries the live updates behind the real time statistics. A cobra based command line interface, yaml.v3 for settings.yaml, semver for version comparison, gopsutil and the pro-bing library for system and network measurements round out the set.
Running GoAway with Docker Compose
The compose file in the repository is the shortest route to a running instance, and it is worth reading before you write your own, because the ports and capabilities are the whole story.
services:
goaway:
image: pommee/goaway:latest
container_name: goaway
restart: unless-stopped
environment:
- DNS_PORT=${DNS_PORT:-53}
- WEBSITE_PORT=${WEBSITE_PORT:-8080}
ports:
- "${DNS_PORT:-53}:${DNS_PORT:-53}/udp"
- "${DNS_PORT:-53}:${DNS_PORT:-53}/tcp"
- "${WEBSITE_PORT:-8080}:${WEBSITE_PORT:-8080}/tcp"
cap_add:
- NET_BIND_SERVICE
- NET_RAWTwo things are configurable through environment variables, DNS_PORT for the resolver port and WEBSITE_PORT for the dashboard, and both default to the standard values of 53 and 8080. The commented lines in the same file show where a custom settings.yaml and the database directory can be mounted, which you will want once your blocklists start to matter. The container image is built from an Alpine base and downloads a released binary rather than compiling the Go source inside the image.
FROM alpine:3.22
ARG GOAWAY_VERSION=""
ARG DNS_PORT=53
ARG WEBSITE_PORT=8080
ENV DNS_PORT=${DNS_PORT} WEBSITE_PORT=${WEBSITE_PORT}The image also ships an updater.sh alongside the binary, and the Makefile exposes a publish target that builds multiarchitecture images for linux/amd64, linux/arm64/v8 and linux/arm/v7 and pushes them under the pommee/goaway name with a latest tag.
Binding port 53 is the actual obstacle, not the software
The troubleshooting section of the README is short and honest, and the first entry is the one that matters. DNS servers typically require higher privileges to bind to port 53, and a permission denied error on start is the expected first failure for a new user. The compose file answers this with the cap_add list, granting NET_BIND_SERVICE and NET_RAW rather than running the container as root. Running the binary directly on a host instead means the same problem in a different shape: you either start it with the privileges to bind the port or you move the resolver to a high port and point your devices at that. Two other documented failure modes sit alongside it. If the dashboard will not load, check that port 8080 is free and not blocked by a firewall, and try http://localhost:8080 on the same machine to separate a firewall problem from a binding problem. If DNS is not working, verify that the process is running and listening on the interface you expect, confirm that the device DNS settings point to the GoAway address, and test directly with a lookup tool. The README suggests testing with nslookup or dig pointed at the GoAway address.
The README also notes that primary testing is conducted on Linux amd64, and the platform table lists Linux as full support across amd64, arm64 and 386, with macOS and Windows on both architectures marked beta. Functionality on those platforms may vary.
A 0.x project that changes shape between versions
The README carries a warning worth quoting in full, because it defines the contract: GoAway is still in version 0.x.x and is subject to major changes from version to version, and feedback is appreciated as bugs are to be expected. The release list shows how fast that line moves. v0.63.17 and v0.63.16 were both published on 2026-06-18, minutes apart, and v0.63.15 came on 2026-05-01. The repository is not archived and its last push was on 2026-06-18. Two implications follow for an operator. First, a 0.x version number means you cannot rely on compatibility between releases, so a container pinned to the latest tag can change behaviour underneath you without a major version bump to warn you. Pin the image by digest or by exact version tag rather than by latest. Second, the updater.sh script shipped in the image and the semver dependency in go.mod point to a project that expects to check and pull newer versions on its own, which is convenient for a home installation and something to turn off in an environment where you want changes to arrive only when you make them. The Makefile also wires semantic release through .releaserc.json and goreleaser through .goreleaser.yml, which is where the automatic tagging comes from.
How GoAway differs from the stack it is inspired by
The README says the project is heavily inspired by Pi-hole and thanks the people involved in that work. The difference in approach is worth being precise about, because the inspiration is not a fork. The Pi-hole approach is a full deployment of cooperating components, and each of those pieces brings its own configuration surface and its own update path. GoAway collapses the stack into one Go binary with one SQLite database and one gin served dashboard, which is why the README can claim a small memory footprint and why the compose file is a single service rather than a set of them. That also means it is not a drop in replacement for that kind of deployment, since nothing there is designed to sit in front of it. The other alternative is not running a resolver at all. Blocking in the browser, at the router, or through a DNS filter on the upstream provider leaves every device untouched and removes the port 53 problem, but it also leaves unprotected devices unprotected and gives you no per network statistics. The choice is between a single self hosted process you control and give up some of the surrounding tooling, and a filtered upstream service where you give up the control instead.
Editorial conclusion
GoAway suits a home lab or a small network where you want domain blocking on a single host with a dashboard you can open in a browser, and where a Docker image is easier to maintain than a full stack of separate services. It does not suit an environment where you cannot grant it the ability to bind port 53, and the README is explicit that the project is still in version 0.x.x and subject to major changes from version to version. Before you point your devices at it, run the Compose stack and confirm that dig @<goaway-ip> google.com resolves, then check the platform support table, since macOS and Windows are listed as beta while primary testing is on Linux amd64.
Frequently asked questions
How do I install and run GoAway?
The repository ships a Dockerfile and a docker-compose.yml, so the quickest route is the compose file, which publishes the pommee/goaway image with DNS_PORT defaulting to 53 and WEBSITE_PORT to 8080 and adds the NET_BIND_SERVICE and NET_RAW capabilities. The Makefile also has a build target that installs and builds the TypeScript client with pnpm.
Why does GoAway fail to start with a permission denied error?
DNS servers typically require higher privileges to bind to port 53, which is the first troubleshooting entry in the README. The compose file solves it by adding the NET_BIND_SERVICE and NET_RAW capabilities to the container.
Is GoAway production ready for a home network?
The README warns that GoAway is still in version 0.x.x and is subject to major changes from version to version, with bugs expected. The platform table lists Linux as fully supported and macOS and Windows as beta, with primary testing on Linux amd64.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/pommee-goaway)Was this useful?