Docker Swarm Across Three Continents: High Availability Designed for 100% Uptime
One data center is a single point of failure. This article builds a Docker Swarm across three continents that can survive the loss of an entire location: manager quorum, WireGuard, one entry point per region, Geo-DNS failover, database replication and operations.
A server in a data center is a single point of failure, no matter how good the hardware and the network are. If that location goes down, whether because of a power or network fault or simply a mistake during maintenance, the application is gone. Docker Swarm across multiple data centers solves exactly this problem: the containers run at three independent locations, ideally on three continents, and if one of them fails completely, the other two take over without users noticing a thing.
This article shows you step by step how to build a Docker Swarm cluster designed for 100% uptime: one server each in North America, Europe and Asia, an encrypted WireGuard network between the nodes, a manager quorum that survives the loss of an entire continent, one entry point per region and a DNS failover that automatically routes users to the nearest healthy location. We also explain honestly what can still fail even with this architecture and how to cover those risks as well.
Can Docker Swarm achieve 100% uptime?
A Docker Swarm across three continents is designed for 100% uptime: no single server, no single data center and no single continent can bring the application to a standstill on its own. Even so, nobody can guarantee absolute availability, not even the big cloud providers, whose highest commitments range from 99.99 to 99.999%. The reason is not the data centers but the things that all locations have in common. This article covers exactly those as well, so that you get as close to 100% as is technically possible.
What availability means in numbers
| Availability | Downtime per year | Downtime per month |
| 99% | 87.6 hours | 7.3 hours |
| 99.9% | 8.76 hours | 43.8 minutes |
| 99.99% | 52.6 minutes | 4.4 minutes |
| 99.999% | 5.3 minutes | 26 seconds |
The figures are based on 8,760 hours per year and 730 hours per month. Each additional nine cuts the permitted downtime to a tenth, and that is exactly where the work begins that a single server can no longer handle.
Why three continents make such a difference
Mathematically, three independent locations with 99.9% availability each only fail together if all three are disrupted at the same time: 0.1% times 0.1% times 0.1% equals 0.0000001%. The farther apart the locations are, the more independent they really are: separate power grids, separate network connections, separate weather, separate maintenance windows. That is why spreading the cluster across North America, Europe and Asia is the strongest form of resilience that can be built with servers.
What can still fail even with three continents
The remaining risks are the dependencies that all locations share, and there is a countermeasure for each of them:
- A faulty update is distributed by the cluster to all locations just as reliably as a good one. Countermeasure: health checks and automatic rollback, plus updates region by region.
- DNS is the one place that every user passes through. Countermeasure: a DNS provider with a globally distributed network and failover, and a short TTL.
- The database has to hold the same data at every location. Countermeasure: replication with automatic failover, see the section on data.
- Expired certificates and domains hit all locations at the same time. Countermeasure: automatic renewal and monitoring of the expiration dates.
- The switchover itself takes as long as the health checks and DNS need to react, usually one to two minutes during which individual requests can fail. Countermeasure: short check intervals, a short TTL and clients that retry failed requests.
The architecture at a glance
A Docker Swarm across multiple continents consists of six building blocks. Each of them eliminates a specific point of failure:
| Building block | Role | Failure it protects against |
| Three manager nodes on three continents | Maintain the cluster state through Raft consensus | Loss of an entire location or continent |
| Worker capacity in every region | Runs the containers close to the users | Failure of individual servers |
| WireGuard network between all nodes | Encrypts all cluster traffic across the internet | Eavesdropping and tampering between the data centers |
| Entry point (reverse proxy) per region | Accepts user requests and answers them locally | Failure of a region's entry point |
| Geo-DNS with health checks | Sends users to the nearest healthy location | Unreachable locations |
| Replicated data storage and backups | Keeps databases and files in several places | Data loss when a location fails |
How many managers, and where?
The manager nodes of a swarm maintain the cluster state using the Raft consensus algorithm. Every change needs the approval of a majority of the managers, known as the quorum. If the majority is lost, the existing containers keep running, but the cluster can no longer reschedule, compensate for failures or roll out updates.
| Managers | Majority | Tolerated failures |
| 3 | 2 | 1 |
| 5 | 3 | 2 |
| 7 | 4 | 3 |
Docker recommends an odd number of managers distributed across at least three zones, in a 1-1-1 split with three managers and 2-2-1 with five. This leads to the most important rule in this article: Two locations are not enough. With two locations, one of them inevitably holds more managers, and if exactly that one fails, the majority is gone. Only with three locations does the quorum survive the loss of any one data center, which with three continents means the loss of an entire continent.
Three continents or one: the trade-off
Every change to the cluster, every deployment and every rescheduling of a container waits for confirmation from the manager majority. Between Europe, North America and Asia, each of these confirmations involves a network latency of about 80 to 250 milliseconds. For users this makes no difference, because their requests are answered locally; deployments and rescheduling, however, take noticeably longer than in a cluster with short network paths.
| Option | Strengths | Trade-offs |
| Three continents (USA, Europe, Asia) | Maximum independence, users worldwide close to a server, an entire continent can fail | Slower cluster management, database replication over long distances, requests have to stay local |
| Three locations on one continent (for example Frankfurt, Strasbourg, Warsaw) | Fast cluster management, simple synchronous replication | A large-scale event on the continent hits all locations, more distant users have longer paths |
For applications with users on several continents and the goal of maximum availability, the three-continent option is the right choice, and it is what we build in this guide. One important rule runs through every step: each request is answered in its own region and never travels back and forth between continents.
Which KernelHost locations are suitable
KernelHost runs servers in the maincubes data center in Frankfurt am Main and offers virtual servers at further locations in Europe, North America and Asia-Pacific, including three locations in the USA as well as Canada, London, Strasbourg, Warsaw, Helsinki, Singapore, Japan, Sydney and Mumbai. The complete list with a map is on the server locations page. For the example in this article, we use Frankfurt am Main for Europe, the US East Coast for North America and Singapore for Asia.
Guide: building a Docker Swarm across three continents
The example uses three servers: swarm-eu in Frankfurt am Main, swarm-us on the US East Coast and swarm-asia in Singapore. The public addresses come from the documentation range 203.0.113.0/24, and the WireGuard network uses 10.10.0.0/24. Replace both with your own values. All three nodes are managers and workers at the same time; for more capacity, add worker-only nodes in each region later.
Step 1: Provision servers on three continents
Order three servers running Debian 12 or 13 in three regions and apply the basic hardening: SSH with keys only, automatic security updates, your own user accounts. The checklist for new root servers covers this. Give the servers descriptive hostnames so that you can tell right away in docker node ls which node is where.
hostnamectl set-hostname swarm-eu
Step 2: Install Docker on all nodes
Install Docker Engine from the official Docker repository on all three servers, as described in the article Installing Docker on Debian and Ubuntu. Then check the version on each node; all three should run the same major version:
docker version --format '{{.Server.Version}}'
Step 3: Build a WireGuard network between the continents
The nodes talk to each other over the public internet. So that all cluster traffic is encrypted and the Swarm ports are never publicly reachable, a WireGuard network connects the three servers. On each node, first generate a key pair:
apt-get install -y wireguard
umask 077
wg genkey | tee /etc/wireguard/private.key | wg pubkey > /etc/wireguard/public.key
Each node then gets a file at /etc/wireguard/wg0.conf. This is what it looks like on swarm-eu; the other two nodes are set up as mirror images:
[Interface]
Address = 10.10.0.1/24
ListenPort = 51820
PrivateKey = SWARM_EU_PRIVATE_KEY
MTU = 1420
[Peer]
PublicKey = SWARM_US_PUBLIC_KEY
Endpoint = 203.0.113.12:51820
AllowedIPs = 10.10.0.2/32
PersistentKeepalive = 25
[Peer]
PublicKey = SWARM_ASIA_PUBLIC_KEY
Endpoint = 203.0.113.13:51820
AllowedIPs = 10.10.0.3/32
PersistentKeepalive = 25
systemctl enable --now wg-quick@wg0
ping -c 3 10.10.0.2
Once all nodes answer on their 10.10.0.x addresses, the network is up. PersistentKeepalive keeps the connection open even behind stateful firewalls. The latencies that ping now reports between the continents are exactly the delays that every change to the cluster will cost.
Step 4: Firewall: only the Swarm nodes get in
Between the nodes, Docker Swarm needs port 2377/TCP for cluster management, 7946/TCP and UDP for communication among the nodes and 4789/UDP for the overlay network. Allow these ports on the WireGuard interface only; the only thing that stays open to the public is WireGuard itself, and only for the other nodes. With ufw, this looks as follows on swarm-eu:
ufw allow from 203.0.113.12 to any port 51820 proto udp
ufw allow from 203.0.113.13 to any port 51820 proto udp
ufw allow in on wg0 to any port 2377 proto tcp
ufw allow in on wg0 to any port 7946
ufw allow in on wg0 to any port 4789 proto udp
Important: ports that Docker publishes for containers bypass ufw, because Docker sets its own iptables rules. So publish only the entry point's ports (80 and 443) and never database or management ports.
Step 5: Initialize the swarm and add managers
On swarm-eu, initialize the swarm and make sure that both management and data traffic run over WireGuard:
docker swarm init --advertise-addr 10.10.0.1 --data-path-addr 10.10.0.1
docker swarm join-token manager
The second command prints the join command for additional managers. Run it on swarm-us and swarm-asia, each with its own WireGuard address, shown here for swarm-us:
docker swarm join --token SWMTKN-1-... --advertise-addr 10.10.0.2 --data-path-addr 10.10.0.2 10.10.0.1:2377
docker node ls
docker node ls then shows three nodes, one of them with the status Leader and the other two with Reachable. The join token is a secret: anyone who knows it can sneak a manager of their own into your cluster. Once the setup is complete, rotate it with docker swarm join-token --rotate manager.
Step 6: Enable autolock
The managers store the cluster state, including the keys used to encrypt the Raft logs, under /var/lib/docker/swarm/. With autolock, these keys are encrypted themselves, and a restarted manager only rejoins the cluster after an unlock key has been entered:
docker swarm update --autolock=true
docker swarm unlock
The first command prints the unlock key, which you store in a password manager. You need the second one after every restart of a manager. Without the key, the swarm cannot be restored even from a backup, so keep it separate from the servers.
Step 7: Label the nodes by region
Labels tell the scheduler where a node is located. The placement constraints in the following steps build on them:
docker node update --label-add region=eu swarm-eu
docker node update --label-add region=us swarm-us
docker node update --label-add region=asia swarm-asia
Step 8: Create an overlay network with the right MTU
Containers at different locations talk to each other over an overlay network. Because it runs through the WireGuard tunnel, its MTU has to be smaller: WireGuard works with 1420 bytes, the overlay network (VXLAN) needs 50 of those bytes for its own headers, which leaves 1370 bytes:
docker network create --driver overlay --attachable --opt com.docker.network.driver.mtu=1370 appnet
An MTU that is too large causes insidious symptoms: small requests work, large responses hang. If you do without WireGuard, you can encrypt the overlay network with --opt encrypted instead; in that case, IP protocol 50 (ESP) must also be allowed between the nodes, and Docker explicitly warns of a noticeable performance penalty. We recommend WireGuard because it covers all traffic, including management.
Step 9: Run the application in every region
A regular Swarm service distributes requests through its service address across all replicas in the cluster, including those on the other continents. With three continents, every second or third request would then travel halfway around the world. That is why each region gets its own service, which a placement constraint keeps in its region. The update settings make sure that new versions are rolled out one container at a time and automatically rolled back if errors occur:
for r in eu us asia; do
docker service create --name web-$r --replicas 2 --network appnet \
--constraint node.labels.region==$r \
--update-parallelism 1 --update-delay 30s \
--update-failure-action rollback \
registry.example.com/web:1.0
done
For Swarm to recognize whether a container is actually working and not just running, the image needs a health check, for example this line in your application's Dockerfile:
HEALTHCHECK --interval=10s --timeout=3s --retries=3 CMD wget -qO- http://127.0.0.1:8080/health || exit 1
A container whose health check fails three times in a row gets replaced, and during an update a failing health check stops the rollout.
Step 10: One entry point per region
A reverse proxy such as Caddy, Traefik or nginx acts as the entry point. It also runs as a separate service in each region and forwards requests only to the application in its own region. In host mode, it publishes ports 80 and 443 directly on the server in its region. A single shared configuration is enough, because Caddy reads the target from an environment variable:
example.com {
reverse_proxy {$UPSTREAM}:80
}
docker config create caddyfile ./Caddyfile
for r in eu us asia; do
docker service create --name edge-$r --network appnet \
--constraint node.labels.region==$r \
--env UPSTREAM=web-$r \
--config source=caddyfile,target=/etc/caddy/Caddyfile \
--publish mode=host,target=80,published=80 \
--publish mode=host,target=443,published=443 \
caddy:2
done
Every region needs a TLS certificate for the same domain. So obtain the certificates through the DNS challenge, which works regardless of which region the DNS record currently points to; for this, Caddy needs the module for your DNS provider. The proxy basics are covered in the article Setting up nginx as a reverse proxy.
Step 11: Set up Geo-DNS with failover
The last building block routes users to the right region. A DNS service with geo-routing and health checks sends users from Europe to Frankfurt am Main, users from the Americas to the US East Coast and users from Asia to Singapore. If a region fails, the health check detects this within 30 to 60 seconds and sends that region's users to the nearest healthy region. Set the time to live (TTL) of the records to 60 seconds so that resolvers pick up a change quickly. Multiple A records without a health check are only a stopgap: browsers often try the next address, but not every client does, and a failed region stays in the response.
Do the math honestly: the time between the failure and the switchover is the check interval plus the TTL, in this example one to two minutes, during which some of the users in the affected region still reach the failed location. Applications and apps that retry failed requests after a short pause bridge this gap almost unnoticed.
Step 12: Test the failure of a region
A failover that has never been rehearsed rarely works when it really counts. Simulate the failure of a region by taking its node out of service, and watch how the cluster and DNS react:
docker node update --availability drain swarm-asia
docker node ls
docker service ls
docker node update --availability active swarm-asia
Because the region's services are bound to their node by a placement constraint, they do not move elsewhere but pause; the DNS failover takes care of the region's users. So in this test, check above all whether the health check removes the region from the responses and whether the neighboring region carries the additional load. For a tougher test, cut the node off from the network entirely, for example by stopping WireGuard. Repeat the test after major changes and at least once a quarter.
Data: the hardest part of high availability
Docker Swarm replicates containers, not data. A volume always lives on the node where the container runs. Stateless services such as web frontends and APIs can therefore run in every region without any problems, but for anything that holds data, you need replication of its own.
Replicating databases across continents
Databases come with their own replication, and it is always preferable to shared storage across data centers. Across continents, a proven setup is a primary instance in one region with asynchronous replicas in the other two: for PostgreSQL, for example, streaming replication with a tool such as Patroni for automatic failover, and for MariaDB and MySQL the built-in replication. Each region then answers read requests locally, while writes go to the primary instance. To be honest, asynchronous also means that if the primary region fails, the last few seconds of writes may be missing. If you want to write worldwide and lose nothing, go with a database built for multiple regions, such as CockroachDB or YugabyteDB. Pin the database nodes to their region with a placement constraint so that Swarm never moves them away from their data:
docker service create --name db-asia --constraint node.labels.region==asia ...
Files and uploads
Uploaded files do not belong in a local volume but in S3-compatible object storage with replication to a second region, or in a replicated storage system of your own. Network file systems such as NFS across continents are slow and are themselves a single point of failure.
Sessions and caches
If the application keeps sessions in a container's memory, users lose their login during a switchover. Store sessions in a replicated database or a replicated cache such as Redis, or use signed tokens that every region can verify on its own.
Backups are still mandatory
Replication protects against the loss of a location, but not against mistakes: a record deleted by accident is gone from every region seconds later. That is why regular, tested backups to an independent location are part of every high-availability architecture, as described in the article Backup strategy for servers.
Operations: updates, maintenance and monitoring
Updates region by region
Do not roll out new versions to all regions at once but one after the other, and watch each region for a short while before moving on to the next. That way, a bug that no health check catches reaches one region at most, and the other two keep serving that region's users:
for r in asia us eu; do
docker service update --image registry.example.com/web:1.1 web-$r || break
sleep 300
done
If an update fails, Swarm rolls it back automatically thanks to the settings from step 9, and || break ends the loop as soon as the command reports an error. If problems with an update only show up later, roll it back manually with docker service rollback web-asia.
Maintaining a region
If a server needs to be rebooted or updated, take it out of service with docker node update --availability drain and let the DNS failover redirect its users to the neighboring regions beforehand. After the maintenance, bring it back with --availability active. Before moving on to the next manager, wait until docker node ls shows all three as reachable again, so that two managers are never missing at the same time.
Monitoring from the outside
Monitor each region individually and from outside the cluster: reachability of the entry points, health checks of the services, the state of the managers, the database replication lag and the expiration dates of certificates and domains. An alert has to get through even when an entire region goes silent. The article Setting up server monitoring shows how to build this for individual servers.
Distributing secrets securely
Passwords and keys do not belong in environment variables or Compose files but in Docker secrets. They are stored encrypted in the Raft log and delivered only to the services you explicitly assign them to:
printf '%s' 'YOUR_DATABASE_PASSWORD' | docker secret create db_password -
docker service update --secret-add db_password web-eu
Why KernelHost for a swarm across multiple continents
A cluster spanning several continents places different demands on the provider than a single server does. These are the points that matter in practice:
| Requirement | Why it matters | At KernelHost |
| Locations on multiple continents | The quorum needs three independent locations, and users want short paths | Frankfurt am Main plus locations in Europe, North America and Asia-Pacific from a single provider |
| Unlimited traffic | WireGuard, the overlay network and database replication generate constant traffic between the continents | Unlimited traffic VPS with no data cap |
| DDoS protection | Every entry point is publicly reachable and therefore a target | Included at every location, at the core location in Frankfurt am Main with 3.2 Tbps of Arbor real-time filtering, without null-routing |
| Full root access | WireGuard, the firewall and Docker Engine need full control | On every KVM root server and dedicated server |
| Fast provisioning | Replacement nodes and test regions should be up in minutes | Around 30 seconds in Frankfurt am Main, usually a few minutes at other locations |
| No contract lock-in per node | Nodes come and go with demand | PrePaid, no minimum term, no setup fee |
| Automation | New nodes should be created by script | Ordering and control through the KernelHost API |
An overview of all cloud plans with prices, along with a cost comparison against the big cloud providers, is on the Cloud server hosting page.
Common mistakes and how to avoid them
- Managers at only two locations. If the location with the majority fails, the cluster comes to a standstill. Solution: three locations, split 1-1-1 or 2-2-1.
- An even number of managers. Four managers do not tolerate more failures than three, but they add coordination overhead. Solution: 3, 5 or 7.
- Requests travel between continents. A single service address across all regions sends users halfway around the world. Solution: one service and one entry point per region.
- Swarm ports publicly reachable. Port 2377 and the overlay network never belong on the open internet. Solution: WireGuard only; publicly, only 80, 443 and WireGuard for the other nodes.
- Forgetting the MTU. Large responses hang, small ones work. Solution: an overlay MTU of 1370 with WireGuard at 1420.
- Relying on ufw for container ports. Docker bypasses ufw for published ports. Solution: publish only the entry point.
- A database in a volume without replication. If the region fails, the data is unreachable. Solution: database replication, with placement pinned to the region.
- Updating all regions at once. A bug then hits every user worldwide. Solution: roll out region by region.
- A high DNS TTL. With a TTL of one day, the failover only takes effect the next day. Solution: 60 seconds.
- Replication instead of backups. A mistake gets replicated just like good data. Solution: tested backups at an independent location as well.
In short
- A Docker Swarm across three continents is designed for 100% uptime: an entire location or continent can fail without the application going down.
- Nobody can guarantee availability in absolute terms; the remaining risks are DNS, faulty updates, the database and certificates, and there is a countermeasure for each of them.
- Three managers at three locations are the minimum; two locations are not enough for a fault-tolerant quorum.
- Every request stays in its region: one service and one entry point per region, plus Geo-DNS with health checks and a short TTL.
- WireGuard encrypts the cluster traffic, the Swarm ports stay invisible, and the overlay MTU drops to 1370.
- Swarm replicates containers, not data: databases need their own replication, and backups remain mandatory.
- KernelHost offers locations in Europe, North America and Asia-Pacific, unlimited traffic, DDoS protection at every location and PrePaid billing with no minimum term.
Frequently asked questions
Can Docker Swarm guarantee 100% uptime?
How many manager nodes does a highly available Docker Swarm need?
Why are two data centers not enough for Docker Swarm?
Can Swarm managers be spread across different continents?
Which ports does Docker Swarm need?
Do I need WireGuard, or is the encrypted overlay network enough?
How does failover between continents work?
How do databases stay available when a location fails?
Docker Swarm or Kubernetes for multiple locations?
Which KernelHost locations are suitable for a swarm across three continents?
What does a Docker Swarm across three continents cost?
2026 KernelHost GmbH. All rights reserved. This guide is protected by copyright. Republishing it on other websites, in whole, in part or in edited form, is not permitted without our written consent. Quoting with a source credit and a link is expressly welcome.

