Sagittarius
A fast, self-hosted DNS sinkhole in a single Rust binary.
Sagittarius is an open-source, network-wide DNS sinkhole — it blocks ads, trackers, and malicious domains for every device on your network, in the spirit of Pi-hole and AdGuard Home. Everything — the DNS engine, storage, and web admin interface — ships in one self-contained binary.
It is named after Sagittarius A*, the supermassive black hole at the centre of the Milky Way: a fitting namesake for something whose job is to make unwanted traffic disappear.
⚠️ Early development. Sagittarius is pre-1.0 and not yet ready for general use. The design is described in
SPEC.md; interfaces and features are still changing.
Goals
- Single binary — no external services, interpreters, or web server to set up.
- Fast — a hand-written DNS codec and a
tokio/towerrequest pipeline keep the hot path lean. - Light — runs comfortably on small home servers, routers, and SBCs.
- Operable — a clean, authenticated web UI for configuration, live query inspection, and statistics; icon-enhanced and responsive, with a collapsing navigation drawer on mobile.
Planned features (v0.1)
- 🛡️ DNS blocking via subscribable blocklists (hosts / domain-list formats) plus manual allow/deny lists. Exact-domain matching in v0.1. Per-list effectiveness shows how many blocks each source contributed (last 24h) and its share of the total, so you can see which lists are pulling their weight.
- ⏸️ Pause blocking temporarily — snooze all blocking for 5 min / 30 min / 1 h (or a custom duration) with a Resume now control and a live countdown. Local DNS records keep answering, and a restart always resumes blocking.
- 📊 Live query log and dashboard — block ratio, top domains, top clients,
and a live query log streamed over SSE, with one-click allow/deny straight
from the log. Clients are shown as their device hostname (
hostname (ip), IP fallback) in both the log and top-clients, resolved internally — set up reverse DNS (below) so your LAN devices get names. The log and dashboard are backed by a persistent query log (configurable retention, default 30 days; an enable/disable toggle and a clear-now action), so history and windowed figures survive a restart. The dashboard also shows a System panel (version, uptime, queries/sec, cache fill, process memory) and per-upstream health (success rate, latency). - 🔒 Encrypted upstreams — forward to resolvers over DNS-over-HTTPS (DoH) and DNS-over-TLS (DoT), with selectable upstream strategy (random, latency-weighted, or parallel-race) and per-upstream health tracking.
- 🏠 Local DNS records — define names for your own network, including
wildcards (e.g.
*.home.lan). - 🔁 Reverse DNS for the LAN — answers PTR queries for your local records
(so
nslookup <LAN IP>resolves), and conditional-forwards the private reverse zones (in-addr.arpa/ip6.arpa) to your router/DHCP resolver with a one-click setup.
See the roadmap for what's planned beyond the first milestone.
Architecture at a glance
| Layer | Technology |
|---|---|
| Async runtime | tokio |
| Service middleware (rate limiting, backpressure) | tower |
| DNS wire format | Custom lazy parser/serializer over bytes — shallow parse + raw passthrough |
| Upstream transport | hickory — UDP/TCP/DoT/DoH |
| Persistent storage | SQLite via sqlx — compile-time-checked queries, embedded migrations; stores config and the durable query-log history |
| Logging | tracing to stdout; live log streamed to the UI over SSE |
| CLI / config | clap flags (bind addresses, db path) with sane defaults |
| Hot-path state | HashSet blacklist/allowlist + a HashMap blocklist (domain → primary source) and HashMap local records, hot-swapped via arc-swap; moka cache with per-entry TTL |
| Web server | axum |
| Templating / UI | askama + Datastar (SSE) + Pico CSS |
| Frontend assets | Vendored and embedded via include_str! / include_bytes! — no CDN, no Node build; Lucide icons (icondata_lu) served as one <symbol> sprite |
The full design is documented in SPEC.md.
Install
Pick whichever fits; all of them give the same single binary.
Quick install (Linux + systemd). Downloads the latest release binary
(checksum-verified), creates an unprivileged sagittarius user, and installs
and starts the hardened systemd service from
deploy/sagittarius.service:
|
Re-running the script upgrades an existing install in place. The admin UI is
then reachable on port 8080 of the host. (As with any curl | sh, feel free
to download deploy/install.sh and read it first.)
Prebuilt binary. Download a Linux x86_64 or aarch64 tarball from the
latest release, verify
its .sha256, unpack, and run ./sagittarius.
From crates.io.
Docker (multi-arch amd64 / arm64, published to GHCR):
The admin UI is published on loopback above; front it with a reverse proxy for
remote access. A ready-made Compose file is at
deploy/docker-compose.yml.
Building
Requires a recent Rust toolchain (edition 2024).
The resulting binary is at target/release/sagittarius.
Running
# all flags shown with their defaults — `sagittarius` alone works too
On first run, open the admin interface and complete the one-step wizard to
create the initial admin user. Everything else is pre-seeded to working defaults
(e.g. Cloudflare 1.1.1.1 / 1.0.0.1 upstreams), so the resolver is functional
immediately. All state lives in the single SQLite file at --db-path.
Notes:
- Binding port 53 usually needs elevated privileges or the
CAP_NET_BIND_SERVICEcapability. - The admin interface serves plain HTTP and defaults to loopback. Put it behind a reverse proxy (Caddy, Traefik, nginx) for TLS / remote access.
--session-cookie-secure autouses secure admin cookies when the browser-facing request is HTTPS, and allows direct local HTTP while testing.
Deployment
The deploy/ directory has ready-to-adapt examples:
deploy/install.sh— the quick-install script (see Install) that downloads the latest release and sets up the systemd service below.deploy/sagittarius.service— a hardened systemd unit that runs Sagittarius as a dedicated unprivileged user withCAP_NET_BIND_SERVICEfor port 53, the database under/var/lib/sagittarius, gracefulSIGTERMshutdown, and the admin UI on0.0.0.0:8080so it is reachable from the LAN out of the box.deploy/Caddyfile— a reverse-proxy snippet that terminates TLS (automatic certificates) in front of a loopback admin UI.
For TLS or exposure beyond a trusted network, bind the admin interface to loopback and reach it only through the proxy; the forwarded scheme/host headers it sets are trusted for secure-cookie and CSRF origin decisions.
Detailed installation and configuration docs will be added as the project stabilizes.
Contributing
Sagittarius is in early development and contributions, ideas, and feedback are
welcome. Please read CONTRIBUTING.md for the quality gate,
branch/PR workflow, and how to set up the local git hooks.
Enable the hooks with a single command after cloning:
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as below, without any additional terms or conditions.
License
Licensed under either of
- Apache License, Version 2.0 (
LICENSE-APACHEor http://www.apache.org/licenses/LICENSE-2.0) - MIT license (
LICENSE-MITor http://opensource.org/licenses/MIT)
at your option.