OxiDNS puts DNS policy, caching, forwarding and network side effects in one pipeline
A high-performance, programmable DNS engine in Rust with flexible pipeline-based routing.
At a glance
- What is it?
- OxiDNS is a GPL licensed Rust DNS engine that models requests, upstream responses and network side effects as a composable sequence of tagged matchers, executors and providers, with a WebUI, a management API, Prometheus metrics and query audit logs. It suits a homelab or soft router operator who wants programmable routing and explainable decisions, and the documentation is explicit that it is not a one click ad blocking panel.
- Who is it for?
- OxiDNS fits an operator of a home gateway, a bypass router, an OpenWrt box or a homelab who wants DNS decisions to be declarative, auditable and able to drive firewall sets, RouterOS address lists or webhooks. It does not fit someone who wants a point and click ad blocking panel or an authoritative DNS service, both of which the documentation rules out in its own words.
- Can I use it commercially?
- Yes, with conditions. GPL-3.0 is a copyleft licence: if you distribute software that includes it, you must release that software's source code under the same licence. Running it internally without distributing it does not trigger that obligation.
- Is it still maintained?
- Yes. The repository last received commits 4 days ago.
- What is it written in?
- Mainly Rust, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.
Editorial analysis
A policy engine where the request path is a sequence
OxiDNS is a high performance, programmable DNS engine in Rust with flexible pipeline based routing, built for soft routers, OpenWrt, homelabs and advanced self hosted networks. The project description is a policy orchestration engine for complex networks, and the design idea is that DNS requests, upstream responses and network side effects go into the same composable and explainable policy pipeline, so complex behaviour can still be configured, validated and traced.
The lineage is stated plainly. The project is inspired by mosdns, but goes further than rule based splitting: instead of classifying a query and sending it down one of two paths, OxiDNS lets a sequence combine matchers, executors and providers into reusable conditional branches, jumps and fallback chains.
The request path itself is drawn in the documentation like this.
client -> server -> sequence (matcher + executor + provider)
|-> upstream / local answer -> response
`-> side effectsFour capabilities are named as the reasons to choose it. The strategy is composable, because a sequence combines matchers, executors and providers into reusable conditional branches, jumps and fallback chains. The decision is explainable, because query records, execution paths, structured logs and metrics can answer what a query matched, what it executed and why that result was chosen. Ingress and egress are unified, since the same policy serves UDP, TCP, DoT, DoQ and DoH and manages upstream resolution, connection reuse, concurrency arbitration and proxy egress together. And DNS drives network behaviour, because resolution results can act directly on Linux ipset and nftset, RouterOS address lists and static routes, HTTP webhooks and external scripts.
The configuration is tags, not protocol branches
The example configuration in the documentation is worth reading closely, because it shows the shape of the model rather than a feature list.
plugins:
- tag: internal_domains
type: domain_set
args:
exps: ["domain:corp.lan"]
- tag: forward_internal
type: forward
args:
upstreams:
- addr: "udp://192.168.1.1:53"
- tag: forward_public
type: forward
args:
upstreams:
- addr: "tls://dns.quad9.net:853"
bootstrap: "9.9.9.9:53"
- tag: main
type: sequence
args:
- matches: "qname $internal_domains"
exec: "$forward_internal"
- matches: "!has_resp"
exec: "$forward_public"
- exec: accept
- tag: dns_server
type: udp_server
args:
entry: main
listen: ":5335"Every unit has a tag and a type, and the sequence refers to them by tag. The matcher expression `qname $internal_domains` asks whether the query name is in the domain set, and the second branch, `!has_resp`, asks whether the previous step produced no response at all, which is what makes it a fallback rather than a second branch. The final `accept` ends the sequence.
The consequence is that policy lives in one declarative file where a provider, a matcher, an executor and a server are composed by name, rather than being spread across protocol entry points. The upstream configuration also shows a per upstream bootstrap address, which is what lets a TLS upstream be resolved before DNS is fully working.
The full configuration structure, the reuse rules and more deployment templates are in the configuration overview and the scenarios pages on the project site.
The plugin table is the real feature list
The documentation summarises the built in components in a table, and the categories are more informative than a bullet list would be.
Protocol ingress covers UDP, TCP, DoT, DoQ and DoH over HTTP/1.1, HTTP/2 and HTTP/3. Policy orchestration covers sequences, conditional matching, executor composition, jumps and fallback chains. Upstreams and egress cover multi protocol upstreams, concurrent response arbitration, connection reuse, bootstrap, SOCKS5 and a unified network.outbound.
Response handling is the longest row: TTL aware caching and negative caching, ECS and ECS client address mapping, local records, redirection, response construction, dual stack and IP preference. Rule data covers domain and IP sets, GeoIP, GeoSite, AdGuard rules and dynamic domain learning.
System integration covers Linux ipset and nftset, RouterOS address-list and static route, HTTP webhooks and external scripts. Observability covers query audit and execution paths, real time logs, Prometheus metrics, upstream probing and health checks. Runtime management covers configuration validation and hot reload, pinned matcher base results, targeted provider reload, and cache and upgrade management. Deployment covers multi platform builds, Debian packages, an OpenWrt LuCI plugin, a built in WebUI and management API, and service style installation.
The negative caching and the IP preference rows are worth noting separately, because they are the two features that distinguish a modern resolver from a minimal one. A TTL aware cache that also caches negative answers reduces the query load a blocked domain generates, and IP preference is what lets a dual stack client be steered towards the address family the network actually serves.
The complete list of built in components and configuration fields is in the plugin reference.
One command installs it and registers the service
The quick start is a single command, and the default behaviour after it is worth knowing.
curl -fsSL https://oxidns.org/install.sh | sudo shOn Windows, administrator PowerShell.
irm https://oxidns.org/install.ps1 | iexBy default the install script downloads the release for the platform, installs the WebUI, and registers and starts the system service.
After installation you can verify both the management side and the default DNS service.
curl -fsS http://127.0.0.1:9199/api/health
dig @127.0.0.1 example.com
dig @127.0.0.1 example.com +tcpThe WebUI default address is the server IP on port 9199. Before allowing other devices to reach it, the documentation says to enable `api.http.auth` and restrict the source through a firewall or reverse proxy.
That last instruction is a good summary of how the project treats its own management surface. The API is bound to a port and is usable locally, and turning on authentication plus source restriction is a step the operator has to take deliberately.
After changing configuration you should first validate it with `oxidns check`. On OpenWrt the same install script installs the luci-app-oxidns plugin, and the documentation covers manual download, Docker, Debian packages, portable installation and uninstallation, with a custom build guide for trimming protocols and plugins.
The project says who it is for, and who it is not for
The section on suitability is unusually direct, and it is the fastest way to decide whether this is your project.
OxiDNS suits DNS environments that need long term operation, fine grained control and complete observability. The listed cases are home gateways, bypass routers, OpenWrt, NAS and homelab; policy routing by domain, client, query type or response result; multiple upstream concurrency, primary and fallback, encrypted DNS and custom egress; ad blocking, local overrides, dual stack preference, ECS and dynamic rule learning; and DNS results driving firewall sets, address lists or policy routing.
Then the exclusions, which the documentation states in its own words. It is not an authoritative DNS service, and it is not a one click ad blocking panel that needs no understanding of the configuration model. If your primary need is ready to use graphical management, other products aimed at that scenario may suit you better. OxiDNS is for users willing to trade some configuration complexity for control and explainability.
That is the honest characterisation of the trade this project asks for. The engine gives you a pipeline, audit trails and metrics, and it charges for them in configuration surface area. A household that wants to block ads and never think about it again will not enjoy it, and the documentation says so rather than pretending otherwise.
A Rust workspace with a fast path and a slow path for the compiler
The repository is a Cargo workspace with the root crate plus four sub crates: crates/macros, crates/ripset, crates/proto and crates/zoneparser. The root package is oxidns at version 1.6.1, edition 2024, licensed GPL-3.0-or-later, and the description calls it a Rust powered DNS engine inspired by MosDNS, designed for performance and complete configurability.
The dependency list describes the design. tokio with fs, net, process, sync, time and signal features is the async runtime, and futures and async-trait sit alongside it. socket2 handles socket options, which is the kind of dependency you see when raw socket behaviour matters. arc-swap, dashmap, ahash and crossbeam-queue are the concurrent data structures, and inventory plus lazy_static are how plugins register themselves at startup.
The observability side is explicit: tracing, tracing-subscriber with an env filter, tracing-appender for file appenders, and jiff for timestamps. wincode and serde handle serialisation, and oxidns-proto and oxidns-macros come from the workspace crates.
The justfile shows how the project keeps itself honest. The check target runs cargo fmt with nightly, cargo clippy with all targets and all features and warnings denied, and then cargo test. There are faster targets: lint for just the format and clippy checks, and check-minimal, check-standard and check-full for the three feature bundles, so a change that breaks only the minimal build is caught. The most interesting target is check-each-feature, which compiles every public feature individually using cargo-hack, specifically to catch regressions where a feature fails to build in isolation. The file also defines a list of private features that should never be enabled on their own, including hotpath, hotpath-alloc, the task-cron ones and the TLS and HTTP ones.
The main README is in Chinese with an English version at README_EN.md, and the documentation site is at oxidns.org.
Editorial conclusion
OxiDNS fits an operator of a home gateway, a bypass router, an OpenWrt box or a homelab who wants DNS decisions to be declarative, auditable and able to drive firewall sets, RouterOS address lists or webhooks. It does not fit someone who wants a point and click ad blocking panel or an authoritative DNS service, both of which the documentation rules out in its own words. Before adopting it, read the quickstart and configuration overview, validate every change with oxidns check before reloading, and keep a recoverable configuration and a bypass plan, because the documentation states that DNS configuration directly affects network availability.
Frequently asked questions
How do I install OxiDNS?
One command: curl -fsSL https://oxidns.org/install.sh | sudo sh, or irm https://oxidns.org/install.ps1 | iex in administrator PowerShell on Windows. By default the script downloads the platform release, installs the WebUI and registers and starts the system service.
What is the sequence plugin in OxiDNS?
It is the policy composition type: a sequence combines matchers, executors and providers into reusable conditional branches, jumps and fallback chains. A rule matches on a condition such as qname against a tagged domain set, and if no response was produced the next branch runs as a fallback.
How do I secure the OxiDNS WebUI?
The WebUI defaults to http://server-ip:9199/. Before letting other devices reach it, enable api.http.auth and restrict the source with a firewall or a reverse proxy.
Is OxiDNS a one click ad blocker?
No, and the documentation says so directly: it is not an authoritative DNS service, and it is not a one click ad blocking panel that requires no understanding of the configuration model. It is aimed at users willing to accept configuration complexity in exchange for control and explainability.
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/svenshi-oxidns)Was this useful?