# 🦎 Tunnels are now highly available

October 15, 2026 · 11 min read

![Animation: one of three data centers is on fire, while visitor requests go through the other two and down a tunnel to a home lab, and the site keeps working](/blog/img/2026-10-15-high-availability/cover-en.svg)

For two years, Tuna ran on the same setup it launched with. A tunnel address pointed straight at a specific server, and that server did everything at once: it accepted traffic from the internet, held client connections and passed one to the other. That made sense for a launch. But Tuna has grown. Today we have more than a thousand tunnels online at any given moment, and our tunnel nodes accept tens of thousands of connections a day. For a service like that, the "everything on one server" design was no longer good enough. If a server went down for a reboot or lost its network, every tunnel on it went down with it.

On October 14, we finished a migration we'd been preparing since the summer, and **our users' tunnels are now truly highly available**. It's no exaggeration to say this is the biggest change to Tuna's infrastructure since launch. No server and no data center is a single point of failure anymore. There's nothing you need to do. Addresses and certificates moved over on their own.

TL;DR

* The point where traffic enters Tuna and the node your client connects to are now separate servers. A failure of either one doesn't take tunnels down.
* Entry points and tunnel nodes run in several data centers operated by two providers in Russia, Germany and the Netherlands.
* A request arrives at the entry point closest to the sender, not wherever the client is connected. That's why Telegram webhooks reach the tunnel no matter where the client runs.
* You no longer need to choose a region for new names, ports and domains.
* High availability works for HTTP and TCP tunnels, for subdomains in the new zones and for custom domains connected via CNAME.

## How it used to work

The first version of the architecture had two regions, `ru` and `nl`. A tunnel's DNS name pointed directly at the IP of a tunnel node. The same node also ran a [Traefik](https://traefik.io/traefik) frontend that accepted requests from the internet and passed them into the tunnel.

![Animation of the old setup: the CLI gets a server address from the API and opens a tunnel to tuna-node; visitor requests go through Traefik on the same server; when the server fails, all tunnels become unavailable](/blog/img/2026-10-15-high-availability/before-en.svg)

Traefik and tuna-node used to live on the same server. If it went down, the tunnels on it became unavailable.

This setup had three weak spots, and we felt all three firsthand:

* **A server failure hit all of its clients.** A kernel update, a provider outage or problems in the data center made every tunnel on the node unavailable until it came back.
* **You had to choose a region.** Where traffic came in and where the client connected were tightly coupled: a tunnel in the `ru` region accepted traffic only through a Russian server.
* **Availability depended on the route to a single server.** If the path from the sender to the node broke, the tunnel became unreachable for that sender. That's how, this spring, [Telegram webhooks](https://tuna.am/en/blog/tunnel-location.md) stopped reaching tunnels in the `ru` region. There was only one workaround: switch the tunnel to another region and change the webhook URL.

## Why now

We'd known about the weak spots of the old setup for a long time, but this summer we really felt them. In June and July, the data center in the Netherlands that hosted our `nl` region node had several major outages. Each time, the node was down for days, and with it went the sites of every client whose tunnels ran through it. Technically, we could have moved the tunnels to another server, but that would only have partly solved the problem. Tunnels on our subdomains would have moved right away. But more than half of the tunnels on that node ran on custom domains like `example.com` connected via an A record. A new server would have had a new IP address, and every one of those clients would have had to update their DNS. That would most likely have taken longer than the data center's recovery, so waiting was the more sensible choice.

That was the first wake-up call. After it, we sat down with diagrams and plans for what highly available tunnels should look like, and got to work. We didn't want to rush, so we tested everything in a staging environment. We took nodes down, switched off entry points and watched how quickly clients reconnected.

