> ## Documentation Index
> Fetch the complete documentation index at: https://docs.craftsupport.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Panel and VPS hosting

> Running Atlas on rented servers, with no orchestrator

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.

```yaml theme={null}
shard:
  address: "127.0.0.1:25566"    # same machine
```

```yaml theme={null}
shard:
  address: "10.0.0.11:25565"    # separate machines on one LAN
```

```yaml theme={null}
shard:
  address: "gs3.myhost.net:25566"   # another provider entirely: this shard's public address
```

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.

<Tip>
  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.
</Tip>

### 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.

```toml velocity.toml theme={null}
[servers]
world-r0 = "10.0.0.11:25565"
world-r1 = "10.0.0.12:25565"
hub      = "10.0.0.10:25565"
```

<Warning>
  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.
</Warning>

## 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.

<Frame caption="Four boxes on three providers, one geo. The only inbound port the public needs is the proxy's.">
  <img className="block dark:hidden" src="https://mintcdn.com/craftsupport/n1BcCEBpHaCnGSeu/diagrams/providers-light.svg?fit=max&auto=format&n=n1BcCEBpHaCnGSeu&q=85&s=c1df2303422c5e5f7a7bc0ec6f128e39" alt="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 shard" width="640" height="430" data-path="diagrams/providers-light.svg" />

  <img className="hidden dark:block" src="https://mintcdn.com/craftsupport/n1BcCEBpHaCnGSeu/diagrams/providers-dark.svg?fit=max&auto=format&n=n1BcCEBpHaCnGSeu&q=85&s=911943d619abb48748268c222fa7a10c" alt="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 shard" width="640" height="430" data-path="diagrams/providers-dark.svg" />
</Frame>

| Connection                      | Direction               | Needed                              |
| ------------------------------- | ----------------------- | ----------------------------------- |
| Player to proxy                 | inbound to the proxy    | The only port the public needs      |
| Proxy to each shard             | outbound from the proxy | Whatever you put in `shard.address` |
| Each shard to MongoDB and Redis | outbound from the shard | Authenticated, over TLS             |
| Proxy to MongoDB and Redis      | outbound from the proxy | Same                                |
| Shard to shard                  | **never happens**       | Nothing to open                     |

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](/deploy/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.

<Note>
  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](/concepts/cross-geo) if you actually want the second proxy.
</Note>

### What latency changes

Everything works over WAN. Four things get slower, and only the first is worth acting on.

| What                             | On a LAN           | Over WAN                          | Do about it                               |
| -------------------------------- | ------------------ | --------------------------------- | ----------------------------------------- |
| A border crossing                | 300-450 ms         | 2.3-2.9 s across an ocean         | Turn on `tuning.pre-open`                 |
| Breaking a block across a border | well inside budget | fine below about 1.5 s round trip | Nothing                                   |
| Mobs appearing after you cross   | a few hundred ms   | depends on the link               | `tuning.chunk-send-rate` on a metered one |
| Handoff acknowledgement          | instant            | 8 s budget, 30 s lease            | Nothing                                   |

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.

<Warning>
  `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.
</Warning>

## 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.

<Note>
  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.
</Note>

## What you give up without an orchestrator

An honest list. None of these stop the system working.

<AccordionGroup>
  <Accordion title="No automatic replacement">
    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.
  </Accordion>

  <Accordion title="No rolling updates">
    Updating the plugin means stopping shards. Players on a stopping shard are drained to the hub first.
  </Accordion>

  <Accordion title="Configuration is per server">
    Four servers means four files. The grid settings in particular have to agree, which is why leaving them at the defaults is worth doing.
  </Accordion>
</AccordionGroup>
