# How external servers work

> How an external server gives a game server you host elsewhere a Coritan join address, and what its Overview tab shows.

Source: https://www.coritan.com/docs/proxies/external-servers/

In the dashboard:

- /dashboard/proxies/external/…/overview: https://www.coritan.com/dashboard/proxies/external

An *external server* gives a Minecraft server that you run somewhere else, such as at home or with another host, a join address under `coritan.gg`. Players join at the join address, and Coritan's edge forwards their connection to your server. Your server stays where it is, and players never see its own address. You order an external server as a plan and pay for it like any other service ([Connect a server you host elsewhere](/docs/proxies/external-servers/connect-an-external-server/)).

For a server hosted here, [create a join address](/docs/proxies/join-addresses/create-a-join-address/) instead.

## How players reach your server

1. The player types the join address, such as `survival-smp.coritan.gg`. It resolves to Coritan's edge in the region you chose.
2. The edge reads the name the player typed and opens a connection to your server's address and port.
3. The edge passes the player's traffic both ways. Your server sees the connection arrive from the edge.

Players type only the join address, whatever port your server listens on. Java players join on the edge's port `25565`, and Bedrock players add port `19132` ([Editions and ports](/docs/proxies/join-addresses/#editions-and-ports)). When your server does not accept the connection, players see the offline message ([What players see](/docs/proxies/join-addresses/#what-players-see)).

An external server carries **Minecraft Java** or **Minecraft Bedrock**, its *edition*. A Bedrock server must accept NetherNet connections, which Bedrock uses from version 26.50. The edge cannot carry players to a Bedrock server that speaks only the older RakNet protocol. A **TCP service** forwards only to a server hosted here, so an external server cannot carry one.

## Regions and edge addresses

The *proxy region* is where the edges that carry your players are. You choose it when you order the external server, and you can change it on the **Connection** tab. Choose the region closest to most of your players. The list offers only the regions that have an edge available at that moment.

The join address resolves only to the edges in its region, and Coritan never sends your players to another region. If no edge in the region is available, the join address stops resolving until one is.

The *edge addresses* are the IP addresses of the edges in your region, and connections to your server come from them. The **Your server** card on the **Overview** tab lists them under **Edge addresses**, so that you can allow them through your server's firewall ([Set up your server](/docs/proxies/external-servers/connect-an-external-server/#set-up-your-server)). Check the list again after you change the region.

## How Coritan checks your server

Coritan asks your server for its status, with the same request that a player's server list sends. It asks:

- every 5 minutes,
- at once after you change the server address or port,
- when you select **Test connection** on the **Overview** tab.

Each check waits up to 3 seconds for an answer. The badge in the external server's header shows the result:

