Skip to main content
Atlas was built on Kubernetes and does not need it. The plugins carry no Kubernetes, Agones or Shulker code; those names appear in comments explaining why something behaves as it does, never in an import. What the cluster supplied was configuration, a name per server, and a copy of the world. This page is how to supply those three things by hand.

Let the proxy find the shards

Give each shard the host and port the proxy dials and it registers itself.
That is the whole setup. The proxy reads the shards out of MongoDB every five seconds and keeps its own server list matching, so you do not list shards in velocity.toml at all. A shard that goes away is unregistered; one that moves is re-registered at its new address. This is the piece Kubernetes was doing. An operator there watched the cluster and registered each server as it appeared. Nothing does that on a rented box, so Atlas does it itself.
A server already named in velocity.toml is never touched, so anything you declare by hand wins and auto-registration only fills in the rest. The two mix freely.

Declaring them yourself

Leave address unset and nothing above happens. The names then become a contract: the proxy asks MongoDB which server owns a region, gets back a name, and looks it up among the servers in velocity.toml. If they do not match, players cannot be routed. Left unset, a shard names itself after its grid position, so world-r0, world-r1 and so on.
velocity.toml
On a panel host, do not rely on the machine hostname for server names. Several servers share one machine, so every shard would announce the same name, the last to start would own every region’s record, and players anywhere would be routed to it.

Shards on different providers

Nothing in Atlas cares where a shard runs. address is only where the proxy dials, so a public host and port works exactly like a LAN one, and a network split across two or three hosts is an ordinary deployment rather than an advanced one. The reason it is this easy is worth knowing, because it is what bounds the firewall work: shards never open a connection to each other. Every message between them — handoffs, ghost frames, block deltas, entity crossings — is published to Redis and read back by the other side. The only thing that ever dials a shard is the proxy.
Players reach a Velocity proxy, which dials shards on three separate providers; every shard and the proxy reach one MongoDB and Redis, and no shard connects to another shardPlayers reach a Velocity proxy, which dials shards on three separate providers; every shard and the proxy reach one MongoDB and Redis, and no shard connects to another shard

Four boxes on three providers, one geo. The only inbound port the public needs is the proxy's.

So the checklist for spreading a network over the internet is three items: give every shard an address the proxy can actually reach, put MongoDB and Redis somewhere every box can reach, and read Security before you do either — a database on a public address with no password is the whole network, and a shard on a public address is only protected by the forwarding secret.
This is not cross-geo. Cross-geo means a second proxy, near players on another continent, with its own Redis and public host. It is about where your players are, not where your servers are. One geo spread over five providers is still one geo. See Across continents if you actually want the second proxy.

What latency changes

Everything works over WAN. Four things get slower, and only the first is worth acting on. The crossing number is the one that matters, and it is not the position handoff — it is a full backend login, which ships this server’s entire registry set, roughly a megabyte, every time. tuning.pre-open makes the neighbour hold that connection open in the configuration phase before the player reaches the line, so the expensive part is already paid when they step over.
tuning.pre-open is off by default and that default is deliberate: the first deployment of it made every crossing fail, because an armed player’s login skipped the lease and only a parked connection ever took it. It also only arms when exactly one neighbour is in reach, so a player walking into a corner still pays the full price. Turn it on against a border with nobody on it before you turn it on for players.

The hub

The hub is the room players are parked in while a shard restarts, and the proxy finds it by name. Calling it hub works. If you call it something else, set proxy.hub to match.

Configuration files

Both plugins write a starter config.yml on first start, in the same shape, at plugins/atlas/config.yml. Every setting is also an environment variable, and the file wins over the environment. That precedence matters more than it looks: on a rented server the panel often injects its own variables, and an operator who edits the file and sees nothing change has no way to find out why.
A misspelled setting is named in the startup log rather than ignored: config.yml has 1 setting(s) this version does not know: [shard.wrold]. That is the one class of configuration bug with no other symptom.

What you give up without an orchestrator

An honest list. None of these stop the system working.
On Kubernetes a dead shard is rescheduled and its region is served again within seconds. Here, a dead shard means its region has no owner until you restart it. Players in that region go to the hub and the rest of the world is unaffected — the failure is contained to one square, which is the design working — but the recovery is yours.
Updating the plugin means stopping shards. Players on a stopping shard are drained to the hub first.
Four servers means four files. The grid settings in particular have to agree, which is why leaving them at the defaults is worth doing.