# How join addresses work

> How a join address carries players to a game server through Coritan's edge, for Minecraft Java, Bedrock and other TCP games.

Source: https://www.coritan.com/docs/proxies/join-addresses/

In the dashboard:

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

A *join address* is a hostname, such as `survival-smp.coritan.gg`, that players type in their game to reach your server. Players connect to Coritan's edge, which reads the name they asked for and forwards the connection to the server behind it. Players never see your server's own IP address and port. The dashboard also calls a join address a *game proxy*, and gives each one a number such as `Route #42`.

Join addresses on coritan.com end in `coritan.gg`, the *join domain*. The **Join domain** card on the [Edge Proxy](https://www.coritan.com/dashboard/proxies/game) page shows it. A join address forwards to one of your servers hosted here, or to a server you run elsewhere as an [external server](/docs/proxies/external-servers/).

## Editions and ports

Each join address carries one kind of game traffic, called its *edition*. You choose it when you [create the join address](/docs/proxies/join-addresses/create-a-join-address/).

| Edition | Players join at | Edge port | Who can join |
|---|---|---|---|
| **Minecraft Java** | `survival-smp.coritan.gg` | `25565` | Players on Minecraft Java Edition |
| **Minecraft Bedrock** | `survival-smp.coritan.gg`, port `19132` | `19132` | Players on Minecraft Bedrock 26.50 and newer |
| **TCP service** | `survival-smp.coritan.gg:61234` | A port of its own, which the edge picks | Players of any game that connects over TCP |

`25565` and `19132` are the games' default ports, so players type only the name. Every Java join address shares port `25565`, and every Bedrock join address shares port `19132`: the edge tells them apart by the name the player typed. A plain TCP connection carries no name, so each **TCP service** join address gets a port of its own on the edge, and players type that port after the name.

Two editions have limits of their own:

- A **Minecraft Bedrock** join address carries NetherNet, the connection that Minecraft Bedrock uses from version 26.50. Older Bedrock clients cannot join through it. The server behind it must accept NetherNet connections too, and a Bedrock server that speaks only the older RakNet protocol cannot take players through a join address.
- A **TCP service** join address forwards only to a server hosted here, and its edge port is in the region where the server runs.

## How a player reaches your server

1. The player's game looks up the join address. It resolves to Coritan's edge in the region where your server runs.
2. The edge reads the name the player asked for and finds its join address.
3. The edge opens a connection to your server and passes the player's traffic both ways.

If your server does not accept the connection, the edge ends the join with the server's offline message ([What players see](#what-players-see)).

## What your server receives

Your server sees each player's connection arrive from the edge's address. The edge can pass on the player's own address in one of two ways:

- With **PROXY protocol** on, the edge starts each connection with a PROXY protocol version 2 header that carries the player's address. The server must expect the header, or every join fails. Bedrock join addresses cannot use it.
- With PROXY protocol off, a Java join address adds the player's address to the server address in the Minecraft handshake, in the form `survival-smp.coritan.gg///203.0.113.50:53422///1790000000`. A plugin that reads this form can recover the player's address, and a server without one ignores the extra text.

Without either, your server's logs and IP bans see the edge's address for every player.

## Join addresses and your server

A join address that forwards to a server hosted here follows the server. When the server moves, or its address or port changes, Coritan points the join address at the new address. A server can have more than one join address.

- When the server is suspended, its join addresses are suspended too, and they come back when the server does.
- When you delete the server, Coritan deletes its join addresses and any custom domain linked to them. The names become free for anyone to take.
- You cannot rename a join address, or delete it while its server stays. To offer players another name, create another join address for the same server.

An external server's join address follows the external server's plan instead ([Manage an external server's plan](/docs/proxies/external-servers/billing/)).

### Join addresses Coritan creates for you

When the join address policy's `auto_provision_minecraft` is `true` ([Read join addresses with the API](#read-join-addresses-with-the-api)), Coritan gives each new Minecraft server a join address while it sets the server up. The address is named after the server when that name is free and follows the [name rules](/docs/proxies/join-addresses/create-a-join-address/#name-rules). Otherwise the server gets none, and you [create one yourself](/docs/proxies/join-addresses/create-a-join-address/).

## What players see

What a player's server list shows, and what happens when they join, depends on the state of the join address and your server.

| Situation | The server list shows | A player who joins |
|---|---|---|
| Your server answers | Your server's own entry, with any changes from the **Server list** tab | Reaches your server |
| Your server does not answer | The offline message, with no players | Sees the offline message |
| A free server is asleep | `Asleep. Join to start the server` | Starts the server ([How free servers work](/docs/managed-containers/free-servers/#sleeping-and-waking)) |
| The join address is suspended | Nothing, because the name stops resolving | Gets the game's own error for a server it cannot find |
| No join address has the name | Nothing, because the name does not resolve | Gets the game's own error for a server it cannot find |

The offline message is the one on the join address's **Server list** tab, or `Server is currently offline` when that is empty ([Customise the server list entry](/docs/proxies/join-addresses/server-list/)).

A name that reaches the edge without a join address of its own, such as a domain whose record points at the edge before you link it, gets `There is no proxy associated with this domain.` in the server list and on joining.

The edge also protects your server from floods of connections:

- While an edge is under a flood, or when one address has too many connections open at once, the edge asks the player to join again with `Please rejoin to verify your connection.` The second attempt goes through.
- An address that opens too many connections in a short time is blocked for a while, and its players see `Your IP is temporarily blocked for suspicious activity.`
- When an edge carries all the players it can take, new joins get `This proxy is at capacity. Please try again shortly.`

## The Overview tab

Open a join address from [Edge Proxy](https://www.coritan.com/dashboard/proxies/game) to see its page. The header shows its name, its status and edition, the join address with a copy button, the server it forwards to and its number. The **Overview** tab has three cards.

**Route**
: The **Join address**, the **Edition**, the server it **Forwards to** with a link to the server's page, the **Port** players join on (**Edge port** for a TCP service), whether **PROXY protocol** is on, the **Status**, the **Status cache** and when it was **Created**. For a Bedrock join address, the **Port** row shows the Java port; Bedrock players join on `19132`.

**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 you 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 **Status** is `active` while players can join, and `suspended` while the server is suspended. An external server's page has more tabs and a **Your server** card ([How external servers work](/docs/proxies/external-servers/)).

## Limits

| Limit | Value |
|---|---|
| Name | 3–28 characters, one name under `coritan.gg` |
| Each name | One join address or [coritan.gg name](/docs/proxies/coritan-gg-names/) on the whole platform |
| Bedrock clients | Minecraft Bedrock 26.50 and newer |
| PROXY protocol | Minecraft Java and TCP service join addresses |
| TCP service | Servers hosted here |

## Read join addresses with the API

Read the join address policy with `GET /api/v1/gameproxy/policy`. It needs no token:

```bash
curl https://api.coritan.com/api/v1/gameproxy/policy
```

```json
{"auto_provision_minecraft": false, "base_domain": "coritan.gg", "listen_port": 25565}
```

`base_domain` is the join domain, `listen_port` is the port Java players join on, and `auto_provision_minecraft` says whether new Minecraft servers get a join address by themselves.

List your join addresses, newest first, with `GET /api/v1/gameproxy/routes`:

```bash
curl https://api.coritan.com/api/v1/gameproxy/routes \
  -H "Authorization: Bearer $CORITAN_TOKEN"
```

```json
{
  "routes": [
    {
      "id": 42,
      "service_id": 0,
      "upstream_service_id": 1187,
      "fqdn": "survival-smp.coritan.gg",
      "subdomain": "survival-smp",
      "base_domain": "coritan.gg",
      "mode": "minecraft_java",
      "listen_port": null,
      "upstream_host": "203.0.113.10",
      "upstream_port": 25565,
      "proxy_protocol": 0,
      "location_id": 3,
      "status": "active",
      "display_name": "Survival SMP",
      "description": null,
      "online_motd": null,
      "offline_motd": null,
      "favicon": null,
      "version_name": null,
      "status_cache_ttl_seconds": null,
      "created_at": "2026-09-01T10:00:04",
      "custom_domain": {
        "linked": false,
        "hostname": null,
        "domain": null,
        "subdomain": null,
        "probe_hostname": null,
        "verified": false,
        "verification_status": null,
        "include_in_list": false,
        "expected_cname_target": "survival-smp.coritan.gg",
        "failed_checks": 0,
        "fail_threshold": 6,
        "last_checked_at": null,
        "last_verified_at": null,
        "last_error": null
      }
    }
  ]
}
```

Each field says this:

| Field | What it holds |
|---|---|
| `fqdn` | The join address. For a TCP service, players add `listen_port` after it. |
| `mode` | The edition: `minecraft_java`, `minecraft_bedrock` or `tcp_port`. |
| `listen_port` | The edge port of a TCP service. `null` for Java and Bedrock, which use the shared ports. |
| `upstream_service_id` | The service ID of the server hosted here that the join address forwards to. `null` for an external server's join address. |
| `service_id` | For an external server's join address, the external server's service ID. For a server hosted here, read `upstream_service_id` instead. |
| `upstream_host`, `upstream_port` | The address the edge forwards to. |
| `location_id` | The region whose edge answers for the join address. |
| `status` | `active` or `suspended`. |
| `display_name`, `online_motd`, `offline_motd`, `favicon`, `version_name`, `status_cache_ttl_seconds` | The server list entry ([Customise the server list entry](/docs/proxies/join-addresses/server-list/#with-the-api)). `null` means the default. |
| `custom_domain` | The custom domain linked to the join address's server ([Use your own domain for a join address](/docs/proxies/join-addresses/custom-domain/#with-the-api)). |

`proxy_protocol` comes back as `0` or `1`. The list also holds your external servers' join addresses, and a row for each linked custom domain: that row's `fqdn` is your hostname, such as `play.example.com`, and its `status` is `active` only while the custom domain is verified. The dashboard folds both into the join address or external server they belong to.

## API

- `GET /api/v1/gameproxy/policy`: Storefront-facing effective policy (auto-provision + base domain) (https://www.coritan.com/docs/api/reference/client/game-proxy/#op-get-api-v1-gameproxy-policy)
- `GET /api/v1/gameproxy/routes`: List my routes (https://www.coritan.com/docs/api/reference/client/game-proxy/#op-get-api-v1-gameproxy-routes)
