> For the complete documentation index, see [llms.txt](https://docs.edgegap.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.edgegap.com/docs/sample-projects/unity-netcodes/small-network-relay.md).

# Lightnet Small Network Relay

Host a small network relay on Edgegap and play the Tanks sample through it with Mirror, FishNet, PurrNet or Netcode for GameObjects, picked with one setting.

Explore how to run your own small network relay on Edgegap, with a Unity game sample that plays through it using [Mirror](https://mirror-networking.com/), [FishNet](https://fish-networking.gitbook.io/docs), [PurrNet](https://purrnet.dev/) or [Netcode for GameObjects (NGO)](https://docs-multiplayer.unity3d.com/netcode/current/about/).

The relay is a small .NET server built on [LightNet](https://github.com/edgegap/server-sample-unity-smart-relays). Edgegap hosts and orchestrates it like any other server: one deployment, started near your players. One player hosts a room and gets a 6-letter code, the other players join with that code. No player opens a port: everyone, including the host, is a client of the relay.

This sample shows:

* **a relay server** in a `linux/amd64` Docker image, listening on port `7777` for both TCP (reliable messages) and UDP (unreliable messages),
* **rooms with a join code** - many rooms can share one relay deployment,
* **the Tanks sample on four netcodes** - Mirror, FishNet, PurrNet and NGO in one Unity project, one build,
* **one setting to switch netcode** - in a settings asset, an editor menu, in the game before connecting, or on the command line,
* **an automated test** - two game clients play through the relay on each netcode.

{% hint style="success" %}
**This is a client-host setup**: the hosting player's runs as server and relay forwards bytes between players.
{% endhint %}

{% hint style="info" %}
Alternative - [dedicated servers](/learn/orchestration/deployments.md#orchestration) prevent host player advantage and the match survives the host leaving.
{% endhint %}

## ✔️ Preparation

Before we start, you will need:

* Small Network Relay sample project - [download from GitHub](https://github.com/edgegap/server-sample-lightnet-relay),
* Unity `6000.0.54f1` - [download from Unity](https://unity.com/releases/editor/archive), to open and build the game,
* .NET 8 SDK (optional) - [download from Microsoft](https://dotnet.microsoft.com/download/dotnet/8.0), only to run the relay outside Docker.

<details>

<summary><a href="https://www.docker.com/products/docker-desktop/">Install Docker Desktop (or Docker CLI)</a></summary>

* [Install Docker Desktop from the official source](https://www.docker.com/products/docker-desktop/) (no account required).
* Restart your computer after completing the installation.

</details>

The repository has three parts:

| Folder         | What it is                                                                                            |
| -------------- | ----------------------------------------------------------------------------------------------------- |
| `LightNet`     | LightNet networking core as a Unity package, plus the relay protocol and its netcode-agnostic client. |
| `relay-server` | Relay Server - .NET 8 console app built from the same sources, and its Dockerfile.                    |
| `tanks`        | the Unity project: Mirror's Tanks example on Mirror, FishNet, PurrNet and NGO.                        |

## 🔀 Pick the Netcode

The netcode is the `netcode` field of `tanks/Assets/Tanks/Resources/TanksSettings.asset`: `Mirror`, `FishNet`, `PurrNet` or `NGO`. The same asset holds the relay address and port.

You can also switch it:

* in the Unity Editor, with the **Tanks > Netcode** menu - this also opens that netcode's scene,
* in the game, with the netcode buttons at the top of the screen, before hosting or joining,
* on the command line, with `-netcode FishNet`.

| Netcode | Version | Tank sync                                                                                |
| ------- | ------- | ---------------------------------------------------------------------------------------- |
| Mirror  | 66.0.9  | `SyncVar`, `Command`, `ClientRpc`, client authoritative `NetworkTransform`               |
| FishNet | 4.7.4   | `SyncVar<int>`, `ServerRpc`, `ObserversRpc`, client authoritative `NetworkTransform`     |
| PurrNet | 1.24.1  | `SyncVar<int>`, `ServerRpc`, `ObserversRpc`, owner authoritative `NetworkTransform`      |
| NGO     | 1.13.0  | `NetworkVariable<int>`, `ServerRpc`, `ClientRpc`, owner authoritative `NetworkTransform` |

{% hint style="warning" %}
**The host and every player must use the same netcode.** The relay doesn't verify netcode compatibility.
{% endhint %}

Each netcode has its own relay transport, built on the same relay client (`RelayPeer`): `MirrorRelayTransport`, `FishNetRelayTransport`, `PurrNetRelayTransport` and `NgoRelayTransport`. To use the relay in your own game, copy the `LightNet` package and the transport for your netcode.

## ⚡ Deploy and Connect

### 1. Run the Relay Locally

☑️ From the repository root, build and run the relay image:

{% code collapsedlinecount="10" %}

```bash
docker build --platform linux/amd64 -f relay-server/Dockerfile -t lightnet-relay:dev .
docker run --rm -p 7777:7777/tcp -p 7777:7777/udp lightnet-relay:dev
```

{% endcode %}

☑️ Open `tanks` in Unity, pick a netcode, and build with **Tanks > Build Windows client**, or press Play on `Assets/Tanks/Scenes/Boot.unity`.

☑️ In the first game, press **Host**: the room code appears on screen. In the second game, type the code and press **Join room**.

✅ You may now proceed to the next step.

### 2. Push the Relay Image

☑️ To get started, you'll need to [create a free account with Edgegap](https://app.edgegap.com/auth/register). No credit card required.

☑️ Find your [Container Registry](/learn/advanced-features/edgegap-container-registry.md) project name and credentials.

☑️ Tag and push the relay image, with a new tag for every build:

{% code collapsedlinecount="10" %}

```bash
docker tag lightnet-relay:dev registry.edgegap.com/<project>/lightnet-relay:<tag>
docker login registry.edgegap.com
docker push registry.edgegap.com/<project>/lightnet-relay:<tag>
```

{% endcode %}

{% hint style="danger" %}
:x: **DO NOT - overwrite existing tags or use `latest` tag** - this will deploy an outdated cache.\
:white\_check\_mark: **DO - always increase your version tag** and deploy the new build.
{% endhint %}

{% hint style="warning" %}
Each organization gets their own registry project, **make sure to modify the commands to match yours.**
{% endhint %}

✅ You may now proceed to the next step.

### 3. Create an App Version

☑️ [Create an application](https://app.edgegap.com/application-management/applications/list) named `lightnet-relay`, and a version with:

* image `registry.edgegap.com/<project>/lightnet-relay` and your tag,
* your Container Registry username and token, so Edgegap can pull your image,
* resources 0.25 vCPU and 512 MB memory,
* one [port](/learn/orchestration/application-and-versions.md) `7777`, named `relay`, protocol **TCP/UDP**,
* [max duration](/learn/orchestration/application-and-versions.md) 30 minutes for testing.

{% hint style="warning" %}
Use one port entry with protocol **TCP/UDP**, not separate `7777` TCP and `7777` UDP entries. Edgegap then gives TCP and UDP the same external port, so players only need one port number.
{% endhint %}

Optional relay settings, as [environment variables on the app version](/learn/orchestration/application-and-versions.md#injected-variables):

| Variable                  | Default | What it does                                                  |
| ------------------------- | ------- | ------------------------------------------------------------- |
| `RELAY_TCP_PORT`          | `7777`  | port for reliable messages                                    |
| `RELAY_UDP_PORT`          | `7777`  | port for unreliable messages                                  |
| `RELAY_MAX_PEERS`         | `256`   | maximum concurrent connections, across all rooms              |
| `RELAY_IDLE_EXIT_SECONDS` | `0`     | stop the relay when no room exists for this long, `0` = never |

✅ You may now proceed to the next step.

### 4. Deploy and Play

☑️ [Deploy your new app version](https://app.edgegap.com/deployment-management/deployments/create) near your players. When it is ready, note its host name (`<id>.pr.edgegap.net`) and the external port of `relay`.

☑️ In both games, set the relay address and port on screen before connecting, or start them from the command line:

{% code collapsedlinecount="10" %}

```bash
Tanks.exe -netcode NGO -relay <id>.pr.edgegap.net -relayPort <external port> -host
Tanks.exe -netcode NGO -relay <id>.pr.edgegap.net -relayPort <external port> -join <code>
```

{% endcode %}

☑️ Host a room in the first game and join it with the code from the second.

{% hint style="info" %}
Relay log shows a player that connects and leaves right after the deployment starts: that is Edgegap's readiness check, not a player.
{% endhint %}

<figure><img src="https://3027732442-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2Fz9xjzvZwKSIp9IeC9qo8%2Fimage.png?alt=media&amp;token=e3f345ac-848d-4469-b66f-3655cd393cf3" alt=""><figcaption></figcaption></figure>

{% hint style="info" %}
The external port of your Deployment on Edgegap cloud will be chosen at random, so that a potential attacker (hacker) is slowed down and detected before they can cause damage.
{% endhint %}

{% hint style="warning" %}
**Disable VPN when testing** for more realistic conditions and receive a [low-latency deployment](/learn/orchestration/deployments.md#server-placement).
{% endhint %}

☑️ Once you verify you’re able to connect to your Deployment without issues and are done testing, **Stop your Deployment** to free up capacity in your account for the next build.

* In case you encounter issues, [inspect Dashboard logs of your deployment](https://app.edgegap.com/deployment-management/deployments/list).
* If you can’t figure out the issue, we’re hanging out in our [Community Discord](https://discord.gg/NgCnkHbsGp) and happy to help.

🙌 Congratulations on your first Deployment on Edgegap! If you’d like to learn more, keep reading.

## 🧪 Automated Test

With a Windows build and a running relay (local or on Edgegap), `e2e.sh` starts a host and a client on each netcode:

{% code collapsedlinecount="10" %}

```bash
./e2e.sh <id>.pr.edgegap.net <external port>
./e2e.sh 127.0.0.1 7777 FishNet NGO
```

{% endcode %}

The client drives and fires. A netcode passes when both games see two tanks, both received data on the reliable and unreliable channels, both saw a projectile spawn, and the host saw the client's tank move.

## 💡 Good to Know

* **How the relay forwards data** - the host's messages go to one player, and each player's messages go only to the host. Players never talk to each other directly. Reliable messages go over TCP and unreliable ones over UDP.
* **Message size** - up to 1,177 bytes per unreliable message and 16 KB per reliable message. The transports report these limits to their netcode.
* **When the host leaves** - the room closes and the relay disconnects its players. The netcodes in this sample don't migrate the host.
* **One relay or many** - one deployment serves many rooms. A lobby or matchmaker can also deploy one relay per match, near its players.
* **Changes to LightNet** - the sample's LightNet works behind NAT and port mapping: the relay answers each player's UDP traffic at the address it came from. See the repository's README for the full list.
