# Internal DNS Server

MintFlow DNS runs locally inside the VPN tunnel. It answers DNS queries, selects Direct or VPN/proxy upstream resolvers, caches results, and supplies domain-routing information to the packet engine. It is not a public DNS service or a DNS server for other LAN devices.

In Rules Mode, enable custom domain routing in **DNS & Routing** (`[dns] app-routing-enabled=true`). Simple Mode also uses internal DNS. If both are off, internal DNS features do not apply. The MintFlow VPN must be connected even when all traffic uses Direct.

## Secure DNS without a remote VPN

Configure **Direct DNS** with DoH or DoT and use a Direct output. Both encrypted DNS and DNS ad filtering are available Free on iOS; neither requires a remote VPN subscription or an HTTP inspection certificate.

```ini
[dns]
app-routing-enabled=true
direct-dns=tls://1.1.1.1
optimistic-dns-caching=true

[routing]
DNS-FALLBACK,DIRECT
DEFAULT,DIRECT
```

Plain IP entries such as `1.1.1.1` use unencrypted DNS. `tls://1.1.1.1` uses DoT; `https://cloudflare-dns.com/dns-query` uses DoH. Choose a resolver whose policies you trust. Encryption protects the connection to the resolver; the resolver still sees the queries. [Cloudflare's DoT documentation](https://developers.cloudflare.com/1.1.1.1/encryption/dns-over-tls/) explains this transport.

## Split DNS and VPN DNS

**Direct DNS** resolves Direct domains; **VPN DNS** resolves domains assigned to a VPN or proxy. This can keep work-domain lookups on a private resolver while ordinary names use your preferred public resolver. A private resolver must be reachable through the selected output.

For a hostname-based encrypted `vpn-dns` upstream, configure `VPN-DNS-SERVER-DOMAINS` to select the bootstrap VPN/proxy path. `bootstrap-dns` supplies the initial resolver addresses. This bootstrap lookup is separate from encrypted application-name queries.

```ini
[dns]
app-routing-enabled=true
direct-dns=tls://1.1.1.1
vpn-dns=https://cloudflare-dns.com/dns-query
bootstrap-dns=1.1.1.1,8.8.8.8

[routing]
VPN-DNS-SERVER-DOMAINS,L3VPN,my-wireguard
DNS-FALLBACK,L3VPN,my-wireguard
DEFAULT,L3VPN,my-wireguard
```

This fragment assumes an existing usable `my-wireguard` interface and peer. For a complete import workflow, see [WireGuard providers and secure DNS](https://galaxnet.dev/mintflow/articles/wireguard-provider-secure-dns/). Configure both DNS groups when using both Direct and VPN/proxy paths.

## Static DNS records and Tailscale names

Use Pro static records for a home NAS, test server, or local service without publishing its address to public DNS:

```ini
[dns-hosts]
nas.example.com=192.168.40.10
lab.example.com=192.168.40.20,192.168.40.21
```

Records match exact hostnames, not wildcards or all subdomains. Up to 256 names and 1–16 IPv4 addresses per name are supported. They answer locally before domain rules and the ad filter. They do not create a traffic route: add a suitable CIDR route, or ensure the address is otherwise reachable. Static and derived records stay inactive in Simple Mode.

A Pro Tailscale interface with `drive-dns:true` can derive peer IPv4 records. Exact user records win over derived names. Unknown names inside the active tailnet DNS zone stay local rather than being sent to public DNS. This is MintFlow-derived DNS, not the official client's complete MagicDNS configuration. See [Tailscale setup](../howtos/tailscale.md).

## Built-in DNS ad filtering in 2.1.0

Filtering is opt-in and runs on the device before an allowed query reaches its upstream. Select one preset: **AdGuard DNS filter** (default), **HaGeZi Multi Normal**, or **OISD Small**. All three include initial offline snapshots; opening the app schedules asynchronous updates for enabled lists, and **Refresh** checks manually. A failed update keeps the last accepted copy.

1. Select the intended profile and open **DNS & Routing → DNS Ad Blocking**.
2. Enable filtering, choose a list, and save. Internal DNS must be enabled.
3. Start VPN. If already connected, check the active status: supported filter-only changes can apply live; other profile changes may require a restart.
4. Use the domain checker, **DNS Log → Rule type**, and **Tools → DNS Runtime → DNS Ad Blocking** to inspect what is active. A cached-list check alone does not prove the running tunnel blocks that domain.

```ini
[dns-adblock]
enabled=true
list=adguard-dns
```

A blocked query receives **NODATA** (a successful DNS response with no answer), without an upstream lookup or a fake address. DNS filtering needs no MITM certificate. Lists do not consume domain-set routing allowances.

## Overrides and limits

In Rules Mode the order is **user static records → Tailscale-derived DNS → domain sets → ordered keywords → ad filter → DNS fallback**. A matching forwarding domain rule bypasses the filter; a Drop/Reject domain rule retains its blocking behavior. Keep forwarding exceptions narrow. `DNS-FALLBACK,DIRECT` does not disable filtering. In Simple Mode, the order is **ad filter → selected output**; saved static/domain rules stay dormant.

Filtering checks the queried DNS name, not every URL or the returned CNAME chain. It cannot remove page placeholders or reliably block ads sharing a hostname with wanted content, including many video and social-feed ads. An app's own encrypted DNS, remote proxy-side resolution, literal IPs, and already-cached addresses can bypass this local DNS check. Custom subscriptions and stacking lists are not supported in 2.1.0.

For a false positive, check the winning rule first. In Rules Mode add a narrow forwarding domain-set exception; in Simple Mode change the list or turn filtering off, or switch to Rules Mode to use exceptions. See the [routing engine](routing-engine.md) for examples.