Then, between October 8 and 11, drones damaged three Yandex data centers, and the Vladimir facility [had to be shut down completely](https://www.kommersant.ru/doc/9023925) (in Russian). Along with Yandex's own services, the websites of companies hosted in its cloud went down too. It was clear we couldn't put this off any longer, especially since by then the new architecture had been thoroughly tested. The switchover on October 14 took almost a whole day and finished at night, and in all that time tunnels were unavailable for about five minutes.

## How it works now

We split the service into two layers, and each of them now runs on its own servers.

**Entry points** accept traffic from the internet and terminate TLS. They now run [Envoy](https://www.envoyproxy.io/) instead of Traefik. The entry points are grouped into a Russian group and a European group. DNS sends requests from Russia to the Russian group and requests from all other countries to the European one, and within a group it picks the closest healthy entry point.

**Tunnel nodes** hold client connections. There are several of them too, in Russia and Europe. The server assigns each client to a node close to it, taking load into account, and the entry points know where each tunnel currently is and deliver requests there.

![Animation of the new setup: RU and EU entry points are separate from tunnel nodes; a request from Russia and a Telegram webhook come in through different entry points and reach the node with the tunnel; when a node fails, the CLI reconnects to a neighboring one, and when an entry point fails, traffic moves to a neighboring one](/blog/img/2026-10-15-high-availability/after-en.svg)

Entry points are now separate from nodes, and a failure of either means reconnecting within seconds rather than downtime.

What this means in practice:

* **An entry point failure is barely noticeable.** DNS drops the failed entry point, and traffic moves to a neighboring one within a few seconds.
* **A tunnel node failure no longer means downtime.** The client moves to another node on its own, and the tunnel address stays the same. This usually takes seconds, or up to a minute when hundreds of tunnels move at once.
* **It no longer matters where your client runs.** A Telegram webhook arrives at the entry point closest to Telegram and goes from there to the node your client is connected to, whether your client is in Russia or outside it. The problem from the spring post is now solved by the architecture, not by a workaround.

## No more choosing a region

Since where traffic comes in is no longer tied to the node the client connects to, choosing a region doesn't make sense anymore. Random and reserved names are now issued in the `a.2na.am` zone, and TCP addresses look like `a.2na.am:<port>`. There's now one free permanent subdomain, in the `a.tuna.free` zone, instead of a pair in `ru` and `nl`. You don't need to choose a region for new addresses, and the dashboard no longer offers that choice.

Old addresses in `ru.tuna.am` and `nl.tuna.am` keep working and now also go through the new entry points. The `--location` flag and the `TUNA_LOCATION` variable are now needed only for them: they tell the client which of the old zones to look in for a reserved name or port. They have no effect on the new zones.

## Where high availability applies

* **Subdomains in the `a.2na.am` and `a.tuna.free` zones** and TCP ports, including SSH, Postgres and Redis over TCP. We've also tested WebSocket, HTTP/2 and SSE.
* **Old addresses in the `ru.tuna.am` and `nl.tuna.am` zones**, including TCP ports. These zones themselves now point to `a.2na.am` via CNAME.
* **Custom subdomains** like `app.example.com` or `www.example.com` connected via a CNAME to `a.2na.am` or to the old `ru.tuna.am` and `nl.tuna.am` zones. ngrok and Cloudflare Tunnel work the same way. A CNAME points to the infrastructure as a whole, not to a specific server.
* **A team's custom domain zone** connected via a `*.<zone>` CNAME to `a.2na.am`, `ru.tuna.am` or `nl.tuna.am`.

If your domain or zone is already connected via a CNAME to `ru.tuna.am` or `nl.tuna.am`, you don't need to change anything.

## Where high availability does not apply

Domains connected via an A record aren't highly available, because an A record points to specific addresses. For a subdomain, switching it to a CNAME is enough. But an apex domain like `example.com`, meaning the domain itself without `www` or any other subdomain, can't be switched that way, because the DNS standard doesn't allow a CNAME there. Such a domain works, but it isn't fully fault-tolerant, and the dashboard warns you about it.

We recommend moving your site to a subdomain with a CNAME: a landing page to `www.example.com`, a user dashboard or web app to `app.example.com` or `my.example.com`. On the apex domain, set up a permanent 301 or 308 redirect using a [gateway](https://tuna.am/en/docs/gateways.md) with the [`redirect`](https://tuna.am/en/docs/traffic-policy.md#redirect) action. The redirect itself won't be fault-tolerant, but the site behind it will be. Browsers remember permanent redirects, so visitors who have been to the site before go straight to the subdomain from then on.

## Other things we've left behind

The minimal setup had been piling up problems for two years, and the migration fixed many of them at once:

* a single server going down no longer takes down the tunnels of all its clients;
* Telegram webhooks reach tunnels no matter where the client runs;
* a custom domain connected via CNAME is no longer tied to a single IP;
* if the DNS check for your custom domain fails, the dashboard tells you why right away, such as an address that isn't ours, an extra AAAA record or a missing record, instead of staying silent until the next day;
* you don't need to choose a region, and there's one free subdomain instead of two.

## You can now host your server at home

The Yandex data center story is a good reminder that any data center can one day disappear entirely, without warning. If your project is reachable from the internet through a service that lives on one server in one data center, your project is exactly as available as that server.

That's no longer the case with Tuna. Entry points and tunnel nodes are spread across different data centers and countries, and losing one of them won't stop our users' traffic.

So if your project isn't high-load and you've long wanted to host it at home in a home lab, on a mini PC or an old laptop, now is a good time. On Tuna's end, your site will stay available. The only things between you and real high availability are your home power and your internet provider, and those don't depend on us. A UPS protects you from power outages, and a backup connection from provider problems.

## What you need to do

There are no required steps. Old addresses keep working, and you don't need to move to the new domain. But we do recommend three things:

* **Update the client** to the latest version. Versions older than 0.28 don't notice a hung node and wait for it to come back instead of reconnecting. Version 0.35.0 has a bug that prevents reconnecting.
* **Switch your domain from an A record to a CNAME** pointing to `a.2na.am`. Old A records keep working, but only a CNAME gives you fault tolerance. We've covered what to do with a domain like `example.com` [above](#where-high-availability-does-not-apply).
* **Update your IP allowlists** if you've added a node or tunnel address to them. A TCP address now has several IPs.

If something doesn't work the way you expect, reach out in our [Telegram community](https://telegram.me/+Kgbtt0_gJwI5ZmEy) or email <info@tuna.am>.

## Leave feedback

If you enjoy using Tuna, or on the contrary you are not happy with something, please [leave feedback](https://my.tuna.am/?show_feedback=1).

![](/blog/img/2024-08-22/feedback.gif)

## News

We announce new features and posts on our [Telegram channel](https://t.me/tuna_am). Subscribe so you don't miss anything.

## Help

We value our users and carefully review every request. If you have any problems with tuna, please contact us in one of the following ways:

* [Email](mailto:info@tuna.am)
* [Telegram community](https://telegram.me/+Kgbtt0_gJwI5ZmEy)

**Tags:**

* [release](https://tuna.am/en/blog/tags/release)
* [tuna](https://tuna.am/en/blog/tags/tuna)