| Badge | Meaning |
|---|---|
| `Online` | Your server answered the last check. |
| `Offline` | Your server did not answer the last check, or its answer was not a Minecraft status. |
| `Not checked` | Coritan has not checked your server yet, for example just after you changed its edition. |
| `Suspended` | The plan is suspended, and the join address does not resolve ([The plan behind the join address](#the-plan-behind-the-join-address)). |

The check has two limits:

- It does not send a PROXY protocol header. A server that requires the header does not answer the check, so the badge shows `Offline` while players can still join. The server list shows the offline message for the same reason ([Customise the server list entry](/docs/proxies/join-addresses/server-list/#troubleshooting)).
- For Bedrock, it passes when the server answers the older RakNet status request. A server that speaks only RakNet shows `Online`, but players on Bedrock 26.50 and newer cannot join it through the edge.

## Addresses Coritan cannot forward to

The server address must be a public IP address, or a full hostname such as `play.example.com` that resolves only to public addresses. Coritan checks it when you save it, and refuses:

- a private, loopback or reserved address, such as `192.168.1.20`, and a private name, such as `server.local`;
- a name without a dot, such as `minecraft`;
- the address of one of Coritan's edges, because players would loop back into the network;
- another customer's join address;
- the join address of another external server. Enter that server's own address instead.

You can enter the join address of one of your own servers hosted here. Coritan then forwards to that server's own address. [Connect a server you host elsewhere](/docs/proxies/external-servers/connect-an-external-server/#troubleshooting) lists the message for each refusal.

## The plan behind the join address

An external server's join address follows its plan:

- Coritan creates the join address once you pay the first invoice, and checks your server straight away.
- While the plan is suspended, for example for an unpaid invoice, the join address does not resolve, and you cannot change the connection. Both come back when the plan is active again ([Failed payments and suspended services](/docs/billing/failed-payments/)).
- When the plan ends, Coritan deletes the join address and unlinks its custom domain, and anyone can take the name. Coritan does not touch your own server.

[Manage an external server's plan](/docs/proxies/external-servers/billing/) covers the price, plan changes and cancelling.

## The Overview tab

Open the external server from the **Game** tab of [Edge Proxy](https://www.coritan.com/dashboard/proxies/game). Its row there shows the address it forwards to, with a note such as `External · Frankfurt` that names its region. The **Needs attention** count includes an external server whose check shows `Offline`.

The page's header shows the server's name, badges for its status, its edition and its last check, the join address with a copy button, the address it forwards to, the region and the service number, such as `#1203`. Until Coritan creates the join address, the header reads `No join address yet`. The **Overview** tab has four cards.

**Route**
: The **Join address**, the **Edition**, the address it **Forwards to**, the **Region**, the **Port** players join on, whether **PROXY protocol** is on, the **Status**, the **Status cache** and when it was **Created**. **Change** opens the **Connection** tab. For a Bedrock server, the **Port** row shows the Java port; Bedrock players join on `19132`.

**Your server**
: What your server answered at the last check: the **Latency**, the **Players** online and the maximum, the **Version** and the **MOTD**. When your server did not answer, the card shows `The backend did not answer` with the reason. The **Edge addresses** follow, and **Test connection** checks your server at once.

**Server list**
: The **Name**, **Online MOTD**, **Offline MOTD**, **Version string** and **Icon** that players see in their server list. **Edit** opens the **Server list** tab ([Customise the server list entry](/docs/proxies/join-addresses/server-list/)).

**Custom domain**
: The domain linked to the join address, and whether it is verified. **Link one** or **Manage** opens the **Custom domain** tab ([Use your own domain for a join address](/docs/proxies/join-addresses/custom-domain/)).

The **Connection** tab changes where the join address forwards ([Change the connection](/docs/proxies/external-servers/connect-an-external-server/#change-the-connection)), and the **Billing** tab holds the plan ([Manage an external server's plan](/docs/proxies/external-servers/billing/)).

## Limits

| Limit | Value |
|---|---|
| Editions | Minecraft Java and Minecraft Bedrock |
| Bedrock clients | Minecraft Bedrock 26.50 and newer, over NetherNet |
| Server address | A public IP address, or a full hostname of up to 253 characters |
| Port | 1–65535 |
| Server name | 1–100 characters |
| PROXY protocol | Minecraft Java only |
| Custom domains | One for each external server |
| Status checks | Every 5 minutes, each waiting up to 3 seconds |
| Connection tests | 20 a minute for your account |
| Connection changes | 30 in 5 minutes for each external server |

## Read external servers with the API

List your external servers, newest first, with `GET /api/v1/client/external-servers`. The answer is an array, and holds every external server on your account that has not been cancelled or deleted, including one that is still waiting for payment:

```bash
curl https://api.coritan.com/api/v1/client/external-servers \
  -H "Authorization: Bearer $CORITAN_TOKEN"
```

```json
[
  {
    "id": 1203,
    "service_id": 1203,
    "route_id": 57,
    "name": "Survival SMP",
    "hostname": null,
    "billing_status": "active",
    "billing_cycle": "monthly",
    "amount": 5.0,
    "next_due_date": "2026-10-01T00:00:00+00:00",
    "ordered_at": "2026-09-01T09:58:40+00:00",
    "module_name": "external_server",
    "status": "active",
    "state": "online",
    "display_name": "Survival SMP",
    "fqdn": "survival-smp.coritan.gg",
    "join_address": "survival-smp.coritan.gg",
    "subdomain": "survival-smp",
    "base_domain": "coritan.gg",
    "mode": "minecraft_java",
    "bedrock_bridge": false,
    "proxy_protocol": false,
    "real_ip": true,
    "upstream": {"host": "203.0.113.10", "port": 25565},
    "region": {"id": 3, "name": "Frankfurt"},
    "edge_addresses": [],
    "probe": {
      "checked_at": "2026-09-25T10:15:03+00:00",
      "ok": true,
      "latency_ms": 18,
      "players_online": 12,
      "players_max": 100,
      "version_name": "Paper 1.21.8",
      "motd": "Survival SMP",
      "error": null
    },
    "branding": {
      "online_motd": null,
      "offline_motd": null,
      "favicon": null,
      "version_name": null,
      "status_cache_ttl_seconds": null
    },
    "created_at": "2026-09-01T10:00:04+00:00",
    "updated_at": "2026-09-20T08:12:44+00:00"
  }
]
```

Each field says this:

| Field | What it holds |
|---|---|
| `id`, `service_id` | The external server's service ID. The other external server calls take it as `service_id`. |
| `route_id` | The join address's `id`. Change the server list entry with it ([Customise the server list entry](/docs/proxies/join-addresses/server-list/#with-the-api)). `null` until the join address exists. |
| `name`, `display_name` | The server's name. |
| `billing_status` | The plan's status: `pending` until you pay, `provisioning` while Coritan sets it up, `active`, `suspended`, `pending_termination` while Coritan removes it, or `failed` when setup failed. |
| `billing_cycle`, `amount`, `next_due_date`, `ordered_at` | The plan's billing cycle and price, when it next renews, and when you ordered it. |
| `status` | The join address's status: `active` or `suspended`. `null` until the join address exists. |
| `state` | The badge: `online`, `offline`, `unknown` for `Not checked`, or `suspended`. |
| `fqdn`, `join_address` | The join address, which players type. |
| `subdomain`, `base_domain` | The join address's name and the join domain. |
| `mode` | The edition: `minecraft_java` or `minecraft_bedrock`. |
| `proxy_protocol` | Whether the edge sends a PROXY protocol header. |
| `real_ip` | Whether a Java join address adds the player's address to the handshake when PROXY protocol is off ([What your server receives](/docs/proxies/join-addresses/#what-your-server-receives)). |
| `bedrock_bridge` | Whether **Geyser on the same port** is on. |
| `upstream` | The address and port the edge forwards to. |
| `region` | The proxy region's `id` and `name`. |
| `edge_addresses` | Always empty in the list. Read one external server for its edge addresses. |
| `probe` | The last check: when it ran, whether it passed, and what your server answered. `ok` is `null` before the first check, and `error` says why a check failed. |
| `branding` | The server list entry. `null` means the default. |

Read one external server with `GET /api/v1/client/external-servers/{service_id}`. It answers the same fields, with the region's `edge_addresses` filled in and a `custom_domain` object that describes the linked domain ([Use your own domain for a join address](/docs/proxies/join-addresses/custom-domain/#with-the-api)):

```bash
curl https://api.coritan.com/api/v1/client/external-servers/1203 \
  -H "Authorization: Bearer $CORITAN_TOKEN"
```

A server that is not on your account answers `404` with `External server not found`.

List the regions that can take an external server with `GET /api/v1/client/external-servers/regions`:

```bash
curl https://api.coritan.com/api/v1/client/external-servers/regions \
  -H "Authorization: Bearer $CORITAN_TOKEN"
```

```json
{
  "regions": [
    {"id": 3, "code": "fra", "name": "Frankfurt", "country_code": "DE", "nodes": 2}
  ],
  "default_region_id": 3
}
```

The list holds only the regions with at least one edge available, and `nodes` counts those edges. `default_region_id` is the first region in the list, which the order page picks for you, or `null` when no region is available. Pass a region's `id` as `location_id` when you change the connection ([Connect a server you host elsewhere](/docs/proxies/external-servers/connect-an-external-server/#with-the-api)).

## API

- `GET /api/v1/client/external-servers`: List external servers (https://www.coritan.com/docs/api/reference/client/external-servers/#op-get-api-v1-client-external-servers)
- `GET /api/v1/client/external-servers/{service_id}`: Get external server (https://www.coritan.com/docs/api/reference/client/external-servers/#op-get-api-v1-client-external-servers-service-id)
- `GET /api/v1/client/external-servers/regions`: Regions a new or existing external server can be served from (https://www.coritan.com/docs/api/reference/client/external-servers/#op-get-api-v1-client-external-servers-regions)
