DEV Community

Cover image for LanCache Router: Routing and Failover for Technitium
Johannes Posch
Johannes Posch

Posted on Fully Autonomous

LanCache Router: Routing and Failover for Technitium

A local game cache is valuable, but it becomes useless as soon as the DNS sends a bunch of PCs into a cache that is no longer functioning.

Another problem arises if you have multiple VLANs - the best choice of the cache for one network may turn out to be very bad for the other network. The PC server with a quick access channel to the gaming PCs of your LAN could be placed behind a firewall access point with a significantly lower speed for all the others.

And I wanted both these problems to work at once – which cache is appropriate for that client? Is the cache online?

The end product is called LanCache Router, an open source software application developed to work in Technitium DNS Server.

Why I moved the decision into Technitium

LanCache stores supported game and update downloads locally, so multiple machines can reuse downloaded content. DNS helps clients find it by returning the cache's address for the relevant download hostnames.

My previous setup spread the routing and health decisions across several components: dnsdist chose a DNS backend by client subnet, lancache-dns supplied the cache answers, and a separate checker toggled availability. Technitium handled normal DNS resolution.

That left several services coordinating a decision I wanted to make inside the DNS server. It also tied the setup to one cache and a hard-coded subnet.

Technitium supports apps that participate in query processing, so I brought the routing, domain matching, and health checks into one app. LanCache still handles the actual downloads and storage.

A gaming client queries Technitium DNS, receives a healthy cache address, and connects directly to that cache for the download.

DNS chooses the destination. The download connection runs directly between the client and the cache.

A route for each client network

The configuration describes cache servers and the networks allowed to use them. A setup could look like this:

Client network Preferred cache If it is unavailable
Gaming PCs Cache in the gaming room Use the standby cache.
Another building Cache in that building Use its configured standby.
Guests No cache route Use normal DNS resolution.

For a supported query reaching the app, the decision is straightforward:

  1. Find the first enabled route matching the client's source address.
  2. Select the first Healthy server in that route's preference list.
  3. Check whether the queried name belongs to the active cache-domain list.
  4. Return the cache address for an A lookup, or let Technitium continue if those checks do not pass.

A route can also explicitly pass queries through, which is useful for exempting a test PC from its subnet's cache rule.

Routes use explicit priorities: lower numbers run first, and the first match wins. Put a device exception before the broader subnet route. If the winning route has no healthy server, the app passes through rather than trying a later route.

One subnet, two caches

Here is a complete configuration for a preferred cache and a standby:

{
  "enabled": true,
  "cacheServers": [
    { "name": "cache-1", "address": "192.168.3.44" },
    { "name": "cache-2", "address": "192.168.4.44" }
  ],
  "routes": [
    {
      "priority": 10,
      "sourceCidr": "192.168.3.0/24",
      "servers": ["cache-1", "cache-2"]
    }
  ]
}
Enter fullscreen mode Exit fullscreen mode

Replace the addresses and subnet with your own. Both caches must be reachable by the routed clients and by the DNS server.

For matching download domains, clients in 192.168.3.0/24 receive cache-1 while it is Healthy. If it becomes unavailable, new answers use cache-2, provided that server is Healthy. If neither qualifies, Technitium resolves the lookup normally under its existing rules.

Clients outside the subnet have no matching route, so their lookups follow normal DNS processing. You could add a second route for 192.168.4.0/24 and reverse the preference list, giving each network its nearby cache first.

This is ordered failover. The app selects one cache at a time for each route; it does not balance downloads across all healthy servers.

Three health snapshots: cache-1 is selected while healthy, cache-2 is selected when only the standby is healthy, and normal DNS resolution continues when neither is healthy.

The route's preference order decides each new answer. Clients may retain an earlier answer until its TTL expires.

Health checks without probing on every lookup

The default check requests /lancache-heartbeat over HTTP on port 80 and accepts a 200 or 204 response. TCP and HTTPS checks are also available, with shared defaults and per-server overrides.

Probes run in the background. Query handling reads the latest health state and domain matcher without making a network request of its own.

By default, two consecutive failures mark a cache Unhealthy, and three consecutive successes make it Healthy. Newly started caches begin Unknown and use faster startup checks until their state settles. A preferred cache returns to selection automatically after it recovers.

There is a timing limit here that matters in practice: changing a DNS answer does not move an existing download.

The app first needs to detect the failure. Clients may then retain an earlier answer until its TTL expires; the default is 60 seconds. Open connections continue independently. Failover improves subsequent lookups, but it cannot make an interrupted connection switch servers instantly.

Keeping the domain list current

The app downloads the community uklans/cache-domains list, with a configurable refresh schedule. You can include or exclude services, add download hosts, and carve individual names out of broader wildcard entries.

A failed refresh keeps the last successful list active. Each DNS node also saves a snapshot for ordinary restarts, so a temporary source outage does not require discarding a list it already has. A first installation still needs a successful download before cache-domain matching becomes available.

Before trying it on your network

There are a few boundaries to account for:

  • Technitium needs to see the client address. If NAT or a forwarding resolver makes every query appear to come from one gateway, subnet routes cannot distinguish the original clients.
  • Health checks run from the DNS node. A successful probe cannot detect a firewall rule that blocks only the clients. In a cluster, each node probes independently.
  • Cache addresses are currently IPv4 only. Eligible AAAA, HTTPS, and SVCB queries receive empty successful answers by default, keeping IPv6 addresses and service hints from bypassing the cache. Those modes are configurable.
  • Existing DNS rules still matter. Local zones and other apps can take precedence. Passthrough follows Technitium's normal behavior, including its blocking and upstream settings.

There is also no per-service routing yet: a client cannot send Steam downloads to one cache and Epic downloads to another through separate service rules. IPv6 cache addresses, per-service routing, and a diagnostic TXT query are recorded in the backlog.

Try it

You need a working LanCache and a compatible Technitium installation. Install the app ZIP through Technitium's Apps page, open its configuration, and start with one client subnet. The packaged configuration is disabled until you supply your settings and enable it.

Once the cache is Healthy and the domain list has loaded, test from a client in that subnet. Replace the DNS address below with yours:

dig @192.168.3.53 lancache.steamcontent.com A +short
Enter fullscreen mode Exit fullscreen mode

With the default list and the example configuration, the answer should be 192.168.3.44 while the preferred cache is Healthy. The installation guide covers package compatibility, building from source, and checking fallback.

The project is MIT licensed, with a wiki covering configuration, routing examples, and troubleshooting.

If this fits your setup, take a look at the repository. Feedback from people running several VLANs or multiple DNS nodes would be especially useful. An issue with your intended topology, expected behavior, and relevant logs gives me something concrete to work with.

How are you handling cache availability across your networks today?

Top comments (0)