# Getting Started

Edgegap helps take your multiplayer game online and operate game servers cost-efficiently:

<table data-view="cards"><thead><tr><th align="center"></th><th data-hidden data-card-cover data-type="files"></th></tr></thead><tbody><tr><td align="center"><strong>1. Build your Server</strong></td><td><a href="https://3027732442-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2FkxE7UFjVLfT9Z2LPvaGQ%2Fvlcsnap-2024-05-27-20h30m21s309.png?alt=media&#x26;token=ff1fafdc-a1e0-49f2-af46-b5a1cecdb903">vlcsnap-2024-05-27-20h30m21s309.png</a></td></tr><tr><td align="center"><strong>2. Upload Build</strong></td><td><a href="https://3027732442-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2FKByjuu0ZjRUmuTD4ywVM%2Fvlcsnap-2025-05-01-11h22m45s961.png?alt=media&#x26;token=a2457add-9994-4cd8-b309-b6552ab9770b">vlcsnap-2025-05-01-11h22m45s961.png</a></td></tr><tr><td align="center"><strong>3. Deploy and Connect</strong></td><td><a href="https://3027732442-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2FYu1AvHWaQTeNwvFohVQs%2FScreenshot_86.png?alt=media&#x26;token=6a54006b-df3b-4507-ab5e-afd887776300">Screenshot_86.png</a></td></tr></tbody></table>

{% hint style="success" %}
[Register your Edgegap account for free and experience our platform today](https://app.edgegap.com/auth/register), no credit card required.
{% endhint %}

## 🚀 Getting Started

Try one of our quick start guides supported with game engine plugins:

* [unreal-engine](https://docs.edgegap.com/unreal-engine "mention"),
* [unity](https://docs.edgegap.com/unity "mention").

{% hint style="success" %}
Start with a solid foundation, using one of [our free sample projects](https://docs.edgegap.com/docs/sample-projects), easily adapted to suit your project.
{% endhint %}

## ❓ What is Game Server Hosting & Orchestration?

{% embed url="<https://youtu.be/2_vTh9b-mYw>" %}

For players to connect and play online, you will need a game server in charge of authority, game logic, and gameplay mechanics. [This can be a dedicated server (remote, cloud or bare metal) or a player host (listen server with relay, peer to peer).](https://edgegap.com/blog/explainer-series-authoritative-servers-relays-peer-to-peer-understanding-networking-types-and-their-benefits-for-each-game-types)

Edgegap orchestrate game servers worldwide across 615+ physical locations and 17+ data center providers to ensure deployment to the ideal location. Our patented strategy is the best-in-class turnkey solution to reduce latency and minimize operating (hosting) cost for game studios, thanks to our pay-per-use pricing.

## 🟢 After your first deployment

{% hint style="success" %}
See [matchmaking](https://docs.edgegap.com/learn/matchmaking "mention") and [server-browser](https://docs.edgegap.com/learn/server-browser "mention") to get started with game client integration.
{% endhint %}

To get the most out of Edgegap, see additional **Best Practices and Insights**:

* [prepare for launch - pre-launch checklist, including load testing](https://edgegap.com/blog/multiplayer-game-pre-launch-checklist),
* [scale to 14 million concurrent users in 60 minutes](https://edgegap.com/resources/performance-benchmark),
* [release updates with zero downtime and simplify DevOps](https://docs.edgegap.com/docs/gen2-matchmaker#rolling-updates-ab-tests).

## 📣 Community Discord

{% hint style="success" %}
[Join our Community Discord](https://discord.gg/MmJf8fWjnt) to network with studios and get support from our staff!
{% endhint %}


# Unreal Engine

Learn by doing and deploy your first Dedicated Server on Edgegap. By the end of this guide, you will have deployed a dedicated server with Edgegap at no cost.

Building with Docker Desktop is the fastest, easiest, and most reliable method to get started.

{% embed url="<https://youtu.be/q7ljcr9rAWE>" %}

## ✔️ Preparation

Before you get started, make sure to [create a free account with Edgegap](https://app.edgegap.com/auth/register) (no credit card required).

**Configure a few essentials on your development machine:**

<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),
* make sure to restart your computer after completing the installation.

</details>

<details>

<summary><a href="https://open.docker.com/extensions/marketplace?extensionId=edgegap/docker-extension">Install Edgegap Quickstart Docker Extension</a></summary>

* Install from Docker Desktop / Extensions / Browse or [using the link](https://open.docker.com/extensions/marketplace?extensionId=edgegap/docker-extension).

<figure><img src="https://3027732442-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2FraFWUCJWPZYvBMLieBUZ%2Fimage.png?alt=media&#x26;token=186886ac-accb-421d-b560-3ccefa7f29cb" alt=""><figcaption></figcaption></figure>

</details>

<details>

<summary><a href="https://www.unrealengine.com/en-US/ue-on-github">Gain Access to Unreal Engine resources on GitHub</a></summary>

* [Sign up for a GitHub account.](https://github.com/)
* Navigate to your [Unreal Engine linked accounts dashboard page](https://www.epicgames.com/account/connections).
* Link GitHub account with your Epic account.
  * Authorize Epic Games to access your GitHub account.
  * Accept email invitation to join Epic Games organization on GitHub.

</details>

<details>

<summary><a href="https://github.com/settings/tokens/new">Generate GitHub Personal Access Token (classic)</a></summary>

* enable only permission `[read:packages]` ,
* generate token - **store this value safely, you won't see it again**.

</details>

{% hint style="info" %}
**Confident in your server builds?** Skip to [#customize-server-image](#customize-server-image "mention") and [advanced-features](https://docs.edgegap.com/learn/advanced-features "mention").
{% endhint %}

## ⚙️ 1. Configure Project <a href="#id-1-configure-project" id="id-1-configure-project"></a>

Whether you’re using a Windows, Mac, or a Linux machine, you will **need to build your server for Linux runtime**, as most cloud providers nowadays (including Edgegap) run on Linux. Don’t worry, no Linux knowledge is required.

{% hint style="info" %}
This method doesn't require downloading Unreal Engine source code, or building it from source!
{% endhint %}

☑️ Start by **verifying your Unreal Engine version** - pre-filled with value from your project files.

☑️ **Input GitHub username and** [**PAT**](#user-content-fn-1)[^1] from [#preparation](#preparation "mention"), to download dependencies from GitHub.

<details>

<summary><a href="https://github.com/settings/tokens/new">Generate GitHub Personal Access Token (classic)</a></summary>

* enable only permission `[read:packages]` ,
* generate token - **store this value safely, you won't see it again**.

</details>

☑️ **Disable Unreal Engine version compatibility check** for dedicated servers and **set `IpNetDriver` as the default driver or the fallback driver** for replication networking:

{% hint style="warning" %}
Make sure to **input your `DefaultServerTarget`  at the end of this snippet**!
{% endhint %}

<pre data-title="Config/DefaultEngine.ini"><code><a data-footnote-ref href="#user-content-fn-2">[ConsoleVariables]</a>
net.IgnoreNetworkChecksumMismatch=1
net.CurrentHandshakeVersion=2
net.MinHandshakeVersion=2
net.VerifyNetSessionID=0
net.VerifyNetClientID=0

<a data-footnote-ref href="#user-content-fn-3">[/Script/Engine.GameEngine]</a>
!NetDriverDefinitions=ClearArray
+NetDriverDefinitions=(DefName="GameNetDriver",DriverClassName="OnlineSubsystemUtils.IpNetDriver",DriverClassNameFallback="OnlineSubsystemUtils.IpNetDriver")

<a data-footnote-ref href="#user-content-fn-4">[/Script/OnlineSubsystemUtils.IpNetDriver]</a>
MaxClientRate=1000000000
MaxInternetClientRate=1000000000
InitialConnectTimeout=120.0
MaxNetTickRate=60
NetServerMaxTickRate=60

<a data-footnote-ref href="#user-content-fn-5">[/Script/BuildSettings.BuildSettings]</a>
DefaultServerTarget=LyraServer
</code></pre>

☑️ **Restart Unreal Engine** to reload latest changes.

☑️ **Create a dedicated server target script** by copying your `<PROJECT>Editor.Target.cs` file in project root folder and renaming the copy to `<PROJECT>Server.Target.cs`.

☑️ **Replace any references to** word **`Editor`** **with** **`Server`** in your server target script.

☑️ **Modify server build defaults** by editing your server target script:

<pre data-title="Source/<PROJECT>Server.Target.cs"><code>bOverrideBuildEnvironment = true;
<a data-footnote-ref href="#user-content-fn-6">bUseLoggingInShipping = true;</a>
<a data-footnote-ref href="#user-content-fn-7">bUseChecksInShipping = false;</a>
<a data-footnote-ref href="#user-content-fn-8">bBuildWithEditorOnlyData = false;</a>
<a data-footnote-ref href="#user-content-fn-9">bUsesSlate = false;</a>
<a data-footnote-ref href="#user-content-fn-10">bCompileCEF3 = false;</a>
</code></pre>

✅ You may now proceed to the next step.

<details>

<summary>Optional: Steam Integration</summary>

To **integrate Steam**, use `IpNetDriver` as your default Net Driver and verify that the [64 bit steamclient.so for Linux](https://developer.valvesoftware.com/wiki/SteamCMD#Ubuntu) is copied to image on path `/home/ubuntu/.steam/sdk64/` .

{% hint style="success" %}
Add `steamclient.so`  linux library with a single click using our [docker extension](https://docs.edgegap.com/unreal-engine).
{% endhint %}

<a href="https://github.com/edgegap/edgegap-unreal-buildutils/raw/refs/heads/main/steamclient.so" class="button secondary" data-icon="square-down">Download steamclient.so</a>

<pre class="language-docker" data-title="Dockerfile"><code class="lang-docker">...
<a data-footnote-ref href="#user-content-fn-11">RUN mkdir -p /home/ubuntu/.steam/sdk64</a>
<a data-footnote-ref href="#user-content-fn-12">COPY ./steamclient.so /home/ubuntu/.steam/sdk64/steamclient.so</a>
<a data-footnote-ref href="#user-content-fn-13">RUN chmod 755 /home/ubuntu/.steam/sdk64/steamclient.so</a>
...
</code></pre>

{% hint style="warning" %}
**Make sure to disable steam networking, which sends packets through Steam Relay and may cause connection issues or lag spikes.** This doesn't prevent you from using other Steamworks features like Leaderboards, Achievements, Voice, or publishing your game on Steam Store.
{% endhint %}

<pre data-title="Config/DefaultEngine.ini"><code>[OnlineSubsystemSteam]
bUseSteamNetworking=false
bAllowP2PPacketRelay=false
<a data-footnote-ref href="#user-content-fn-14">SteamDevAppId=480</a>
<a data-footnote-ref href="#user-content-fn-14">SteamAppId=480</a>
</code></pre>

</details>

## 🔧 2. Build Game Server <a href="#id-2-build-game-server" id="id-2-build-game-server"></a>

Now we'll build and cook your project, and package it in an easily reusable docker image.

Working in a team of developers means sharing your code. When things go wrong, the last thing you want to hear is “it works on my machine”. Game servers have to run reliably on any machine, since a successful games’ servers will run on thousands of server machines across the world.

To help make your server reliable, we use Docker - virtualization software to ensuring that all of your server code dependencies down to the operating system level are going to be always exactly the same, no matter how or where the server is launched.

{% hint style="info" %}
We recommend watching ["Never install locally" (video)](https://www.youtube.com/watch?v=J0NuOlA2xDc\&ab_channel=Coderized). **You DON'T need to use Dockerhub with Docker**.  Docker ≠ Dockerhub. Think of Docker as a programming engine and Dockerhub as it’s App Store.
{% endhint %}

☑️ You may configure the following options (or keep defaults):

* **Image name** is a unique identifier of your choice, labeling your server build before shipping.
  * Usually, this will include the name of your game - for example “my-game-server”.
* **Image tag** is an identifier pointing to a specific version of your image.
  * The term “build artifact” is sometimes used to refer to a specific version of your image.
  * Timestamps are a great option for tagging, e.g. `2024.01.30-16.23.00-UTC`  (default).

☑️ **Build Project** once you're satisfied with your configuration. Completing this step will add a new image with your linux game server executable in your local Docker client.

✅ You may now proceed to the next step.

## 🧪 3. Test Server Locally <a href="#id-3-test-server-locally" id="id-3-test-server-locally"></a>

Let’s try deploying locally (on your machine) and connecting a game client, to make sure the server image is functioning properly before we upload and deploy (which may take a bit of time).

☑️ **Select the image tag you wish to run locally** (remote images will be downloaded). Optionally, more [docker run arguments](https://docs.docker.com/reference/cli/docker/image/build/#options) can be supplied to customize your local test:

* `-p 7777:7777/udp` - this is your local container [port mapping](https://docs.edgegap.com/learn/orchestration/application-and-versions#port-mapping),
* `-e ARBITRIUM_PORT_GAMEPORT_INTERNAL=7777`  is an [environment variable](#environment-variables) mocking a real Edgegap deployment, telling your game server the internal port to listen on for player connections.

☑️ Once you’re happy with your configuration hit **Start Local Server**. Completing this step will result in a **new container being started** on your development machine.

☑️ Now it's time to connect your Unreal Engine Editor (PIE) game client to your local server container. Open Unreal PIE console with `~`  (tilde) and connect with `open <ip>:<port>`:

* `ip`  = `localhost`  or `127.0.0.1`  (equivalent in most cases),
* `port`  = randomized external port value of the container in Docker GUI.

<figure><img src="https://3027732442-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2FCDGTUe5ests3DI3u9rTV%2Fimage.png?alt=media&#x26;token=8c4799d8-0622-4142-91a5-93fd1816149c" alt=""><figcaption></figcaption></figure>

☑️ Once you’ve verified you’re able to connect to your local server container and play without issues, you may delete the container 🗑️ to free up resources on your machine for other programs.

✅ You may now proceed to the next step.

<details>

<summary>Troubleshooting and FAQ</summary>

Can’t connect clients to server - `Request timed out.` , `请求超时` , `ConnectionFailed` , or `Port verification failed`

* First, make sure that the container is up, and there are no runtime errors in your logs.
* Please verify that your port values in the `docker run` command match.
* Please ensure that your game client is connecting to the **external port** shown on your container details page, this value will be always randomized due to security reasons.
* Please ensure you’ve renamed your target file and configured game builds as described in step [#id-1-configure-project](#id-1-configure-project "mention").

***

My container is up but I’m not able to connect for several minutes afterwards.

* Once a container is up, your game engine initialization begins. This process may take anywhere from seconds to minutes, and the server doesn’t accept to player connections during this period.
* Consider optimizing your server initialization to decrease this time period.
* Game clients should retry connection in 1 second intervals for a limited amount of time (depending on your initialization duration), after which they should return to matchmaking.
* Consider adding a loading scene so the server can perform initialization (and travel in case of Unreal Engine) at the same time as clients, while synchronizing state of both.

***

`Warning: Could not create socket for bind address`

* Please install Epic’s Steam Subsystem plugin through Fab asset store.
* When using Edgegap Integration Kit (EGIK) with SteamCore source version downloaded from github, Epic’s Steam Subsystem plugin is not included due to Epic Games plugin distribution policies.

***

I connected but my screen is completely dark.

* Verify you have the correct **Game Default Map** set under **Edit / Project Settings / Maps & Modes**.

</details>

## ☁️ 4. Publish to Edgegap <a href="#id-4-publish-to-edgegap" id="id-4-publish-to-edgegap"></a>

It’s time to ship your server online! Now that your image can successfully host players, we can upload it to Edgegap and start running it anywhere in the world. In this guide, we’ll be using [**Edgegap’s Container Registry**](https://docs.edgegap.com/learn/advanced-features/edgegap-container-registry) (storage for images).

☑️ **Choose an application name** to label and group similar images on Edgegap.

☑️ **Select the image tag you wish to publish** and **Upload Image**. Completing this step will result in uploading your server image to Edgeap Registry and a new [Application version being created](https://docs.edgegap.com/learn/orchestration/application-and-versions) in your web browser. **Make sure to create your** [**port mapping**](https://docs.edgegap.com/learn/orchestration/application-and-versions#port-mapping) **when prompted,** with the default value&#x73;**.**

{% hint style="success" %}
Found a bug and need to rebuild/publish again? Use **Rebuild from Source** to [#id-2.-build-game-server](#id-2.-build-game-server "mention") and [#id-4.-publish-to-edgegap](#id-4.-publish-to-edgegap "mention") **with the current extension input values quickly.**
{% endhint %}

✅ You may now proceed to the next step.

<details>

<summary>Troubleshooting and FAQ</summary>

`denied: adding 756.6 MiB of storage resource, which when updated to current usage of 4.3 GiB will exceed the configured upper limit of 4.7 GiB` , `failed commit on ref "layer-sha256:--------": unexpected status from PUT request to https://registry.edgegap.com/`

* Seems like you’ve run out of image storage space on [Container Registry](https://app.edgegap.com/registry-management/repositories/list). Consider removing unused build artifacts (if you have any) or optimize server build size. If using a custom Dockerfile or .dockerignore, you might be copying some unneeded files into your image.

***

`You have reached you Application limit of 2` , `Unable to update docker tag/version: You have reached you Application Version limit of 2`

* You’ve reached the limits of our Free tier, please consider upgrading your account. Alternatively, you may remove your existing resources through our [Dashboard](https://app.edgegap.com/).

***

My new application version is not listed in the plugin/extension.

* Please ensure you’ve completed app version create form in the last step.

</details>

## 🚀 5. Deploy to Cloud <a href="#id-5-deploy-to-cloud" id="id-5-deploy-to-cloud"></a>

This is the final step in this guide, after which you will have a server deployed on Edgegap cloud, to which players from anywhere in the world can connect.

☑️ **Choose an application and version** from previous step to deploy.

☑️ Once you’re ready, hit **Deploy to Cloud**, wait to reach [#id-3.-deployment-ready](https://docs.edgegap.com/learn/orchestration/deployments#id-3.-deployment-ready "mention"). Completing this step will result in a [new Deployment being started](https://app.edgegap.com/deployment-management/deployments/list) on your Edgegap account.

☑️ Verify there are no new errors in your console output. Ensure also that your [#container-logs](https://docs.edgegap.com/learn/orchestration/deployments#container-logs "mention") don’t show any errors and your [#container-metrics](https://docs.edgegap.com/learn/orchestration/deployments#container-metrics "mention") don’t indicate 100% resource utilization (vCPU or memory), otherwise new player connections may be rejected, or your server stuck in a restart loop. See troubleshooting steps below to address any issues.

☑️ Now we’ll perform the final test and **connect your Unreal Engine Editor to your cloud deployment**. Grab your **Deployment’s Host** in place of server IP and the Deployment’s **external port**, open Unreal console in game client (tilde `~`) and type `open {host}:{port}` .

<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&#x26;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](https://docs.edgegap.com/learn/orchestration/deployments#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.

<details>

<summary>Troubleshooting and FAQ</summary>

Can’t connect clients to server - `Request timed out.` , `请求超时` , `ConnectionFailed` , or `Port verification failed`

* First, make sure that the deployment is Ready, and there are no runtime exceptions or errors in your deployment log. If your deployment stopped, inspect logs in our [Dashboard](https://app.edgegap.com/deployment-management/deployments/list).
* Please verify that your port setting in your server build’s netcode settings matches the internal port in your [App version](https://app.edgegap.com/application-management/applications/list). For plugin builds, the port is set for you automatically. You can change the port mapping by editing the [App version](https://app.edgegap.com/application-management/applications/list) without rebuilding. Find your protocol in your netcode integration.
* Please ensure that your game client is connecting to the **external port** shown on your Deployment details page, this value will be always randomized due to security reasons.
* Please ensure you’ve renamed your target file and configured game builds as described in step [#id-1.-configure-project](#id-1.-configure-project "mention").
* Are you located in China and are using [Smart Fleets](https://docs.edgegap.com/docs/deployment/session/fleet-manager/fleet)? Your connection may be blocked by the Great Firewall. Consider adding a server located in China to your fleet, or using a VPN to connect.

***

My deployment is ready but I’m not able to connect for several minutes afterwards.

* Once a deployment is Ready, your game engine initialization begins. This process may take anywhere from seconds to minutes, and the server doesn’t accept to player connections during this period.
* Consider optimizing your server initialization to decrease this time period.
* Game clients should retry connection in 1 second intervals for a limited amount of time (depending on your initialization duration), after which they should return to matchmaking.
* Consider adding a loading scene so the server can perform initialization (and travel in case of Unreal Engine) at the same time as clients, while synchronizing state of both.

***

`Warning: Could not create socket for bind address`

* Please install Epic’s Steam Subsystem plugin through Fab asset store.
* When using Edgegap Integration Kit (EGIK) with SteamCore Integration Kit (SIK) source version downloaded from github, Epic’s Steam Subsystem plugin is not included due to Epic Games plugin distribution policies.

***

I connected but my screen is completely dark.

* Verify you have the correct **Game Default Map** set under **Edit / Project Settings / Maps & Modes**.
* Verify that the [Unreal Engine version compatibility check has been disabled](#id-2.-configure-game-server-builds) in `DefaultEngine.ini`.

***

My deployment stopped/restarted and I can’t access it’s logs anymore.

* In case the server process crashes due to an exception, our system will attempt restarting the server automatically. Consider testing your server locally to uncover the root cause.
* We only keep logs for the duration of the deployment, if you wish to inspect logs after deployment stops, please [integrate a third party log storage](https://docs.edgegap.com/docs/deployment/endpoint-storage).
* See [#id-5.-deployment-stopped](https://docs.edgegap.com/learn/orchestration/deployments#id-5.-deployment-stopped "mention") to discover all causes for stopping your deployment.

***

My deployment stopped automatically after X minutes.

* Free Tier deployments have a 60 minute limit, please consider upgrading your account.
* All deployments will be terminated after 24 hours of runtime following our server sanitization policy, for infrastructure maintenance, and to prevent racking up unexpected costs when deployment wasn’t shut down properly. For long-running servers, consider using [private-fleets](https://docs.edgegap.com/learn/orchestration/private-fleets "mention") with [persistence](https://docs.edgegap.com/learn/orchestration/persistence "mention").
* See [#id-5.-deployment-stopped](https://docs.edgegap.com/learn/orchestration/deployments#id-5.-deployment-stopped "mention") to discover all causes for stopping your deployment.

***

What will happen if a player leaves my deployment?

* By default, servers don’t reject player connections. Authenticating players is up to your devs, since many different methods and player authentication providers can be used.
* Game clients may store connection information locally to attempt reconnecting in case of unexpected client crashes.
* To allow players to join games in progress, consider using [#backfill](https://docs.edgegap.com/learn/matchmaking/matchmaker-in-depth#backfill "mention") or [Sessions](https://docs.edgegap.com/docs/deployment/session).

***

My server shows 100% CPU utilization after becoming ready.

* This may not be an issue, as game engines tend to perform CPU-heavy operations during server initializations. If the CPU usage doesn’t drop after 2-3 minutes from deployment start, you may need to optimize your server or increase app version resources.
* Reducing tick rate can help control CPU usage due to processing less messages.
* You’re limited to 1.5 vCPU and 3GB of memory (RAM) in Free Tier.
* You may increase allocated resources when creating a new app version. You can duplicate your App version in our Dashboard and adjust these values as needed, without rebuilding your server or image.

***

My deployment is restarting repeatedly and shows error `OOM kill`

* This is caused by exceeding allocated memory amount. Consider optimizing memory usage with object pooling, compression, or removing unneeded objects in your scene.
* You’re limited to 1.5 vCPU and 3GB of memory (RAM) in Free Tier.
* You may increase allocated resources when creating a new app version. You can duplicate your App version in our Dashboard and adjust these values as needed, without rebuilding your server or image.

***

Sometimes, my server’s memory (RAM) usage spikes to a high value, is that a problem?

* As long as you stay within the allocated app version memory amount, this is not an issue.
* Exceeding the allocated app version memory amount will cause `OOM kill` (see above).

***

Will my server performance be impacted by other servers running on the same machine?

* No, our platform ensures that allocated resources will not be used by other studios, or other servers on shared infrastructure. With Edgegap, there are no noisy neighbors.

</details>

## 👉 Next Steps

Once you have a working client/server setup, make sure to **save a copy of your project** (using version control software like git) so you can always trace back your steps in case you run into issues.

Continue reading to learn more about topics related to server lifecycle and discoverability.

### Stop Deployments

Learn about various methods to [stop deployments](https://docs.edgegap.com/learn/orchestration/deployments#id-5.-deployment-stopped) once the match concludes and players leave.

If you followed this guide and built with our Docker Extension, you can simply call method `FGenericPlatformMisc::RequestExit` . We've added a script managing your server process in the packaged image, which will automatically perform a graceful deployment shutdown.

To customize server lifecycle management, modify our [example `StartServer.sh`](https://github.com/edgegap/edgegap-unreal-buildutils/blob/main/StartServer.sh)  script.

{% hint style="info" %}
Prefer managing lifecycle from Unreal? See [#integration-kit](https://docs.edgegap.com/developer-tools#integration-kit "mention") for self-stop API blueprint.
{% endhint %}

{% hint style="warning" %}
Connect your [endpoint-storage](https://docs.edgegap.com/docs/endpoint-storage "mention") to get your deployment logs, otherwise they will be deleted!
{% endhint %}

### Injected Variables

Read useful information like deployment ID, server IP address, server location, and more; by accessing injected environment variables. Each deployment automatically includes:

* [Deployment Variables](https://docs.edgegap.com/learn/orchestration/deployments#injected-environment-variables) - automatically supplied by Edgegap,
* [Matchmaking Variables](https://docs.edgegap.com/learn/matchmaking/matchmaker-in-depth#injected-environment-variables) - automatically supplied by Edgegap when using [Matchmaker](https://docs.edgegap.com/broken-reference),
* [App Version Variables](https://docs.edgegap.com/learn/orchestration/application-and-versions#injected-variables) - custom key-value pairs configurable by you.

**Verify if the current instance is a game client or server** by checking if Edgegap variable is set:

```cpp
if (
  FPlatformMisc::GetEnvironmentVariable(TEXT("ARBITRIUM_REQUEST_ID")).empty()
)
{
  // client code
} else {
  // server code
}
```

### Profiling Servers

To understand and optimize server performance issues on Edgegap, explore [#container-logs](https://docs.edgegap.com/learn/orchestration/deployments#container-logs "mention"), [#container-metrics](https://docs.edgegap.com/learn/orchestration/deployments#container-metrics "mention"), and more [#dashboard-monitoring](https://docs.edgegap.com/learn/orchestration/deployments#dashboard-monitoring "mention") tools at your disposal.

You can also use existing Unreal Engine profiling tools with Edgegap:

* [Configure tracing in your Unreal Engine server](https://dev.epicgames.com/documentation/en-us/unreal-engine/developer-guide-to-tracing-in-unreal-engine) (built-in and custom events):
  * save trace on server disk with `-tracefile`, upload to 3rd party storage and analyze offline,
  * or stream trace data with [#port-mapping](https://docs.edgegap.com/learn/orchestration/deployments#port-mapping "mention") for internal port `1981` over UDP protocol.
* Analyze [Memory Insights](https://dev.epicgames.com/documentation/en-us/unreal-engine/memory-insights-in-unreal-engine) and [Networking Insights](https://dev.epicgames.com/documentation/en-us/unreal-engine/networking-insights-in-unreal-engine) and [#optimize-server-builds](#optimize-server-builds "mention").

### Matchmaking

Starting your Deployments manually, pasting URL and ports will not cut it for a live game.

{% hint style="success" %}
[**Read more about Matchmaking**](https://docs.edgegap.com/learn/matchmaking) **to deploy automatically, just in time**, when players come online.
{% endhint %}

### Optimize Server Builds

**Configure asset chunking to isolate client-only assets from server assets.**

* Explore [Asset Chunking techniques and recommendations](https://dev.epicgames.com/documentation/en-us/unreal-engine/preparing-assets-for-chunking-in-unreal-engine) by Epic.

**Exclude assets and plugins which are client-only, and not required for server to run.**

* Learn about [build-time asset and plugin exclusion](https://dev.epicgames.com/community/learning/tutorials/Kp1k/unreal-engine-build-time-asset-and-plugin-exclusion).

**Review your content cooking strategy.**

* Consider [Cooking on the Fly (COTF)](https://dev.epicgames.com/documentation/en-us/unreal-engine/build-operations-cooking-packaging-deploying-and-running-projects-in-unreal-engine#cookonthefly) to delay cooking client assets and speed up server builds.

**Implement Level Streaming to reduce runtime memory load.**

* If your design keeps players mostly together in the same map area, [level streaming may cut down your server's memory usage](https://dev.epicgames.com/documentation/en-us/unreal-engine/level-streaming-in-unreal-engine) by more than 60%, and improve client performance!

**Only include what you absolutely need for your server to run.**

* Copying unused files in your images results in image bloat, longer uploads, slower caching speeds, and slower overall server startup. [Review Docker image optimization suggestions](https://docs.docker.com/build-cloud/optimization/#dockerignore-files).

<details>

<summary>Example <code>.dockerignore</code> file to remove extra files.</summary>

```docker
# Compiled Object files
*.slo
*.lo
*.o
*.obj

# Precompiled Headers
*.gch
*.pch

# Compiled Dynamic libraries
*.so
*.dylib
*.dll

# Fortran module files
*.mod

# Compiled Static libraries
*.lai
*.la
*.a
*.lib

# Executables
*.exe
*.out
*.app
*.ipa

# These project files can be generated by the engine
*.xcodeproj
*.xcworkspace
*.sln
*.suo
*.opensdf
*.sdf
*.VC.db
*.VC.opendb

# Precompiled Assets
**/SourceArt/**/*.png
**/SourceArt/**/*.tga

# Builds
**/Build/*

# Whitelist PakBlacklist-<BuildConfiguration>.txt files
!**/Build/*/
**/Build/*/**
!**/Build/*/PakBlacklist*.txt

# Don't ignore icon files in Build
!**/Build/**/*.ico

# Configuration files generated by the Editor
**/Saved/*
**/Intermediate/*
**/DerivedDataCache/*
**/Binaries/*
**/Build/*
**/Releases/*
**/Packaged/*
```

</details>

**Consider using** [**multi-stage Docker builds (link)**](https://docs.docker.com/build/building/multi-stage/)**.**

* Separate large server dependencies to a separate image to reuse in multi-stage builds. Docker will cache each layer and simply reuse the previous version and skip uploading this part unless specifically instructed to do so, saving you bandwidth and time waiting for the upload to finish.
* If you’re not sure why one of your Dockerfile commands throws an error, try debugging locally. Create a new stage just before the issue happens (add a second `FROM` command), use `--target` to instruct the build process to stop at the problematic stage, and then `docker exec -it {container} /bin/bash` to enter interactive terminal inside your container. Afterwards, you can use shell commands in your base image to investigate further (e.g. `top` on ubuntu).

### Customize Server Image

We also support adding your own Dockerfile for users who need more control over their images due to build size optimization, extraneous dependencies, or requiring more complex startup process. We’ll now share a few “do it yourself” tips and best practices.

**Always make sure you are working with a functioning server build.**

* Before assuming an issue is related to the custom Dockerfile, ensure your Unity server build can be started, and that the build process in Unity didn’t throw any exceptions or errors.

**Always test locally before uploading.**

* Testing your image locally will save you lots of time while waiting for the upload to finish. It’s also entirely free ✨ as it doesn’t require any Edgegap resources.
* When testing locally, make sure to set your internal port correctly:

  ```bash
  docker run \
    -p 7777/udp \
    -e ARBITRIUM_PORTS_MAPPING='{"ports":{"gameport":{"internal":7777}}}' \
    'registry.edgegap.com/<repository>:<tag>'
  ```

**Make sure you’ve got the basics down. Every Dockerfile needs a few essential commands:**

* `FROM {image}` is your base image, for Unity projects we usually use a long-term supported Linux, but any Linux-based base image will do. These are usually public images stored on dockerhub. Dockerfile reference here. [Dockerfile reference here](https://docs.docker.com/reference/dockerfile/#from).
* `COPY {source} {destination}` to copy your linux server build from your host machine inside the image, so you can start it later on. [Dockerfile reference here](https://docs.docker.com/reference/dockerfile/#copy).
* `USER {user}` should follow after a [useradd (ubuntu) command](https://manpages.ubuntu.com/manpages/bionic/man8/useradd.8.html) or equivalent, it’s best not to run everything as `root` to be on the safer side. [Dockerfile reference here](https://docs.docker.com/reference/dockerfile/#user).
* `CMD {command}` will be the last line, most likely calling a `StartServer.sh` or some kind of startup script to make sure your server initializes correctly once everything is set up. [Dockerfile reference here](https://docs.docker.com/reference/dockerfile/#cmd).
* do NOT use `VOLUME` - you will not be able to mount any local storage this way on Edgegap, consider our Endpoint Storage feature instead and use an S3 bucket, see [Endpoint Storage](https://docs.edgegap.com/docs/deployment/endpoint-storage),
* `EXPOSE 7777/UDP`  is not required! This will not actually make the internal server port available from outside the container, it's only a hint for the developer and the port needs to be
  * published when testing locally with `docker run <image> -p 7777/udp` ,
  * or mapped in [Edgegap Port Mapping](https://docs.edgegap.com/learn/orchestration/application-and-versions#other-parameters-optional).

**Delay declaration of parameters until latest possible moment. Configurability > composability due to long server build times.** [**Apply this approach to Dockerfile commands to build and upload faster.**](https://medium.com/@esotericmeans/optimizing-your-dockerfile-dc4b7b527756)

* Scenario: you need to define parameters like deployment stage, version, game mode, map, player count per server, backup frequency, or similar.
* Bad solution: creating a separate image for every combination of your parameters. You will spend all of your time rebuilding the images with very little benefits from this approach.
* Better solution - substitute configuration parameters just in time:
  1. deployment parameters - supplied just before the deployment is made - matchmaking selectors passed as environment variables, or your custom session management system passing environment variables at deployment time,
  2. version parameters - shared for all deployments on an app version - deployment stage, artifact tag, third party secrets and endpoints, and similar; then
  3. one single image - contains and loads all configuration options when launched.

**Do NOT run databases on Edgegap deployments.**

* Edgegap deployments are not intended for long-running processes and may be terminated after a long period of runtime without prior notice. A database (even if distributed) running in this manner may be terminated and result in an irreversible loss of data. If you need a database, please consider a third party DBaaS.
* Consider using our [Managed Clusters](https://app.edgegap.com/cluster-management/clusters/list) for hosting databases and long running services.

[^1]: Personal Access Token

[^2]: disable compatibility check

[^3]: use IpNetDriver

[^4]: set client/server tick rates and timeout

[^5]: set server build as default target

[^6]: enable logs

[^7]: don't use checks

[^8]: don't package editor content

[^9]: don't package Slate UI (editor)

[^10]: don't compile CEF3 (editor)

[^11]: create parent directory

[^12]: copy the steamclient.so file

[^13]: allow executing steam client

[^14]: find in your steam publisher portal


# More Build Methods

These approaches are generally slower and require deeper understanding of Unreal Engine.

{% hint style="success" %}
See [](https://docs.edgegap.com/unreal-engine "mention") for your first steps with Unreal Engine game server hosting on Edgegap.
{% endhint %}

Explore alternative build methods suited for more advanced Unreal Engine and Edgegap users:

1. [#build-from-containers](#build-from-containers "mention") is a fast and automated method suitable for Continuous Integration.
2. [#build-from-plugin](#build-from-plugin "mention") is a legacy build method requiring building Unreal Engine from source.

## ⚡ Build with Scripts

Building with scripts is a fast, fully automated, and easy method suitable for Continuous Integration.

### Preparation <a href="#scripts-before-starting" id="scripts-before-starting"></a>

Before you get started, make sure to [create a free account with Edgegap](https://app.edgegap.com/auth/register) (no credit card required).

**Configure a few essentials on your development machine:**

<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),
* make sure to restart your computer after completing the installation.

</details>

<details>

<summary><a href="https://www.unrealengine.com/en-US/ue-on-github">Gain Access to Unreal Engine resources on GitHub</a></summary>

* [Sign up for a GitHub account.](https://github.com/)
* Navigate to your [Unreal Engine linked accounts dashboard page](https://www.epicgames.com/account/connections).
* Link GitHub account with your Epic account.
  * Authorize Epic Games to access your GitHub account.
  * Accept email invitation to join Epic Games organization on GitHub.

</details>

<details>

<summary><a href="https://github.com/settings/tokens/new">Generate GitHub Personal Access Token (classic)</a></summary>

* enable only permission `[read:packages]` ,
* generate token - **store this value safely, you won't see it again**.

</details>

### 1. Configure Project <a href="#scripts-configure-game-builds" id="scripts-configure-game-builds"></a>

Whether you’re using a Windows, Mac, or a Linux machine, you will **need to build your server for Linux runtime**, as most cloud providers nowadays (including Edgegap) run on Linux. Don’t worry, no Linux knowledge is required.

☑️ **Disable Unreal Engine version compatibility check** for dedicated servers and **set `IpNetDriver` as the default driver or the fallback driver** for replication networking:

{% hint style="warning" %}
Make sure to **input your `DefaultServerTarget`  at the end of this snippet**!
{% endhint %}

<pre data-title="Config/DefaultEngine.ini"><code><a data-footnote-ref href="#user-content-fn-1">[ConsoleVariables]</a>
net.IgnoreNetworkChecksumMismatch=1
net.CurrentHandshakeVersion=2
net.MinHandshakeVersion=2
net.VerifyNetSessionID=0
net.VerifyNetClientID=0

<a data-footnote-ref href="#user-content-fn-2">[/Script/Engine.GameEngine]</a>
!NetDriverDefinitions=ClearArray
+NetDriverDefinitions=(DefName="GameNetDriver",DriverClassName="OnlineSubsystemUtils.IpNetDriver",DriverClassNameFallback="OnlineSubsystemUtils.IpNetDriver")

<a data-footnote-ref href="#user-content-fn-3">[/Script/OnlineSubsystemUtils.IpNetDriver]</a>
MaxClientRate=1000000000
MaxInternetClientRate=1000000000
InitialConnectTimeout=120.0
MaxNetTickRate=60
NetServerMaxTickRate=60

<a data-footnote-ref href="#user-content-fn-4">[/Script/BuildSettings.BuildSettings]</a>
DefaultServerTarget=LyraServer
</code></pre>

☑️ **Restart Unreal Engine** to reload latest changes.

☑️ **Create a dedicated server target script** by copying your `<PROJECT>Editor.Target.cs` file in project root folder and renaming the copy to `<PROJECT>Server.Target.cs`.

☑️ **Replace any references to** word **`Editor`** **with** **`Server`** in your server target script.

☑️ **Modify server build defaults** by editing your server target script:

<pre data-title="Source/<PROJECT>Server.Target.cs"><code>bOverrideBuildEnvironment = true;
<a data-footnote-ref href="#user-content-fn-5">bUseLoggingInShipping = true;</a>
<a data-footnote-ref href="#user-content-fn-6">bUseChecksInShipping = false;</a>
<a data-footnote-ref href="#user-content-fn-7">bBuildWithEditorOnlyData = false;</a>
<a data-footnote-ref href="#user-content-fn-8">bUsesSlate = false;</a>
<a data-footnote-ref href="#user-content-fn-9">bCompileCEF3 = false;</a>
</code></pre>

✅ You may now proceed to the next step.

<details>

<summary>Optional: Steam Integration</summary>

To **integrate Steam**, use `IpNetDriver` as your default Net Driver and verify that the [64 bit steamclient.so for Linux](https://developer.valvesoftware.com/wiki/SteamCMD#Ubuntu) is copied to image on path `/home/ubuntu/.steam/sdk64/` .

{% hint style="success" %}
Add `steamclient.so`  linux library with a single click using our [docker extension](https://docs.edgegap.com/unreal-engine).
{% endhint %}

<a href="https://github.com/edgegap/edgegap-unreal-buildutils/raw/refs/heads/main/steamclient.so" class="button secondary" data-icon="square-down">Download steamclient.so</a>

<pre class="language-docker" data-title="Dockerfile"><code class="lang-docker">...
<a data-footnote-ref href="#user-content-fn-10">RUN mkdir -p /home/ubuntu/.steam/sdk64</a>
<a data-footnote-ref href="#user-content-fn-11">COPY ./steamclient.so /home/ubuntu/.steam/sdk64/steamclient.so</a>
<a data-footnote-ref href="#user-content-fn-12">RUN chmod 755 /home/ubuntu/.steam/sdk64/steamclient.so</a>
...
</code></pre>

{% hint style="warning" %}
**Make sure to disable steam networking, which sends packets through Steam Relay and may cause connection issues or lag spikes.** This doesn't prevent you from using other Steamworks features like Leaderboards, Achievements, Voice, or publishing your game on Steam Store.
{% endhint %}

<pre data-title="Config/DefaultEngine.ini"><code>[OnlineSubsystemSteam]
bUseSteamNetworking=false
bAllowP2PPacketRelay=false
<a data-footnote-ref href="#user-content-fn-13">SteamDevAppId=480</a>
<a data-footnote-ref href="#user-content-fn-13">SteamAppId=480</a>
</code></pre>

</details>

### 2. Build and Publish <a href="#scripts-build-and-upload-to-edgegap" id="scripts-build-and-upload-to-edgegap"></a>

Working in a team of developers means sharing your code. When things go wrong, the last thing you want to hear is “it works on my machine”. Game servers have to run reliably on any machine, since a successful games’ servers will run on thousands of server machines across the world.

To help make your server reliable, we use Docker - virtualization software to ensuring that all of your server code dependencies down to the operating system level are going to be always exactly the same, no matter how or where the server is launched.

{% hint style="info" %}
We recommend watching ["Never install locally" (video)](https://www.youtube.com/watch?v=J0NuOlA2xDc\&ab_channel=Coderized). **You DON'T need to use Dockerhub with Docker**.  Docker ≠ Dockerhub. Think of Docker as a programming engine and Dockerhub as it’s App Store.
{% endhint %}

☑️ **Verify that Docker is installed and running.**

{% embed url="<https://github.com/edgegap/edgegap-unreal-buildutils>" %}

☑️ **Download our Edgegap Build Utils** archive including:

* platform-specific build scripts:
  * `BuildAndUpload.ps1`  for Windows,
  * `BuildAndUpload.sh`  for macOS and Linux,
* `Dockerfile`  - recipe for building your docker images,
* `dockerignore`  - list of noncritical files to remove and speed up builds,
* `StartServer.sh`  - utility script managing your Unreal Engine lifecycle on runtime.

☑️ **Move the `edgegap-unreal-buildutils` folder to your project root directory.**

☑️ **Edit the `BuildAndUpload`  script for your platform** to configure:

* github credentials used to pull pre-built Unreal Engine images for Linux Servers,
* project details - engine version, server configuration, .uproject file name,
* [Edgegap Registry](https://app.edgegap.com/registry-management/repositories/list) credentials used to upload your completed builds.

☑️ **Execute the edited script** to start build and upload process. Completing this step will add a new **image in your** [Edgegap Container Registry dashboard page in your Repository](https://app.edgegap.com/registry-management/repositories/list).

☑️ You will be automatically redirected to **create a new** [#app-versions](https://docs.edgegap.com/learn/orchestration/application-and-versions#app-versions "mention") in [dashboard](https://app.edgegap.com/application-management/applications/list)**.**

✅ You may now proceed to the next step, skip to [#test-your-server-locally](#test-your-server-locally "mention").

<details>

<summary>Troubleshooting and FAQ</summary>

`ERROR: failed to run Build function: the Dockerfile cannot be empty`

* Some plugin sources may be missing `Dockerfile` and/or `StartServer.sh` , please find a copy these files from github source version of your plugin to your local plugin.

***

`open //./pipe/dockerDesktopLinuxEngine: The system cannot find the file specified.`

* Verify that Docker is running on your development machine.

***

`invalid reference format EdgegapLog: Warning: OnContainerizeCallback: Could not generate container, message:Failed`

* Verify that your application name is set and doesn't contain trailing whitespace.
* Make sure to press Enter to confirm the input value when done editing.

***

[**Couldn’t find target rules file for target ‘ProjectName’ when building a project?**](https://forums.unrealengine.com/t/how-may-i-resolve-an-error-couldnt-find-target-rules-file-for-target-projectname-when-building-a-project/411707)

* Change build configuration in your `XYZServerTarget.cs` file:

```
BuildConfig = EProjectPackagingBuildConfigurations::PPBC_Shipping;
```

***

`403 Forbidden, Could not push container, message:Failed`

* Please verify your docker credentials are correctly set.
* If using Edgegap Container Registry, ensure the username doesn’t include `app-version-pull` , which is the profile only allowing pulling images. Your profile should resemble your account email instead.
* Verify that you have enough free space in your account’s [Container Registry](https://app.edgegap.com/registry-management/repositories/list). We recommend trying to [#optimize-server-build-size](#optimize-server-build-size "mention"), and using [our API to delete older images](https://docs.edgegap.com/api/#tag/Container-Registry/operation/image-tag-delete). Images are stored on your local machine until deleted for backups.

</details>

## ⚡ Build from Plugin <a href="#build-from-plugin" id="build-from-plugin"></a>

Our legacy plugin includes advanced utilities, and requires building Unreal Engine from source.

### Preparation <a href="#plugin-before-starting" id="plugin-before-starting"></a>

Before you get started, make sure to [create a free account with Edgegap](https://app.edgegap.com/auth/register) (no credit card required).

**Configure a few essentials on your development machine:**

<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),
* make sure to restart your computer after completing the installation.

</details>

<details>

<summary><a href="https://www.unrealengine.com/en-US/ue-on-github">Gain Access to Unreal Engine resources on GitHub</a></summary>

* [Sign up for a GitHub account.](https://github.com/)
* Navigate to your [Unreal Engine linked accounts dashboard page](https://www.epicgames.com/account/connections).
* Link GitHub account with your Epic account.
  * Authorize Epic Games to access your GitHub account.
  * Accept email invitation to join Epic Games organization on GitHub.

</details>

<details>

<summary>Configure Your Development Environment</summary>

* [Download Unreal Engine source code](https://dev.epicgames.com/documentation/en-us/unreal-engine/downloading-unreal-engine-source-code#downloadingthesourcecode).
* [Set up Visual Studio](https://dev.epicgames.com/documentation/en-us/unreal-engine/setting-up-visual-studio-development-environment-for-cplusplus-projects-in-unreal-engine).

</details>

<details>

<summary>Install an Official Edgegap Unreal Engine Plugin</summary>

Choose one of the official plugins:

* download [#integration-kit](https://docs.edgegap.com/developer-tools#integration-kit "mention"),
* or download [#legacy-plugin](https://docs.edgegap.com/developer-tools#legacy-plugin "mention").

</details>

### 1. Configure Project <a href="#scripts-configure-game-builds" id="scripts-configure-game-builds"></a>

Whether you’re using a Windows, Mac, or a Linux machine, you will **need to build your server for Linux runtime**, as most cloud providers nowadays (including Edgegap) run on Linux. Don’t worry, no Linux knowledge is required.

☑️ [Build your Unreal Engine version from source](https://dev.epicgames.com/documentation/en-us/unreal-engine/building-unreal-engine-from-source) on your development machine,

* install [specific release branch (e.g. ](https://github.com/EpicGames/UnrealEngine/tree/5.5)[`5.5`](https://github.com/EpicGames/UnrealEngine/tree/5.5)[)](https://github.com/EpicGames/UnrealEngine/tree/5.5) to build on a stable foundation,
* **use Solid State Drive (SSD)** to speed up builds (from \~12+ hours to \~2+ hours),
* this is only required the first time and every time you upgrade your Unreal Engine version.

{% hint style="warning" %}
**Download branch with a git client!** Using github UI will always download the unstable `release` branch.
{% endhint %}

☑️ [Install Unreal Cross-Compiling Toolchain](https://dev.epicgames.com/documentation/en-us/unreal-engine/linux-development-requirements-for-unreal-engine) to build game servers for Linux.

☑️ **Restart your development machine**, otherwise you’ll run into errors later on!

☑️ **Disable Unreal Engine version compatibility check** for dedicated servers and **set `IpNetDriver` as the default driver or the fallback driver** for replication networking:

{% hint style="warning" %}
Make sure to **input your `DefaultServerTarget`  at the end of this snippet**!
{% endhint %}

<pre data-title="Config/DefaultEngine.ini"><code><a data-footnote-ref href="#user-content-fn-1">[ConsoleVariables]</a>
net.IgnoreNetworkChecksumMismatch=1
net.CurrentHandshakeVersion=2
net.MinHandshakeVersion=2
net.VerifyNetSessionID=0
net.VerifyNetClientID=0

<a data-footnote-ref href="#user-content-fn-2">[/Script/Engine.GameEngine]</a>
!NetDriverDefinitions=ClearArray
+NetDriverDefinitions=(DefName="GameNetDriver",DriverClassName="OnlineSubsystemUtils.IpNetDriver",DriverClassNameFallback="OnlineSubsystemUtils.IpNetDriver")

<a data-footnote-ref href="#user-content-fn-3">[/Script/OnlineSubsystemUtils.IpNetDriver]</a>
MaxClientRate=1000000000
MaxInternetClientRate=1000000000
InitialConnectTimeout=120.0
MaxNetTickRate=60
NetServerMaxTickRate=60

<a data-footnote-ref href="#user-content-fn-4">[/Script/BuildSettings.BuildSettings]</a>
DefaultServerTarget=LyraServer
</code></pre>

☑️ **Restart Unreal Engine** to reload latest changes.

☑️ **Create a dedicated server target script** by copying your `<PROJECT>Editor.Target.cs` file in project root folder and renaming the copy to `<PROJECT>Server.Target.cs`.

☑️ **Replace any references to** word **`Editor`** **with** **`Server`** in your server target script.

☑️ **Modify server build defaults** by editing your server target script:

<pre data-title="Source/<PROJECT>Server.Target.cs"><code>bOverrideBuildEnvironment = true;
<a data-footnote-ref href="#user-content-fn-5">bUseLoggingInShipping = true;</a>
<a data-footnote-ref href="#user-content-fn-6">bUseChecksInShipping = false;</a>
<a data-footnote-ref href="#user-content-fn-7">bBuildWithEditorOnlyData = false;</a>
<a data-footnote-ref href="#user-content-fn-8">bUsesSlate = false;</a>
<a data-footnote-ref href="#user-content-fn-9">bCompileCEF3 = false;</a>
</code></pre>

✅ You may now proceed to the next step.

<details>

<summary>Optional: Steam Integration</summary>

To **integrate Steam**, use `IpNetDriver` as your default Net Driver and verify that the [64 bit steamclient.so for Linux](https://developer.valvesoftware.com/wiki/SteamCMD#Ubuntu) is copied to image on path `/home/ubuntu/.steam/sdk64/` .

{% hint style="success" %}
Add `steamclient.so`  linux library with a single click using our [docker extension](https://docs.edgegap.com/unreal-engine).
{% endhint %}

<a href="https://github.com/edgegap/edgegap-unreal-buildutils/raw/refs/heads/main/steamclient.so" class="button secondary" data-icon="square-down">Download steamclient.so</a>

<pre class="language-docker" data-title="Dockerfile"><code class="lang-docker">...
<a data-footnote-ref href="#user-content-fn-10">RUN mkdir -p /home/ubuntu/.steam/sdk64</a>
<a data-footnote-ref href="#user-content-fn-11">COPY ./steamclient.so /home/ubuntu/.steam/sdk64/steamclient.so</a>
<a data-footnote-ref href="#user-content-fn-12">RUN chmod 755 /home/ubuntu/.steam/sdk64/steamclient.so</a>
...
</code></pre>

{% hint style="warning" %}
**Make sure to disable steam networking, which sends packets through Steam Relay and may cause connection issues or lag spikes.** This doesn't prevent you from using other Steamworks features like Leaderboards, Achievements, Voice, or publishing your game on Steam Store.
{% endhint %}

<pre data-title="Config/DefaultEngine.ini"><code>[OnlineSubsystemSteam]
bUseSteamNetworking=false
bAllowP2PPacketRelay=false
<a data-footnote-ref href="#user-content-fn-13">SteamDevAppId=480</a>
<a data-footnote-ref href="#user-content-fn-13">SteamAppId=480</a>
</code></pre>

</details>

### 2. Build and Publish <a href="#plugin-build-and-upload-to-edgegap" id="plugin-build-and-upload-to-edgegap"></a>

Working in a team of developers means sharing your code. When things go wrong, the last thing you want to hear is “it works on my machine”. Game servers have to run reliably on any machine, since a successful games’ servers will run on thousands of server machines across the world.

To help make your server reliable, we use Docker - virtualization software to ensuring that all of your server code dependencies down to the operating system level are going to be always exactly the same, no matter how or where the server is launched.

{% hint style="info" %}
We recommend watching ["Never install locally" (video)](https://www.youtube.com/watch?v=J0NuOlA2xDc\&ab_channel=Coderized). **You DON'T need to use Dockerhub with Docker**.  Docker ≠ Dockerhub. Think of Docker as a programming engine and Dockerhub as it’s App Store.
{% endhint %}

☑️ **Verify that Docker is installed and running.**

☑️ [Rebuild our plugin](https://dev.epicgames.com/community/learning/tutorials/qz93/unreal-engine-building-plugins) for your custom Unreal Engine version built from source.

☑️ **Copy compiled plugin** to your `Plugins` folder **in the root of your Unreal project** (not engine).

☑️ **Launch your new Unreal Engine** from Visual Studio and **open toolbar item Edit / Plugins**.

☑️ **Enable our plugin** in section **INSTALLED / Other**.

☑️ **Configure our plugin** by opening toolbar item **Edit / Project Settings / Edgegap**:

{% hint style="warning" %}
Always press enter after editing input values to **ensure they are saved correctly**.
{% endhint %}

* **API Token** is needed to upload your server to Edgegap, get one by clicking Get Token.
* **Application name** on Edgegap can match your project name or be customized, make sure to only use lowercase letters, numbers, or characters dash `-` and underscore `_`.
* **Image Path** provides optionally a custom icon for your game server on Edgegap, skip for now.
* **Version name** is useful for tracking client/server compatibility and rolling back in case of issues.
  * Timestamps are a great option for app version names, e.g. `2024.01.30-16.50.20-UTC` .
  * Multiple application versions may point to the same image tag, such as `v1.1.0` and `dev` .
  * Learn more about [application-and-versions](https://docs.edgegap.com/learn/orchestration/application-and-versions "mention") later.

{% hint style="warning" %}
**Do not reuse `latest` version** to prevent our system from deploying outdated (cached) image.
{% endhint %}

☑️ Click **Create Application.** Completing this step will result in a **new application appearing** in [Edgegap Dashboard](https://app.edgegap.com/application-management/applications/list).

☑️ Skip custom container registry settings for now, you can use third party registry later if you’d like.

☑️ Once you’re happy with your configuration hit **Build and Push**, wait for the process to finish and verify there are no new errors in your Unreal console. Completing this step will result in a **new folder appearing in your project root** - `Saved/LinuxServer`. In addition, a **new image appears now in your** [Edgegap Container Registry dashboard page underneath your Repository](https://app.edgegap.com/registry-management/repositories/list), and a new [#app-versions](https://docs.edgegap.com/learn/orchestration/application-and-versions#app-versions "mention") **appears in your** [dashboard underneath your Application](https://app.edgegap.com/application-management/applications/list)**.**

☑️ In your new application version, set environment variable `TARGET_FILE_NAME`  to match your `DefaultServerTarget`  value from step [#id-2.-configure-game-server-builds-1](#id-2.-configure-game-server-builds-1 "mention").

✅ You may now proceed to the next step.

<details>

<summary>Troubleshooting and FAQ</summary>

`ERROR: failed to run Build function: the Dockerfile cannot be empty`

* Some plugin sources may be missing `Dockerfile` and/or `StartServer.sh` , please find a copy these files from github source version of your plugin to your local plugin.

***

`open //./pipe/dockerDesktopLinuxEngine: The system cannot find the file specified.`

* Verify that Docker is running on your development machine.

***

`invalid reference format EdgegapLog: Warning: OnContainerizeCallback: Could not generate container, message:Failed`

* Verify that your application name is set and doesn't contain trailing whitespace.
* Make sure to press Enter to confirm the input value when done editing.

***

[**Couldn’t find target rules file for target ‘ProjectName’ when building a project?**](https://forums.unrealengine.com/t/how-may-i-resolve-an-error-couldnt-find-target-rules-file-for-target-projectname-when-building-a-project/411707)

* Change build configuration in your `XYZServerTarget.cs` file:

```
BuildConfig = EProjectPackagingBuildConfigurations::PPBC_Shipping;
```

***

`403 Forbidden, Could not push container, message:Failed`

* Please verify your docker credentials are correctly set.
* If using Edgegap Container Registry, ensure the username doesn’t include `app-version-pull` , which is the profile only allowing pulling images. Your profile should resemble your account email instead.
* Verify that you have enough free space in your account’s [Container Registry](https://app.edgegap.com/registry-management/repositories/list). We recommend trying to [#optimize-server-build-size](#optimize-server-build-size "mention"), and using [our API to delete older images](https://docs.edgegap.com/api/#tag/Container-Registry/operation/image-tag-delete). Images are stored on your local machine until deleted for backups.

</details>

## 👉 Next Steps

Continue to [#id-5.-deploy-to-cloud](https://docs.edgegap.com/unreal-engine/..#id-5.-deploy-to-cloud "mention") with our [Dashboard Deployment](https://app.edgegap.com/deployment-management/deployments/list) feature and learn more about stopping your deployments, injected variables and parametrization, and server discoverability.

[^1]: disable compatibility check

[^2]: use IpNetDriver

[^3]: set client/server tick rates and timeout

[^4]: set server build as default target

[^5]: enable logs

[^6]: don't use checks

[^7]: don't package editor content

[^8]: don't package Slate UI (editor)

[^9]: don't compile CEF3 (editor)

[^10]: create parent directory

[^11]: copy the steamclient.so file

[^12]: allow executing steam client

[^13]: find in your steam publisher portal


# Developer Tools

We build these tools for you with a simple mantra: “the keys to successful teams are fast iteration and frequent testing”. If you see an opportunity for improvement, please let us know in our [Community Discord](https://discord.gg/NgCnkHbsGp). We hope you will enjoy a smooth experience. :rocket:

{% hint style="info" %}
See our [Unreal Engine Samples](https://docs.edgegap.com/docs/sample-projects/unreal-engine) to use as a project starter or inspiration.
{% endhint %}

## 🐋 Docker Extension

Verify your project settings, build servers for linux, test locally or deploy to cloud, all within the comfortable graphical interface of Docker Desktop:

* [install from Docker Extension Marketplace](https://open.docker.com/extensions/marketplace?extensionId=edgegap/docker-extension) (free).

{% hint style="success" %}
**Follow along our easy guide for** [](https://docs.edgegap.com/unreal-engine "mention") **developers (includes video tutorial).**
{% endhint %}

## ⚡ Integration Kit

* Unreal Engine [#integration-kit](#integration-kit "mention"):
  * [install from Fab Marketplace](https://www.fab.com/listings/ff17ad88-12a1-49cf-9a41-31695ed11e16) (free for Personal use),
  * [import simple example blueprint](https://blueprintue.com/blueprint/m33u1okj/) and customize to your needs.

This plugin supports Unreal Engine 4.27, 5.0 and all following minor releases (5.1, 5.2, etc.):

{% hint style="success" %}
This plugin is a Verified Solution maintained by an independent partner - Betide Studio.
{% endhint %}

### ⭐ Matchmaking SDK

The Edgegap Integration Kit extends [#legacy-plugin](#legacy-plugin "mention") with more configurability and [matchmaking](https://docs.edgegap.com/learn/matchmaking "mention") integration. [See official documentation](https://egik.betide.studio/).

## ⚡ Legacy Plugin

Build and launch your dedicated game server into the cloud directly from your Unreal Editor!

* [Dedicated Servers for Unreal plugin - turnkey solution, source code, and full release notes.](https://github.com/edgegap/edgegap-unreal-plugin)

This plugin supports Unreal Engine 4.27, 5.0 and all following minor releases (5.1, 5.2, etc.).

{% hint style="success" %}
This plugin is provided 100% free of charge, under Terms and Conditions of Free Tier.
{% endhint %}


# Unity

Learn by doing and deploy your first Dedicated Server on Edgegap. By the end of this guide, you will have deployed a dedicated server with Edgegap at no cost.

{% embed url="<https://youtu.be/4FR04V4YEUk>" %}

## ✔️ Preparation

Before you get started, make sure to [create a free account with Edgegap](https://app.edgegap.com/auth/register) (no credit card required).

**Configure a few essentials on your development machine:**

<details>

<summary>Install Unity Linux Build Support Modules</summary>

* Use Unity Hub to select tab **Installs**, access **Settings** and **Add Modules** for each Unity version you intend to use with Edgegap platform:

<figure><img src="https://3027732442-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2FylRG4r8orenZrw5ijjpJ%2Fimage.png?alt=media&#x26;token=fb981825-8a15-4c07-9180-0f79a6a77a91" alt=""><figcaption></figcaption></figure>

* Scroll down to select and install the following Unity modules:
  * **Linux Build Support (IL2CPP),**
    * **Linux Build Support (Mono),**
    * **Linux Dedicated Server Build Support**

<figure><img src="https://3027732442-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2FuXtyqoLhBOk8CZJ4WdzA%2Fimage.png?alt=media&#x26;token=19e956ed-a731-420d-b911-130c334794fc" alt=""><figcaption></figcaption></figure>

</details>

<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),
* make sure to restart your computer after completing the installation.

</details>

<details>

<summary><a href="https://github.com/edgegap/edgegap-unity-plugin">Install Edgegap's Unity Dedicated Servers Quickstart Plugin</a></summary>

Please refer to [the official plugin repository](https://github.com/edgegap/edgegap-unity-plugin) for detailed instructions on installation.

{% embed url="<https://youtu.be/3a5veDyxpoE>" %}

</details>

{% hint style="info" %}
**Confident in your server builds?** Skip to [#customize-server-image](#customize-server-image "mention") or [advanced-features](https://docs.edgegap.com/learn/advanced-features "mention") for more.
{% endhint %}

## ⚙️ 1. Connect Account

☑️ Sign in and verify there are no new errors in your Unity console related to Edgegap's plugin.

✅ You may now proceed to the next step.

<details>

<summary>Troubleshooting and FAQ</summary>

`!Success: 400 BAD REQUEST - POST | https://api.edgegap.com/v1/wizard/init-quick-start - {"message": "The browser (or proxy) sent a request that this server could not understand."}`

* If you’ve installed by copying the ZIP file or used a sample project with a copy of the plugin installed this way, you will need to manually install package dependencies including the Newtonsoft JSON library, see [the official plugin repository](https://github.com/edgegap/edgegap-unity-plugin/tree/main?tab=readme-ov-file#instructions-1).
* Please contact us on [Community Discord](https://discord.gg/NgCnkHbsGp) for help if this is not the case.

</details>

## 🔧 2. Build Game Server

Whether you’re using a Windows, Mac, or a Linux machine, you will **need to build your server for Linux runtime**, as most cloud providers nowadays (including Edgegap) run on Linux. Don’t worry, no Linux knowledge is required to accomplish this with our plugin.

☑️ **Validate you have installed the required Unity Linux build tools.**

<details>

<summary>Install Unity Linux Build Support Modules</summary>

* Use Unity Hub to select tab **Installs**, access **Settings** and **Add Modules** for each Unity version you intend to use with Edgegap platform:

<figure><img src="https://3027732442-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2FylRG4r8orenZrw5ijjpJ%2Fimage.png?alt=media&#x26;token=fb981825-8a15-4c07-9180-0f79a6a77a91" alt=""><figcaption></figcaption></figure>

* Scroll down to select and install the following Unity modules:
  * **Linux Build Support (IL2CPP),**
    * **Linux Build Support (Mono),**
    * **Linux Dedicated Server Build Support**

<figure><img src="https://3027732442-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2FuXtyqoLhBOk8CZJ4WdzA%2Fimage.png?alt=media&#x26;token=19e956ed-a731-420d-b911-130c334794fc" alt=""><figcaption></figcaption></figure>

</details>

☑️ Edit Build Settings to **ensure that all of your required game scenes are included**.

{% hint style="info" %}
**Advanced Unity users** - optionally change [Unity Build Settings](https://docs.unity3d.com/Manual/BuildSettings.html). Caution! This may break your build.
{% endhint %}

☑️ Optional: add netcode-specific script for port verification and environment bootstrapping to your initial server scene from Edgegap Server Hosting menu (right-click / :heavy\_plus\_sign: in your Hierarchy window).

<figure><img src="https://3027732442-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2FZ8dV9ERoV3rczrXXUdV9%2Fimage.png?alt=media&#x26;token=f7c44a27-7521-4392-9d11-276c48410ed0" alt="" width="360"><figcaption></figcaption></figure>

{% hint style="info" %}
Once you complete step [#id-6.-deploy-a-server-on-edgegap](#id-6.-deploy-a-server-on-edgegap "mention"), the port verification script will log a warning if your netcode address or ports don't match your Edgegap [App Version Port Mapping](https://docs.edgegap.com/learn/orchestration/application-and-versions#other-parameters-optional) configuration.
{% endhint %}

{% hint style="success" %}
Server builds should use address `0.0.0.0`  and port `7777`  in your netcode transport. If you customize your port please specify the same in your [#port-mapping](https://docs.edgegap.com/learn/orchestration/application-and-versions#port-mapping "mention") once you [#id-5.-upload-to-edgegap](#id-5.-upload-to-edgegap "mention").
{% endhint %}

☑️ Once you’re happy with your configuration hit **Build server**, wait for the process to finish and verify there are no new errors in your Unity console. Completing this step will result in a **new folder appearing in your project root** - `Builds/EdgegapServer/ServerBuild` .

✅ You may now proceed to the next step.

<details>

<summary>Troubleshooting and FAQ</summary>

Unity: The only standalone targets supported are Windows x64 and OSX with OpenXR.

* Open your Packages and disable OpenXR before building your server.
* The OpenXR plugin is only required for clients and is not compatible with Linux server builds. By excluding it from your server builds you are not losing any functionality.

</details>

## 🐋 3. Containerize Server

Working in a team of developers means sharing your code. When things go wrong, the last thing you want to hear is “it works on my machine”. Game servers have to run reliably on any machine, since a successful games’ servers will run on thousands of server machines across the world.

To help make your server reliable, we use Docker - virtualization software to ensuring that all of your server code dependencies down to the operating system level are going to be always exactly the same, no matter how or where the server is launched.

{% hint style="info" %}
We recommend watching ["Never install locally" (video)](https://www.youtube.com/watch?v=J0NuOlA2xDc\&ab_channel=Coderized). **You DON'T need to use Dockerhub with Docker**.  Docker ≠ Dockerhub. Think of Docker as a programming engine and Dockerhub as it’s App Store.
{% endhint %}

☑️ For now, start by hitting the **Validate** button to ensure you’ve completed [#usage-requirements](https://docs.edgegap.com/developer-tools#usage-requirements "mention").

<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),
* make sure to restart your computer after completing the installation.

</details>

☑️ You may configure the following options (or keep defaults):

* **Build path** is the relative path to your server build artifact, let’s keep the default for now.

{% hint style="warning" %}
Docker only accepts build paths relative to your project root folder, **keep builds inside your project folder**.
{% endhint %}

* **Image name** is a unique identifier of your choice, labeling your server build before shipping.
  * Usually, this will include the name of your game - for example “my-game-server”.
* **Image tag** is an identifier pointing to a specific version of your image.
  * The term “build artifact” is sometimes used to refer to a specific version of your image.
  * Timestamps are a great option for tagging, e.g. `2024.01.30-16.23.00-UTC` .
* **Path to Dockerfile** can be used to customize the recipe for your images.
  * We recommend keeping the default setting for now, you can read more later in section [#customize-server-image](#customize-server-image "mention").
* **Optional docker build parameters** can be used to further instruct Docker on finer nuances.
  * We recommend keeping the default setting for now, you can [read more later in Docker docs](https://docs.docker.com/reference/cli/docker/image/build/#options).

☑️ Once you’re happy with your configuration hit **Containerize with Docker**, wait for the process to finish and verify there are no new errors in your Unity console. Completing this step will result in a **new image appearing in your local machine**. You can verify this either in Docker Desktop, in tab Images underneath Local (default), or in docker CLI by running `docker images` .

✅ You may now proceed to the next step.

<details>

<summary>Troubleshooting and FAQ</summary>

`/bin/bash: docker: command not found` , or `could not find Packages\com.edgegap.unity-servers-plugin\Editor`

* First, ensure you’ve completed [#usage-requirements](https://docs.edgegap.com/developer-tools#usage-requirements "mention").
* Confirm you have verified your Edgegap account, you should’ve received a verification link by email.
* Some settings may have reset after updating your Docker Desktop. Try navigating to your Docker Desktop Settings / Advanced and for “Choose how to configure the installation of Docker’s CLI tools:” select “System (requires password)”.

***

`docker build requires exactly 1 argument`

* Please verify that your image tag doesn’t contain any whitespace characters (spaces, tabs). Re-typing your image tag value will ensure you didn’t accidentally copy such characters.

***

`(HTTP code 400) unexpected - invalid tag format`

* This is a [known issue with macOS Docker version 4.33](https://github.com/docker/for-win/issues/14258), please consider rolling back to 4.32 or upgrading to 4.35.

***

`ERROR: failed to solve: ubuntu:22.04: failed to resolve source metadata for http://docker.io/library/ubuntu:22.04: failed to authorize: failed to fetch oauth token`

* Are you located in China? Your connection may be interrupted by the Great Firewall. Try running `docker pull ubuntu:22.04` in your command line manually (open command line by pressing Win+R, then type `cmd` and Enter).

***

`System.IndexOutOfRangeException: Index was outside the bounds of the array.`

* If you installed our Unity quickstart plugin by downloading ZIP, your Unity Editor cache might be broken. Try deleting your plugin copy and installing using the git URL or from Unity Asset Store. You should no longer need Newtonsoft.JSON package as it’s automatically included with the other sources.

***

My docker image size is massive (over 1GB) / tiny (below 100mb), is this okay?

* This could be okay in some cases, as long as you can run the server and connect successfully (see [#id-4.-test-your-server-locally](#id-4.-test-your-server-locally "mention")). If this is not the case, consider reviewing your build options, resetting them to defaults, and gradually adding options to see how they impact your build size. See also [#optimize-server-build-size](#optimize-server-build-size "mention").

***

I’m experiencing another issue not mentioned anywhere in this documentation.

* First, please try [updating your Edgegap plugin](https://github.com/edgegap/edgegap-unity-plugin?tab=readme-ov-file#update-the-plugin-in-unity) as we may have shipped a fix. If this doesn’t help, please contact us on our [Community Discord](https://discord.gg/NgCnkHbsGp) and we’ll promptly investigate with you.

</details>

## 🧪 4. Test Server Locally

Let’s try deploying locally (on your machine) and connecting a game client, to make sure the server image is functioning properly before we upload and deploy (which may take a bit of time).

☑️ You may configure the following options (or keep defaults):

* **Server image tag** from the previous step.
  * Defaults to the last tag you’ve built with the plugin.
* **Optional docker run parameters** can be supplied for exposing multiple ports, or running your image on macOS machines.
  * You may publish multiple ports for your container if needed, simply add the parameter `-p {internal port}/{protocol}` for each, for example `-p 8080/tcp -p 7770/udp` to publish and map your server port `8080` to a random external port for TCP connection and server port `7777` to a random external port for UDP connection at the same time.
  * **Find server port configuration in your Transport or netcode-specific settings.**
  * If you’re using a machine with ARM architecture (macOS M1, M2, M3, etc..) you should see this optional parameter included in your Optional docker build parameters: `--platform=linux/amd64` .

☑️ Once you’re happy with your configuration hit **Deploy local container**, wait for the process to finish, and verify there are no new errors in your Unity console. Completing this step will result in a **new container being started** on your development machine.

{% hint style="info" %}
For more details see Docker Desktop / Containers, or Docker CLI command `docker ps` .
{% endhint %}

☑️ Now it’s time to **connect your Unity Editor game client to your local docker container** to verify your server image is functioning properly. Find your netcode client settings and input:

* `localhost` or `127.0.0.1` (equivalent in most cases) in place of server IP,
* randomized external port value found in Docker Desktop / Containers / edgegap-server-test.

<figure><img src="https://3027732442-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2FCDGTUe5ests3DI3u9rTV%2Fimage.png?alt=media&#x26;token=8c4799d8-0622-4142-91a5-93fd1816149c" alt=""><figcaption></figcaption></figure>

☑️ Once you’ve verified you’re able to connect to your local server container and play without issues, you may delete the container 🗑️ to free up resources on your machine for other programs.

✅ You may now proceed to the next step.

<details>

<summary>Troubleshooting and FAQ</summary>

I’m unable to connect to the local docker container using my Unity Editor game client.

* First, make sure that the container status is Up and is not Restarting or Exited, which would indicate a runtime exception. If your container is not running, inspect it’s logs via Docker Desktop tab Containers (click on your container) or using `docker logs {container_id} --timestamps` via docker CLI.
* Next, please verify that your Network Manager port setting from your server build matches the published port in **Optional docker run parameters**. If it doesn’t, try resetting or manually changing the value for this input field to match `{container}` port to your Network Manager setting. Find your protocol in your netcode settings.
* Lastly, confirm that your Unity Editor game client netcode settings are using the port published in **Optional docker run parameters** (see screenshot above).

***

`(Segmentation fault) - core dumped`

* If you’re using a machine with ARM architecture (macOS M1, M2, M3, etc..) you should see this optional parameter included in your Optional docker build parameters: `--platform=linux/amd64` . If you don’t, try resetting the value for this input field.

***

`SceneId of 9120233082191360994 not found in SceneObjects.`

* This could mean that the scene you’re trying to load was not correctly included in the build, a known issue in older plugin versions. To remedy this, please try updating your netcode integration version or [updating your Edgegap plugin](https://github.com/edgegap/edgegap-unity-plugin?tab=readme-ov-file#update-the-plugin-in-unity).

***

`http2: server: error reading preface from client //./pipe/docker_engine: file has already been closed`

* This is a [known issue with older versions of Docker Desktop for Windows](https://github.com/docker/for-win/issues/13611). Please update your Docker Desktop application and try containerizing again.

***

`Curl error 35: Cert handshake failed. Fatal error. UnityTls error code: 7`

* This error indicates a root SSL certificate validation issue, a known issue in older plugin versions. To remedy this, please try [updating your Edgegap plugin](https://github.com/edgegap/edgegap-unity-plugin?tab=readme-ov-file#update-the-plugin-in-unity).

</details>

## ☁️ 5. Upload to Edgegap

It’s time to ship your server online! Now that your image can successfully host players, we can upload it to Edgegap and start running it anywhere in the world. In this guide, we’ll be using [**Edgegap’s Container Registry**](https://docs.edgegap.com/learn/advanced-features/edgegap-container-registry) (storage for images).

☑️ You may configure the following options (or keep defaults):

* **Application name** on Edgegap can match your image name or be customized.
  * We’ve chosen to copy your image name for now.
* **Application version** on Edgegap can match your tag or be customized.
  * Timestamps are a great option for app version names, e.g. `2024.01.30-16.50.20-UTC` .
  * Multiple application versions may point to the same image tag, such as `v1.1.0` and `dev` .
  * Learn more about [application-and-versions](https://docs.edgegap.com/learn/orchestration/application-and-versions "mention") later.
* **Server image name** from step [#id-3.-containerize-your-game-server](#id-3.-containerize-your-game-server "mention").
* **Server image tag** from step [#id-3.-containerize-your-game-server](#id-3.-containerize-your-game-server "mention").

{% hint style="success" %}
Find any image name and tag stored on your machine in **Docker Desktop / Images**.
{% endhint %}

☑️ Once you’re happy with your configuration hit **Upload image and create App version**, wait for the process to finish, and verify there are no new errors in your Unity console.

☑️ You will be brought to our [Dashboard](https://app.edgegap.com/), where you may configure optional settings. Completing this step will result in a [new Application version being created](https://app.edgegap.com/application-management/applications/list), and your [build artifact being tagged and uploaded to Edgegap’s Container Registry](https://app.edgegap.com/registry-management/repositories/list).

☑️ You will now be prompted to define a Port for your new Application version. Make sure to set the same server port value as in step [#id-4.-test-your-server-locally](#id-4.-test-your-server-locally "mention") from your Transport or netcode-specific settings.

✅ You may now proceed to the next step.

<details>

<summary>Troubleshooting and FAQ</summary>

`denied: adding 756.6 MiB of storage resource, which when updated to current usage of 4.3 GiB will exceed the configured upper limit of 4.7 GiB` , `failed commit on ref "layer-sha256:--------": unexpected status from PUT request to https://registry.edgegap.com/`

* Seems like you’ve run out of image storage space on [Container Registry](https://app.edgegap.com/registry-management/repositories/list). Consider removing unused build artifacts (if you have any) or optimize server build size. If using a custom Dockerfile or .dockerignore, you might be copying some unneeded files into your image.

***

`You have reached you Application limit of 2` , `Unable to update docker tag/version: You have reached you Application Version limit of 2`

* You’ve reached the limits of our Free tier, please consider upgrading your account. Alternatively, you may remove your existing resources through our [Dashboard](https://app.edgegap.com/).

***

My new application version is not listed in the plugin/extension.

* Please ensure you’ve completed app version create form in the last step.

</details>

## 🚀 6. Deploy to Cloud

This is the final step in this guide, after which you will have a server deployed on Edgegap cloud, to which players from anywhere in the world can connect.

☑️ **Choose an application and version** from previous step to deploy.

☑️ Once you’re ready, hit **Deploy to Cloud**, wait to reach [#id-3.-deployment-ready](https://docs.edgegap.com/learn/orchestration/deployments#id-3.-deployment-ready "mention"). Completing this step will result in a [new Deployment being started](https://app.edgegap.com/deployment-management/deployments/list) on your Edgegap account.

☑️ Verify there are no new errors in your console output. Ensure also that your [#container-logs](https://docs.edgegap.com/learn/orchestration/deployments#container-logs "mention") don’t show any errors and your [#container-metrics](https://docs.edgegap.com/learn/orchestration/deployments#container-metrics "mention") don’t indicate 100% resource utilization (vCPU or memory), otherwise new player connections may be rejected, or your server stuck in a restart loop. See troubleshooting steps below to address any issues.

☑️ Now we’ll perform the final test and **connect your Unity Editor game client to your cloud deployment**. Input game client connection details from the Deployment's:

* **Host** **URL** pointing to server's IP, usually in `NetworkManager` component.
* **External port** mapping to the [server's internal listen port](https://docs.edgegap.com/learn/orchestration/application-and-versions#port-mapping), usually in Transport component.

<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&#x26;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](https://docs.edgegap.com/learn/orchestration/deployments#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.

<details>

<summary>Troubleshooting and FAQ</summary>

Can’t connect clients to server - `Request timed out.` , `请求超时` , `ConnectionFailed` , or `Port verification failed`

* First, make sure that the deployment is Ready, and there are no runtime exceptions or errors in your deployment log. If your deployment stopped, inspect logs in our [Dashboard](https://app.edgegap.com/deployment-management/deployments/list).
* If you’re using Mirror netcode you need to have ["Auto Start Server”](https://mirror-networking.gitbook.io/docs/hosting/edgegap-hosting-plugin-guide#build-and-push) selected in your `NetworkManager` , rebuild, push, and redeploy your server.
* If you’re using FishNet netcode you need to enable [“Start on Headless”](https://fish-networking.gitbook.io/docs/manual/components/managers/server-manager#settings-are-general-settings-related-to-the-servermanager) in your `ServerManager`, rebuild, push, and redeploy your server.
* If you’re using Photon Fusion 2 netcode, please ensure that your server is passing the deployment public IP, external port and the `roomCode` on the server, and the same room code in the client in the [“NeworkRunner.StartGame”](https://doc.photonengine.com/fusion/current/manual/network-runner#creating-or-joining-a-room) parameter `StartGameArgs`. Deployment ID (e.g. `b63e6003b19f`) is a great choice as it’s globally unique and easily accessible to client by [Matchmaker](https://docs.edgegap.com/learn/matchmaking/matchmaker-in-depth) and [#injected-environment-variables](https://docs.edgegap.com/learn/matchmaking/matchmaker-in-depth#injected-environment-variables "mention").
* Next, please verify that your port setting in your server build’s netcode settings matches the internal port in your [App version](https://app.edgegap.com/application-management/applications/list). You can change the port mapping by editing the [App version](https://app.edgegap.com/application-management/applications/list) without rebuilding. Find your protocol in your netcode integration.
* Please ensure that your game client is connecting to the **external port** shown on your Deployment details page, this value will be always randomized due to security reasons.
* If you’re using Secure Websocket (WSS) protocol in your netcode integration, please ensure that your [App version](https://app.edgegap.com/application-management/applications/list) port configuration for the WSS port has TLS Upgrade enabled.
* Are you located in China and are using [Smart Fleets](https://docs.edgegap.com/docs/deployment/session/fleet-manager/fleet)? Your connection may be blocked by the Great Firewall. Consider adding a server located in China to your fleet, or using a VPN to connect.

***

My deployment stopped/restarted and I can’t access it’s logs anymore.

* In case the server process crashes due to an exception, our system will attempt restarting the server automatically. Consider [testing your server locally](#id-4.-test-your-server-locally) to uncover the root cause.
* We only keep logs for the duration of the deployment, if you wish to inspect logs after deployment stops, please [integrate a third party log storage](https://docs.edgegap.com/docs/deployment/endpoint-storage).
* See [#id-5.-deployment-stopped](https://docs.edgegap.com/learn/orchestration/deployments#id-5.-deployment-stopped "mention") to discover all causes for stopping your deployment.

***

My deployment stopped automatically after X minutes.

* Free Tier deployments have 60 minute limit, please consider upgrading your account.
* All deployments will be terminated after 24 hours of runtime following our server sanitization policy, for infrastructure maintenance, and to prevent racking up unexpected costs when deployment wasn’t shut down properly. For long-running servers, consider using [private-fleets](https://docs.edgegap.com/learn/orchestration/private-fleets "mention") with [persistence](https://docs.edgegap.com/learn/orchestration/persistence "mention").
* See [#id-5.-deployment-stopped](https://docs.edgegap.com/learn/orchestration/deployments#id-5.-deployment-stopped "mention") to discover all causes for stopping your deployment.

***

My deployment is ready but I’m not able to connect for several minutes afterwards.

* Once a deployment is Ready, your game engine initialization begins. This process may take anywhere from seconds to minutes, and the server doesn’t accept to player connections during this period.
* Consider optimizing your server initialization to decrease this time period.
* Game clients should retry connection in 1 second intervals for a limited amount of time (depending on your initialization duration), after which they should return to matchmaking.
* Consider adding a loading scene so the server can perform initialization (and travel in case of Unreal Engine) at the same time as clients, while synchronizing state of both.

***

My Meta Quest device throws `HTTP 0: Cannot resolve destination host` .

* When building Unity apps for Android target, your Internet Access permission may be removed from the output APK client build artifact automatically.
* Re-add the permissions in (requires rebuilding client afterwards):
  * Project Settings / OpenXR / :gear: Meta Quest Support / Force Remove Internet Permissions (uncheck).
  * Player Settings / Internet Access (set to require).

***

What will happen if a player leaves my deployment?

* By default, servers don’t reject player connections. Authenticating players is up to your devs, since many different methods and player authentication providers can be used.
* Game clients may store connection information locally to attempt reconnecting in case of unexpected client crashes.
* To allow players to join games in progress, consider using [#backfill](https://docs.edgegap.com/learn/matchmaking/matchmaker-in-depth#backfill "mention") or [Sessions](https://docs.edgegap.com/docs/deployment/session).

***

My server shows 100% CPU utilization after becoming ready.

* This may not be an issue, as game engines tend to perform CPU-heavy operations during server initializations. If the CPU usage doesn’t drop after 2-3 minutes from deployment start, you may need to optimize your server or increase app version resources.
* Reducing tick rate can impact CPU usage as the server performs less messaging operations.
* If you’re using Mirror netcode you need to have ["Auto Start Server”](https://mirror-networking.gitbook.io/docs/hosting/edgegap-hosting-plugin-guide#build-and-push) selected in your `NetworkManager` , rebuild, push, and redeploy your server.
* If you’re using FishNet netcode you need to enable [“Start on Headless”](https://fish-networking.gitbook.io/docs/manual/components/managers/server-manager#settings-are-general-settings-related-to-the-servermanager) in your `ServerManager`, rebuild, push, and redeploy your server.
* You’re limited to 1.5 vCPU and 3GB of memory (RAM) in Free Tier.
* You may increase allocated resources when creating a new app version. You can duplicate your App version in our Dashboard and adjust these values as needed, without rebuilding your server or image.

***

My deployment is restarting repeatedly and shows error `OOM kill`

* This is caused by exceeding allocated memory amount. Consider optimizing memory usage with object pooling, compression, or removing unneeded objects in your scene.
* Ensure your project is loading the default scene containing your `NetworkManager` and the scene is included in Unity’s Build Settings.
* You’re limited to 1.5 vCPU and 3GB of memory (RAM) in Free Tier.
* You may increase allocated resources when creating a new app version. You can duplicate your App version in our Dashboard and adjust these values as needed, without rebuilding your server or image.

***

Sometimes, my server’s memory (RAM) usage spikes to a high value, is that a problem?

* As long as you stay within the allocated app version memory amount, this is not an issue.
* Exceeding the allocated app version memory amount will cause `OOM kill` (see above).

***

Will my server performance be impacted by other servers running on the same machine?

* No, our platform ensures that allocated resources will not be used by other studios, or other servers on shared infrastructure. With Edgegap, there are no noisy neighbors.

</details>

## 👉 Next Steps

Once you have a working client/server setup, make sure to **save a copy of your project** (using version control software like git) so you can always trace back your steps in case you run into issues.

Continue reading to learn more about topics related to server lifecycle and discoverability.

### Stop Deployments

Learn about various methods to [stop deployments](https://docs.edgegap.com/learn/orchestration/deployments#id-5.-deployment-stopped) once the match concludes and players leave.

For graceful shutdowns, we strongly recommend implementing the self-stop API in your game:

<details>

<summary>Unity C# self-stop API code snippet example</summary>

```csharp
using System;
using System.Collections;
using UnityEngine;
using UnityEngine.Networking;

public class EdgegapSelfStop : MonoBehaviour
{
    private const int MaxRetries = 2;
    private const int TimeoutSeconds = 30;
    private string url = Environment.GetEnvironmentVariable("ARBITRIUM_DELETE_URL");
    private string token = Environment.GetEnvironmentVariable("ARBITRIUM_DELETE_TOKEN");

    public void Run()
    {
        StartCoroutine(SendDeleteWithRetry());
    }

    private IEnumerator SendDeleteWithRetry()
    {
        if (string.IsNullOrEmpty(url))
        {
            Debug.LogError("Edgegap | ARBITRIUM_DELETE_URL is not set.");
            yield break;
        }

        if (string.IsNullOrEmpty(token))
        {
            Debug.LogError("Edgegap | ARBITRIUM_DELETE_TOKEN is not set.");
            yield break;
        }

        int attempt = 0;

        while (attempt <= MaxRetries)
        {
            attempt++;

            using (UnityWebRequest request = UnityWebRequest.Delete(url))
            {
                request.timeout = TimeoutSeconds;
                request.SetRequestHeader("Authorization", token);

                yield return request.SendWebRequest();

                if (request.result == UnityWebRequest.Result.Success)
                {
                    Debug.Log("Edgegap | DELETE request succeeded.");
                    yield break;
                }

                Debug.LogWarning(
                    $"Edgegap | DELETE attempt {attempt} failed.\n" +
                    $"Result: {request.result}, Error: {request.error}"
                );

                if (attempt == MaxRetries)
                {
                    Debug.LogError("Edgegap | DELETE request failed after all retries.");
                    yield break;
                }
            }
        }
    }
}
```

</details>

{% hint style="info" %}
Your Unity Server will be restarted automatically in case of crash or running our of memory.
{% endhint %}

### Injected Variables

Read useful information like deployment ID, server IP address, server location, and more; by accessing injected environment variables. Each deployment automatically includes:

* [Deployment Variables](https://docs.edgegap.com/learn/orchestration/deployments#injected-environment-variables) - automatically supplied by Edgegap,
* [Matchmaking Variables](https://docs.edgegap.com/learn/matchmaking/matchmaker-in-depth#injected-environment-variables) - automatically supplied by Edgegap when using [Matchmaker](https://docs.edgegap.com/broken-reference),
* [App Version Variables](https://docs.edgegap.com/learn/orchestration/application-and-versions#injected-variables) - custom key-value pairs configurable by you.

**Verify if the current instance is a game client or server** by checking if Edgegap variable is set:

```csharp
if (
  string.IsNullOrEmpty(Environment.GetEnvironmentVariable("ARBITRIUM_REQUEST_ID"))
)
{
  // client code
} else {
  // server code
}
```

### Matchmaking

Starting your Deployments manually, pasting URL and ports will not cut it for a live game.

{% hint style="success" %}
[**Read more about Matchmaking**](https://docs.edgegap.com/learn/matchmaking) **to deploy automatically, just in time**, when players come online.
{% endhint %}

### Optimize Server Builds

**Rebuild only assets that changed since last build.**

Consider using [Unity’s Incremental Builds](https://docs.unity3d.com/Manual/incremental-build-pipeline.html) to speed up your build time.

* Consider using [Unity’s Incremental Builds](https://docs.unity3d.com/Manual/incremental-build-pipeline.html) to speed up your build time.

**Only include what you absolutely need for your server to run.**

* Copying unused files in your images results in image bloat, longer uploads, slower caching speeds, and slower overall server startup. [Review Docker image optimization suggestions](https://docs.docker.com/build-cloud/optimization/#dockerignore-files).

**Disable static batching of meshes to reduce image size.**

* [Disable static batching for faster builds, uploads, and deployments.](https://docs.unity3d.com/Manual/DrawCallBatching.html)

**Compress meshes to reduce image size.**

* [Set mesh compression to High for faster builds, uploads, and deployments.](https://docs.unity3d.com/6000.0/Documentation/Manual/compressing-mesh-data-optimization.html)
* Vertex compression does not impact image size.

**Implement conditional lazy-loading of resources.**

* Exclude client-only assets by [setting textures and meshes to CPU read/write disabled](https://docs.unity3d.com/6000.0/Documentation/Manual/dedicated-server-optimizations.html).
* Consider using [Unity Addressables](https://docs.unity3d.com/Packages/com.unity.addressables@2.1/manual/index.html) for your client builds to speed up builds and deployments by [loading assets just in time](https://docs.unity3d.com/Packages/com.unity.addressables@1.19/manual/LoadingAddressableAssets.html), or skipping loading some assets in server builds by checking for presence of [#injected-environment-variables](https://docs.edgegap.com/learn/orchestration/deployments#injected-environment-variables "mention").

**Consider using** [**multi-stage Docker builds (link)**](https://docs.docker.com/build/building/multi-stage/)**.**

* Separate large server dependencies to a separate image to reuse in multi-stage builds. Docker will cache each layer and simply reuse the previous version and skip uploading this part unless specifically instructed to do so, saving you bandwidth and time waiting for the upload to finish.
* If you’re not sure why one of your Dockerfile commands throws an error, try debugging locally. Create a new stage just before the issue happens (add a second `FROM` command), use `--target` to instruct the build process to stop at the problematic stage, and then `docker exec -it {container} /bin/bash` to enter interactive terminal inside your container. Afterwards, you can use shell commands in your base image to investigate further (e.g. `top` on ubuntu).

### Customize Server Image

We also support adding your own Dockerfile for users who need more control over their images due to build size optimization, extraneous dependencies, or requiring more complex startup process. You may optionally supply a path to your custom Dockerfile in step [#id-3.-containerize-your-game-server](#id-3.-containerize-your-game-server "mention"). We’ll now share a few “do it yourself” tips and best practices.

**Having issues when using Websockets, or HTTPS requests?**

* If you’re getting `Curl error 35: Cert handshake failed. Fatal error. UnityTls error code: 7` don’t despair, this is a known issue with older base (`FROM`) images including an expired root authority certificate. You can fix this by updating to a newer base image version (e.g. `ubuntu:22.04`), and running `update-ca-certificates` , add this to your Dockerfile:

  ```docker
  FROM ubuntu:22.04

  RUN apt-get install -y ca-certificates && \
      apt-get clean && \
      update-ca-certificates
  ```

**Always make sure you are working with a functioning server build.**

* Before assuming an issue is related to the custom Dockerfile, ensure your Unity server build can be started, and that the build process in Unity didn’t throw any exceptions or errors.

**Always test locally before uploading.**

* Testing your image locally will save you lots of time while waiting for the upload to finish. It’s also entirely free ✨ as it doesn’t require any Edgegap resources.
* When testing locally, make sure to set your internal port correctly:

  ```bash
  docker run \
    -p 7777/udp \
    -e ARBITRIUM_PORTS_MAPPING='{"ports":{"gameport":{"internal":7777}}}' \
    'registry.edgegap.com/<repository>:<tag>'
  ```

**Make sure you’ve got the basics down. Every Dockerfile needs a few essential commands:**

* `FROM {image}` is your base image, for Unity projects we usually use a long-term supported Linux, but any Linux-based base image will do. These are usually public images stored on dockerhub. Dockerfile reference here. [Dockerfile reference here](https://docs.docker.com/reference/dockerfile/#from).
* `COPY {source} {destination}` to copy your linux server build from your host machine inside the image, so you can start it later on. [Dockerfile reference here](https://docs.docker.com/reference/dockerfile/#copy).
* `USER {user}` should follow after a [useradd (ubuntu) command](https://manpages.ubuntu.com/manpages/bionic/man8/useradd.8.html) or equivalent, it’s best not to run everything as `root` to be on the safer side. [Dockerfile reference here](https://docs.docker.com/reference/dockerfile/#user).
* `CMD {command}` will be the last line, most likely calling a `StartServer.sh` or some kind of startup script to make sure your server initializes correctly once everything is set up. [Dockerfile reference here](https://docs.docker.com/reference/dockerfile/#cmd).
* do NOT use `VOLUME` - you will not be able to mount any local storage this way on Edgegap, consider our Endpoint Storage feature instead and use an S3 bucket, see [Endpoint Storage](https://docs.edgegap.com/docs/deployment/endpoint-storage),
* `EXPOSE 7777/UDP`  is not required! This will not actually make the internal server port available from outside the container, it's only a hint for the developer and the port needs to be
  * published when testing locally with `docker run <image> -p 7777/udp` ,
  * or mapped in [Edgegap Port Mapping](https://docs.edgegap.com/learn/orchestration/application-and-versions#other-parameters-optional).

**Delay declaration of parameters until latest possible moment. Configurability > composability due to long server build times.** [**Apply this approach to Dockerfile commands to build and upload faster.**](https://medium.com/@esotericmeans/optimizing-your-dockerfile-dc4b7b527756)

* Scenario: you need to define parameters like deployment stage, version, game mode, map, player count per server, backup frequency, or similar.
* Bad solution: creating a separate image for every combination of your parameters. You will spend all of your time rebuilding the images with very little benefits from this approach.
* Better solution - substitute configuration parameters just in time:
  1. deployment parameters - supplied just before the deployment is made - matchmaking selectors passed as environment variables, or your custom session management system passing environment variables at deployment time,
  2. version parameters - shared for all deployments on an app version - deployment stage, artifact tag, third party secrets and endpoints, and similar; then
  3. one single image - contains and loads all configuration options when launched.

**Do NOT run databases on Edgegap deployments.**

* Edgegap deployments are not intended for long-running processes and may be terminated after a long period of runtime without prior notice. A database (even if distributed) running in this manner may be terminated and result in an irreversible loss of data. If you need a database, please consider a third party DBaaS.
* Consider using our [Managed Clusters](https://app.edgegap.com/cluster-management/clusters/list) for hosting databases and long running services.

{% hint style="info" %}
Running into a wall? We’re available in our [Community Discord](https://discord.gg/MmJf8fWjnt) and happy to help.
{% endhint %}


# Developer Tools

We build these tools for you with a simple mantra: “the keys to successful teams are fast iteration and frequent testing”. If you see an opportunity for improvement, please let us know in our [Community Discord](https://discord.gg/NgCnkHbsGp). We hope you will enjoy a smooth experience. 🚀

{% hint style="info" %}
[Find real world examples](https://docs.edgegap.com/docs/sample-projects/unity-netcodes) which you can use as a project starter and modify further.
{% endhint %}

## ⚡ Dedicated Servers Quickstart Plugin

Build and launch your dedicated game server into the cloud directly from your Unity Editor!

* [Dedicated Servers for Unity plugin - turnkey solution, source code, and full release notes.](https://github.com/edgegap/edgegap-unity-plugin)

{% hint style="success" %}
This plugin is provided 100% free of charge, under Terms and Conditions of Free Tier.
{% endhint %}

All Unity3D Long Term Support (LTS) versions after 2021.3+ are officially supported.

This plugin contains features intended to help you:

* connect your Unity project to your Edgegap account,
* build your dedicated game server,
* containerize your dedicated game server,
* test your server’s docker image locally,
* configure your Edgegap application version,
* deploy a test instance of your server on Edgegap cloud.

{% hint style="info" %}
This plugin does not modify any game behavior, it’s merely a convenient dev tool for Edgegap tasks. The plugin isn't included in your builds, as it’s only used during server build preparation.
{% endhint %}

#### Installation

Please refer to [the official plugin repository](https://github.com/edgegap/edgegap-unity-plugin) for detailed instructions on installation.

{% embed url="<https://youtu.be/3a5veDyxpoE>" %}

<details>

<summary>Install Unity Linux Build Support Modules</summary>

* Use Unity Hub to select tab **Installs**, access **Settings** and **Add Modules** for each Unity version you intend to use with Edgegap platform:

<figure><img src="https://3027732442-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2FylRG4r8orenZrw5ijjpJ%2Fimage.png?alt=media&#x26;token=fb981825-8a15-4c07-9180-0f79a6a77a91" alt=""><figcaption></figcaption></figure>

* Scroll down to select and install the following Unity modules:
  * **Linux Build Support (IL2CPP),**
    * **Linux Build Support (Mono),**
    * **Linux Dedicated Server Build Support**

<figure><img src="https://3027732442-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2FuXtyqoLhBOk8CZJ4WdzA%2Fimage.png?alt=media&#x26;token=19e956ed-a731-420d-b911-130c334794fc" alt=""><figcaption></figcaption></figure>

</details>

<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),
* make sure to restart your computer after completing the installation.

</details>

{% hint style="success" %}
See [](https://docs.edgegap.com/unity "mention") to get started and for detailed instructions on plugin usage.
{% endhint %}

<details>

<summary>Troubleshooting and FAQ</summary>

Unity error: `[Package Manager Window] Error adding package: https://github.com/edgegap/edgegap-unity-plugin.git`

* To add our plugin via git URL, you will need git client installed ([#installation](#installation "mention")).

***

Unity Error: `Missing Linux Build Support`

* See [#usage-requirements](#usage-requirements "mention"), you’re most likely missing Linux Build Support modules, which you can install through Unity hub. Make sure to choose the same Unity version as your project’s.

</details>

{% hint style="info" %}
If you need help, [please reach out to us over Discord](https://discord.gg/MmJf8fWjnt). For live games support see our [ticketing system](https://edgegap.atlassian.net/servicedesk/customer/portal/3).
{% endhint %}

{% hint style="info" %}
**For plugin developers** - if you wish to detect presence of this plugin in the users Editor, you can do so using a compiler directive `#if EDGEGAP_PLUGIN_SERVERS {your code} #endif` .
{% endhint %}

## ⭐ Matchmaking SDK

* Unity [#matchmaking-sdk](#matchmaking-sdk "mention") by Edgegap:
  * [install package using Unity Package Manager for free](https://github.com/edgegap/edgegap-unity-gen2-sdk?tab=readme-ov-file#install-with-git-recommended),
  * [import simple example script](https://github.com/edgegap/edgegap-unity-gen2-sdk?tab=readme-ov-file#import-simple-example) and customize for your needs,

{% hint style="success" %}
This plugin is provided 100% free of charge, under Terms and Conditions of Free Tier.
{% endhint %}

All Unity3D Long Term Support (LTS) versions after 2021.3+ are officially supported.

This plugin contains features intended to help you:

* start and stop matchmaking with an individual ticket,
* resume matchmaking from cached server assignment,
* start matchmaking with a group,
* use [ping-beacons](https://docs.edgegap.com/learn/orchestration/ping-beacons "mention") for latency measurement,
* monitor matchmaker health.

{% hint style="success" %}
Use our [Simple Example Unity sample script](https://github.com/edgegap/edgegap-unity-gen2-sdk?tab=readme-ov-file#import-simple-example) to test Matchmaking in 5 minutes.
{% endhint %}

#### Installation

Please refer to [the official plugin repository](https://github.com/edgegap/edgegap-unity-gen2-sdk?tab=readme-ov-file#install-with-git-recommended) for detailed instructions on installation.

{% hint style="success" %}
[Add Packages directly from Unity's Editor with Git (video tutorial)](https://www.youtube.com/watch?v=ODL0DpEOiIE\&pp=ygUHZWRnZWdhcA%3D%3D).
{% endhint %}

<details>

<summary>Troubleshooting and FAQ</summary>

Unity: `[Package Manager Window] Error adding package: https://github.com/edgegap/edgegap-unity-gen2-sdk.git`

* To add our plugin via git URL, you will need git client installed ([#installation-1](#installation-1 "mention")).

***

Unity: `failed to resolve assembly: 'Edgegap.Gen2.SDK...`

* This is a known issue caused by [Unity's Burst compiler](https://docs.unity3d.com/6000.0/Documentation/Manual/com.unity.burst.html).
* Install plugin [via ZIP archive](https://github.com/edgegap/edgegap-unity-gen2-sdk/edit/main/README.md#install-via-zip-archive) and delete .asmdef in the plugin folder to resolve this.

***

Visual Studio: `type or namespace name could not be found` for Edgegap namespace.

1. In Unity Editor, navigate to **Edit / Preferences / External Tools / Generate .csproj files**.
2. Make sure you have enabled **Git packages**.
3. Click **Regenerate project files**.

</details>

{% hint style="info" %}
If you need help, [please reach out to us over Discord](https://discord.gg/MmJf8fWjnt). For live games support see our [ticketing system](https://edgegap.atlassian.net/servicedesk/customer/portal/3).
{% endhint %}

## 📫 Distributed Relay Transports library

Find a custom Transport for your netcode library to utilize Distributed Relays in peer to peer games.

[See documentation](https://docs.edgegap.com/docs/relay-transports-samples):

* Download Edgegap Relay Samples:
  * [Mirror sample](https://github.com/edgegap/unity-mirror-relay-sample),
  * [FishNet sample](https://github.com/edgegap/unity-fishnet-relay-sample),
  * [Unity NGO sample](https://github.com/edgegap/unity-ngo-relay-sample).
* [Edgegap Relay Transport Library - source code and release notes for supported netcodes.](https://github.com/edgegap/distributed-relay-examples)


# Orchestration

Orchestration and DevOps[^1] are at the core of Edgegap platform. Building strong processes around best practices is key to efficiently leveraging new technologies and services for teams of every size.

Setting up your project in the right way is paramount for long term success:

1. **Focus on your core business** instead of building hyper-reusable scaffolding around it.
2. **Minimize vendor lock-in** with cloud native approach and loose service coupling.
3. **Make your development experience enjoyable** and iterate faster with automation.

{% hint style="success" %}
Optimize your resource usage and [leverage fractional vCPU allocation](https://docs.edgegap.com/learn/application-and-versions#resource-requirements) to reduce overall server cost.
{% endhint %}

**Skip the painful trial and error phase and start with a strong foundation:**

* Create template [application-and-versions](https://docs.edgegap.com/learn/orchestration/application-and-versions "mention") to start new server [deployments](https://docs.edgegap.com/learn/orchestration/deployments "mention") within seconds.
  * Scale rapidly with [#match-bound](https://docs.edgegap.com/learn/deployments#match-bound "mention") short lived sessions,
  * or pre-scale manually with [#regional-standby](https://docs.edgegap.com/learn/deployments#regional-standby "mention") for predictable traffic.
* Establish user sessions with [matchmaking](https://docs.edgegap.com/learn/matchmaking "mention"), [server-browser](https://docs.edgegap.com/learn/server-browser "mention"), or with a custom solution.
  * Pick teammates, opponents, and servers with [ping-beacons](https://docs.edgegap.com/learn/orchestration/ping-beacons "mention") for low latency.
* Handle server state [persistence](https://docs.edgegap.com/learn/orchestration/persistence "mention") reliably to mitigate outages and rollbacks.
  * Reserve standby compute with [private-fleets](https://docs.edgegap.com/learn/orchestration/private-fleets "mention") for persistent 24/7 servers.
  * Configure and customize [managed-clusters](https://docs.edgegap.com/learn/advanced-features/managed-clusters "mention") for highly available kubernetes apps.
* Upload new server builds and manage versioning easily with our free [edgegap-container-registry](https://docs.edgegap.com/learn/advanced-features/edgegap-container-registry "mention").

Keep reading to learn more about best practices and recommendations for your setup.

[^1]: Developer Operations


# Apps and Versions

Learn about versioning and applications - concepts and best practices for deeper understanding.

## 📦 Applications

Applications encapsulate server projects. This separation of context is particularly useful if you:

* work on multiple games or non-game projects (consolidated billing),
* work on external projects as a co-developer (transfer ownership later),
* depend on multiple loosely coupled server types with different scaling patterns or requirements.

You can manage your Applications on Edgegap using our plugins, [dashboard](https://app.edgegap.com/application-management/applications/list), or our API.

{% hint style="success" %}
Explore our [Applications API reference](https://docs.edgegap.com/api/#tag/Applications), or read more about our [Management API](https://docs.edgegap.com/api/).
{% endhint %}

## 🏷️ App Versions

As you develop your application and continuously produce new builds, you will need to store each build as a separate version to:

* **maintain compatibility** between your clients and server,
* compare various aspects of your **incremental releases** (performance, user sentiment),
* test **multiple app versions simultaneously** (development, quality assurance, staging, beta).

{% hint style="info" %}
Each App version points to one build artifact of your choice. Multiple versions may point to the same build.
{% endhint %}

You can manage your App versions on Edgegap using our [dashboard](https://app.edgegap.com/application-management/applications/list), or our API.

{% hint style="success" %}
Explore our [App versions API reference](https://docs.edgegap.com/api/#tag/Applications/operation/app-version-post), or read more about [API](https://docs.edgegap.com/api/).
{% endhint %}

Each version is uniquely identified within it’s parent Application by **App version name**. You are free to decide your own naming convention. Here’s a few popular examples to inspire your choice:

* `2024.01.30-16.23.00-UTC` - timestamps are transparent for keeping many past versions,
* `1.1.0` - [semantic versioning](https://semver.org/) is a great choice to communicate scope of changes,
* `dev` , `staging`, `qa`, `prod` - keeping only the latest version per environment is very easy,
* `blue`, `green` - versions can be used as aliases for a rolling update release strategy.

{% hint style="success" %}
You can change your approach at any time, as long as you maintain client/server compatibility.
{% endhint %}

{% hint style="info" %}
You may disable any App or Version in our [dashboard](https://app.edgegap.com/application-management/applications/list) to **safeguard against human (dev) errors**.
{% endhint %}

{% hint style="info" %}
Free Tier is limited to 2 Applications, 2 versions, and 5 GB of Container Registry storage.
{% endhint %}

### Combine Versioning Strategies

Oftentimes, the best solution is a mix of versioning strategies, for example:

* using timestamps or semantic versioning for dev builds, for more granular tracking;
* keeping `staging`, `qa` and `prod` versions with environment-specific parameters;
* alternating `blue` and `green` versions as aliases for [zero matchmaking downtime updates](https://docs.edgegap.com/docs/gen2-matchmaker#rolling-updates-ab-tests).

## 🧱 Required Parameters

These fundamental parameters must be always defined.

### Resource Requirements

In addition to the **version’s name**, several parameters are required to create a new version:

* **vCPU** - how many virtual CPU units your app needs to run (1024 units = 1 vCPU),
  * **the minimum allowed vCPU amount is 0.25 vCPU (256 units),**
  * this setting can’t be edited on an existing App version, you must create a new version.
* **Memory** - how many megabytes of RAM your app needs to run (1024MB = 1GB),
  * this setting can’t be edited on an existing App version, you must create a new version.
* **GPU** - how many Graphical Processing Units your app needs to run,
  * this feature is not available yet, please contact us if you’re interested.

{% hint style="success" %}
Versions automatically include RAM in 2:1 RAM-vCPU ratio, **allowing up to 512MB of RAM per 0.25 vCPU**.
{% endhint %}

{% hint style="info" %}
Our server machines use AMD/Intel CPUs with clock speed 2.4 - 3.2 GHz, varying by location. To ensure your server has sufficient resources available, reach out on [Community Discord](https://discord.gg/MmJf8fWjnt).
{% endhint %}

### Image Details

These parameters will help our system decide which build of your server should be started later:

* **Registry** - `registry.edgegap.com` if you’re using our [Container Registry](https://docs.edgegap.com/docs/container/edgegap-container-registry),
  * to use a third party registry input your third party registry docker credentials,
  * registry serves as a shared storage service for your and other user’s repositories.
* **Image Repository** - refers to your Application’s dedicated repository,
  * find all of your repositories on our [dashboard’s Container Registry page](https://app.edgegap.com/registry-management/repositories/list),
  * each repository may include multiple tags of your server image.
* **Tag** - refers to a specific build artifact (version) of your server image,
  * our plugins copy the tag values from App version names by default,
  * you can view locally stored tags in Docker Desktop Images or using docker CLI.

{% hint style="danger" %}
:x: **DO NOT - overwrite existing tags or use `latest` tag** to avoid deploying outdated (cached) builds.\
:white\_check\_mark: **DO - increase your version tag always** to deploy the intended build and prevent release issues.
{% endhint %}

* **Private Registry** - if your repository’s access is protected (private repository), we’ll also need:
  * **Username Token** - your registry’s programmatic access username,
  * **Password Token** - your registry’s programmatic access password,
  * for Edgegap [Container Registry](https://docs.edgegap.com/docs/container/edgegap-container-registry), you may [copy these values from our dashboard](https://app.edgegap.com/registry-management/repositories/list),
  * these are not required for public repositories.

<details>

<summary>Troubleshooting and FAQ</summary>

I received error `401 Unauthorized` when pushing my server image.

* This means you haven’t signed in to your container registry. See Container Registry for [Edgegap Container Registry instructions](https://docs.edgegap.com/docs/container/edgegap-container-registry#getting-your-credentials), or the equivalent for your registry provider. Repeating your last operation will not resolve the error.

***

I received error `403 Forbidden` when pushing my server image.

* This means that either your currently signed in registry user doesn’t have sufficient permissions (typically to push a new image), or that you are signed into the incorrect registry provider. Try signing out and signing in with the correct provider and user with sufficient permissions. Repeating your last operation will not resolve the error.

***

What is the difference between a registry, repository, and a project?

* Think of registry as a storage facility, repository as a storage unit, and project as a storage unit number. Each registry typically includes many repositories, some public, some private to organizations and users.
* Example registry: `registry.edgegap.com` .
* Example repository: `registry.edgegap.com/my-edgegap-org/my-game-server`.
* Example project name: `my-game-server` .

***

When pushing new image tags / builds my changes are not reloading correctly.

* Make sure that every time you rebuild, you push with a new image tag. Edgegap’s internal caching system uses tag names and in case you overwrite a tag value (e.g. `latest`) it will not pick up on the new build.

***

Can I tag the same build artifact multiple times?

* Yes, you can tag the same artifact multiple times without issues, serving as multiple aliases to the same build. Keep reading to learn how to remove the tags later.

***

What happens when I delete a tag? Why can’t I delete a specific artifact using a hash?

* Deleting a tag will also cause the associated build artifact to be deleted, if there are no other tags associated with the artifact at the time of [the API request](https://docs.edgegap.com/api/#tag/Container-Registry/operation/image-tag-delete).
* Due to docker API standards and to ensure best possible user experience, we only provide an interface for deleting tags. See point above regarding deleting build artifacts.

</details>

## ⚙️ Optional Parameters

These parameters may be configured to further customize your deployments.

### Injected Variables

Custom environment variables will be injected for all deployments on this version:

* common examples include: engine arguments, third party secrets and endpoints,
* see [#injected-environment-variables](https://docs.edgegap.com/learn/deployments#injected-environment-variables "mention") for understanding different ways environment variables can be injected depending on deployment’s context, in addition to app version variables,
* each environment variable may contain up to 4KB (kilobytes) of string data.

{% hint style="warning" %}
Make sure to **set your sensitive variables (secrets, tokens) as hidden** for added security!
{% endhint %}

### Active Caching

:star2: [**Upgrade to Pay as You Go tier**](https://app.edgegap.com/user-settings?tab=memberships) **to unlock 0.5 second deployment time worldwide!**

**Speed up deployments and start servers within seconds, no standby servers required.** Server image associated with this app version will be preloaded in all of our worldwide locations automatically.

Caching will take full effect once your app version's caching level reaches 🟢 Good.

{% hint style="success" %}
Multiple app versions may reuse the same image tag. **Enabling cache for one version will enable it for all versions linked with the same image tag automatically**, making parametrized deployments easy.
{% endhint %}

{% hint style="info" %}
Image is also passively cached at deployment, only on the host machine where it was deployed.
{% endhint %}

{% hint style="warning" %}
**Images are removed from cache if they aren't deployed for 72 consecutive hours.**
{% endhint %}

### Port Mapping

Each server requires at least one port in order to accept incoming client connections:

* **Port** value refers to the **internal port** value, usually from your netcode integration,
* **Protocol** will depend on your netcode integration transport,
* **Name** is a human-readable identifier for your own needs, may be the same as Port,
* **Verifications** can be enabled to ensure your container is initialized before marked READY.

{% hint style="success" %}
Most games will only require adding a single UDP port mapping for port `7777`.
{% endhint %}

While internal ports for the server process are defined as part of app version, **external ports are assigned at random once a deployment is created**, so that a potential malicious party (hacker) is slowed down and detected before they can cause damage.

<figure><img src="https://3027732442-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2FXfDDoCk7J4O9qtkkjurh%2Fimage.png?alt=media&#x26;token=a509cc92-a410-4658-9dcd-b032497debb5" alt=""><figcaption></figcaption></figure>

{% hint style="info" %}
Add more ports in your port mapping if your server communicates over multiple protocols.
{% endhint %}

### Safety Guardrails

These parameters help with various edge cases and general server troubleshooting:

* **Time Constraints** - these features can help you manage deployments’ resource lifecycle:
  * **Game Max Duration** can be set to gracefully shut down your servers after a given period, or set to `-1`  with [app version API create/edit](https://docs.edgegap.com/docs/api/versioning#post-v1-app-app_name-version) for [persistence](https://docs.edgegap.com/learn/orchestration/persistence "mention") with [private-fleets](https://docs.edgegap.com/learn/orchestration/private-fleets "mention").
  * **Maximum time to deploy** can help you clean up deployments taking too long to start.
* **Container Log Storage** - to export server logs after deployment stops, specify pre-configured S3-compatible bucket to export your container logs,
  * see [Endpoint Storage](https://docs.edgegap.com/docs/deployment/endpoint-storage) for details on configuration and usage.

{% hint style="warning" %}
Logs of versions without external Storage will be deleted on deployment termination.
{% endhint %}

{% hint style="info" %}
Free Tier is limited to 2 Applications, 2 versions, and 5 GB of Container Registry storage.
{% endhint %}

## ⏩ Update Consistency

In order to ensure that none of the parameters change when you create a new App version through our [dashboard](https://app.edgegap.com/application-management/applications/list), we recommend using the **Duplicate** feature in the top right corner of your previous App version’s dashboard page. When duplicating, you may edit any parameters before saving.

{% hint style="success" %}
**Duplicating or editing your App versions does not require rebuilding your server image.**
{% endhint %}

{% hint style="info" %}
See [Matchmaker Rolling Updates](https://docs.edgegap.com/docs/gen2-matchmaker#rolling-updates-ab-tests) for further **automation of releases**.
{% endhint %}


# Deployments

Learn about deployments and their lifecycle - concepts and best practices for deeper understanding.

## 🗺️ Orchestration

Start new servers within seconds to meet capacity demands with our cloud native edge computing approach. We treat servers as [cattle rather than pets](https://cloudscaling.com/blog/cloud-computing/the-history-of-pets-vs-cattle/) - replacing faulty instances entirely instead of nursing each one manually.

{% hint style="info" %}
Your orchestration choice will **impact your devops cost, server cost, and scalability**.
{% endhint %}

{% hint style="success" %}
[Reach out in Discord](https://discord.gg/MmJf8fWjnt) to learn about hybrid orchestration options and optimizing your hosting cost.
{% endhint %}

To fully understand all pros and cons, let’s compare various orchestration methods.

### Match-Bound

Golden standard for modern studios providing the **easiest integration with best cost efficiency**.

👍 **Advantages**

* Best cost efficiency - scaling in real time to meet player demand minute by minute.
* Lowest devops cost due to region-less hosting, Edgegap automates 99% of tasks.
* Lowest ping due to 615+ sites in Edgegap’s public cloud infrastructure.
* Fastest scale up (burst-ability) in case of unexpected traffic spike.
* Highest standard of security and player cheating prevention (server authority).
* Minimal impact of unexpected server crash on players, only affecting a single match.

👎 **Disadvantages**

* Adopting a new orchestration mental model requires some ramp up effort initially.
* Servers running longer than 24 hours will be automatically terminated.

🧩 **Best Suited For**

* Latency-sensitive games - **when netcode optimization can't overcome high ping:**
  * First Person Shooters, Fighting Games, VR & XR (virtual and extended reality), …
* Games with an **upper limit on match duration by design**,
  * Battle Royale, PvPvE[^1], Coop Shooters, MOBA, Sports Games, ARPGs & Dungeon Crawlers, …

🔎 **Discoverability**

* Start new games when sufficient players join [matchmaking](https://docs.edgegap.com/learn/matchmaking "mention").
  * Add players to [replace leavers in existing matches with backfill](https://docs.edgegap.com/matchmaking/matchmaker-in-depth#backfill).
* Let players browse servers and pick from a list with [server-browser](https://docs.edgegap.com/learn/server-browser "mention").
* [Implement custom or third party game backend to discover servers](https://docs.edgegap.com/advanced-features/managed-clusters#nakama-by-heroic-labs).

{% hint style="info" %}
Edgegap automatically scales all 615+ server locations up/down based on player activity in each region. Prepare for success - seamlessly [scale to 14 million concurrent users in 60 minutes](https://edgegap.com/resources/performance-benchmark).
{% endhint %}

### Regional Standby

Traditional model for **persistent worlds with user-generated content and social MMO games**.

👍 **Advantages**

* Familiar and easy to understand, old-school approach for battle-scarred veterans.
* Highest standard of security and player cheating prevention (server authority).
* Easily predictable cost based on monthly commitment.

👎 **Disadvantages**

* Higher hosting cost - each region requires one or more idle standby servers (burst capacity).
* Higher devops cost - scaling, operations, and maintenance duplicated per region.
* Regions with smaller player base experience high ping due to joining servers far away.

🧩 **Best Suited For**

* Persistent worlds with user-generated content stored on server even when players go offline.
  * MMOs, Sandboxes with base building or object placement, Extraction Shooters, ...
* latency-tolerant games - **when server authoritative real-time physics aren’t required**:
  * mobile games, Coop Games, TCGs/CCGs, Turn-Based Strategies, …
* Asynchronous multiplayer, **where server crashes have minimal impact on player experience:**
  * race against ghosts, loot enemy base, timer-based building/farming games, …
* applications with heavy initialization process - when preparing servers takes minutes.

🔎 **Discoverability**

* Let players browse servers and pick from a list with [server-browser](https://docs.edgegap.com/learn/server-browser "mention").
* [Implement custom or third party game backend to discover servers](https://docs.edgegap.com/advanced-features/managed-clusters#nakama-by-heroic-labs).

{% hint style="info" %}
See [managed-clusters](https://docs.edgegap.com/learn/advanced-features/managed-clusters "mention") for **self-hosting your microservices and backend services** on Edgegap.
{% endhint %}

### Peer to Peer

Shift development efforts from ~~dedicated servers~~ to **relay netcode for non-competitive games**.

Related topics: listen servers, player-host authority, NAT punch-through.

👍 **Advantages**

* Lowest hosting cost, requiring only Relay servers to solve NAT punch-through.
* Lowest devops cost - maintenance required only for client builds and distribution channels.
* Minimal impact of unexpected server crash on players, only affecting a single match.
* Easy to implement and fast time to prototype, without any backend development required.

👎 **Disadvantages**

* Increased peer-to-peer netcode development effort requiring concurrent programming skills.
* Worst ping times and most sensitive to unfavorable network conditions (e.g. mobile internet).
* Weakest security, vulnerable to man-in-the-middle attacks and session hijacking.
* Risk dropping sessions when host leaves unless you implement custom host migration.

🧩 **Best Suited For**

* Coop & casual games - **when cheating doesn’t take away from fun or break the game**,
  * Kids Games, Exploration Games, Adventures, …

🔎 **Discoverability**

* [Implement custom or third party game backend to discover servers](https://docs.edgegap.com/advanced-features/managed-clusters#nakama-by-heroic-labs).

{% hint style="success" %}
See our [Distributed Relays](https://docs.edgegap.com/docs/distributed-relay-manager) for service enabling peer to peer with best in class latency and security.
{% endhint %}

## 📍 Server Placement

No matter which orchestration method you choose, picking the right server location for a group of players is critical in ensuring the best possible ping, and optimal player experience. Learn about different strategies for server placement, and how they impact your players.

{% hint style="info" %}
Your server placement strategy will **impact your players’ experience, retention, and your game reviews**.
{% endhint %}

{% hint style="success" %}
**Edgegap deploys in the** [**best possible location**](#server-score) **with available capacity**, for fast and low-latency matches.
{% endhint %}

<figure><img src="https://3027732442-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2FjiPRa6gGEku2oGm3qW5s%2Fimage.png?alt=media&#x26;token=306897d4-8ab1-4766-bc90-5d02882b573c" alt=""><figcaption></figcaption></figure>

{% hint style="info" %}
See [#deployment-balance-points](#deployment-balance-points "mention") to **analyze server placement in real time**, at scale.
{% endhint %}

### Server Score

Server score strategy uses Edgegap’s patented methodology, which **optimizes placement of servers for each match individually**. Performs non-intrusive telemetry to approximate each player’s network proximity to our server locations and choose the server which delivers best:

* **responsiveness** - provides lowest ping for all players on average,
* **fairness** - provides a balanced and fair ping for all players.

{% hint style="success" %}
Our [Matchmaker](https://docs.edgegap.com/learn/matchmaking) uses **Server Score strategy by default, to ensure best possible experience**. To use this strategy with [Deploy APIs](https://docs.edgegap.com/api/#tag/Deployments), input players’ public IPs or geo coordinates in your deploy request.
{% endhint %}

**Unresponsive placement** - server is far away, high ping for all players:

<figure><img src="https://3027732442-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2FNszxk3uRY78L7V6nLPlp%2Fimage.png?alt=media&#x26;token=904b9b3d-7499-45d3-81c6-cc2b5cb6dd32" alt=""><figcaption></figcaption></figure>

**Unfair placement** - uneven ping, one player is at a disadvantage:

<figure><img src="https://3027732442-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2FxjsD6ijYWHljBAVuV57w%2Fimage.png?alt=media&#x26;token=ab477e89-4afe-4203-9b7f-b85b035dc9eb" alt=""><figcaption></figcaption></figure>

**Good placement example** - responsive and fair ping for all players:

<figure><img src="https://3027732442-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2FQfSd4uo9twyxEWCkPLqu%2Fimage.png?alt=media&#x26;token=8d3cd64b-9527-48fe-886b-96393c15449d" alt=""><figcaption></figcaption></figure>

{% hint style="info" %}
This strategy is **especially effective for hosting a group of players far away from each other** (North America vs. Europe, or West coast vs. East coast), frequently the case with pre-made lobbies.
{% endhint %}

### Geolocation

Alternatively, **provide players' latitude & longitude coordinates or coordinates of a preferred server location** instead of leveraging automated telemetry. This approach requires additional client-side geo-lookup implementation, fully relying on game developer’s solution.

{% hint style="warning" %}
Geolocation strategy is not recommended for [#match-bound](#match-bound "mention") orchestration, except for applications with strict regulatory requirements for inter-regional data transfers, or when player IP is unavailable.
{% endhint %}

{% hint style="success" %}
To use this strategy with [Deploy APIs](https://docs.edgegap.com/api/#tag/Deployments), list players’ public IPs or geo coordinates in your deploy request.
{% endhint %}

### Region Lock

Servers may be placed using a crudely generalized region parameter, either:

* automatically chosen for the player, based on their metadata (player account database), or
* selected by the player during matchmaking, allowing placement with high client-server latency.

{% hint style="danger" %}
**Using this strategy alone is not recommended as it may result in poor network performance.**
{% endhint %}

{% hint style="success" %}
Using **region selection as a pre-filter in combination with another strategy** is a better alternative.
{% endhint %}

## 🟢 Connection Quality

Some games (and some players) are more sensitive to latency or lag than others. While player reports are a great indicator of incidents or regression bugs at scale, **players may lack deep understanding of networking concepts** and are quick to assign blame to studios, netcode, or servers.

Root cause of some issues may be hidden from players, so cooperation of studio and hosting provider may be crucial. **Edgegap’s priority is always to provide the best possible service.**

If you’re receiving numerous player reports, experiencing widespread outages, or repeated issues, please reach out to us immediately through a support ticket in our platform.

{% hint style="info" %}
If you need help, [please reach out to us over Discord](https://discord.gg/MmJf8fWjnt). For live games support see our [ticketing system](https://edgegap.atlassian.net/servicedesk/customer/portal/3).
{% endhint %}

#### Low Latency

Player latency is a combination of latency from transferring data between:

* **physical devices -** the physical signal travelling across [Internet networking topology](https://en.wikipedia.org/wiki/Internet#Routing),
* **host to host** - resulting from protocol, transport, and security measures,
* **process to process** - resulting from (un)boxing and processing data in client/server.

Edgegap reduces physical latency by placing servers closer to your players for shorter responses and lower number of network hops. With locations across 17 cloud and bare metal providers, you get **best-in-class ping for players anywhere in the world**.

Server and internet coverage globally (not only with Edgegap) is limited due to factors like:

* **infrastructure availability** - internet connection quality in a given region may not be sufficient,
* **natural factors** - highly complex server racks require mostly stable environment.

#### High Availability

Availability of servers in various locations around the world will vary over time, changing multiple times throughout the day. Edgegap automatically **scales up/down** locations **on demand**, considering:

* **burst traffic** - deployments made within a 15 minute period,
* **vCPU requirements** - more vCPU per deployment increases overall demand for specific location,
* **provider offering** - some remote locations have less provider options available,
* **machine availability** - some locations may only offer 4 vCPU or 8 vCPU machines,
* **studio requests** for testing, quality assurance, early access, closed betas, or tournaments.

All applications' deploy requests are combined to assess location demand. All organizations have equal allocation priority by default, with the **possibility to add private server pools for enterprise customers requiring specific hardware or locations**.

{% hint style="success" %}
Please **reach out to us to plan a release**, or if you have any requests regarding location availability.
{% endhint %}

#### Player Issue Resolution

Player issues may be rooted in server bugs or provider incidents, but may also arise from third parties such as local ISPs, game services, bugs in low level libraries, infrastructure providers, or other sources.

When troubleshooting player reports or incidents, consider factors:

* **matchmaking quality** - players should be close to each other (same region) for [#server-placement](#server-placement "mention") to yield best results:
  * see [matchmaking](https://docs.edgegap.com/learn/matchmaking "mention") and [ping-beacons](https://docs.edgegap.com/learn/orchestration/ping-beacons "mention") for our recommendations,
  * see [#player-tracing](https://docs.edgegap.com/matchmaking/matchmaker-in-depth#player-tracing "mention") to learn how to find server logs related to player reports,
* **regional issues:**
  * localized Internet Service Providers (ISPs) may be resolving an incident momentarily,
  * some regions (e.g. China, Russia) may be restricted due to localized sanctions,
* **caching level** - Edgegap will prioritize fast deployments in cached locations:
  * [activate caching to deploy your servers within seconds](https://docs.edgegap.com/learn/application-and-versions#other-parameters-optional),
* **maximum time to deploy** - deployments may fail due to slow and heavy initialization process:
  * see [#safety-guardrails](https://docs.edgegap.com/learn/application-and-versions#safety-guardrails "mention") to increase the timeout period,
  * delay initialization steps until absolutely necessary,
* **server image or integration issues**.

{% hint style="success" %}
**Display deployment IDs in client match history UI** to trace player reports when troubleshooting.
{% endhint %}

{% hint style="info" %}
Notify users about widespread bugs, temporary issues, and outages to mitigate negative sentiment.
{% endhint %}

## 🔄 Deployment Lifecycle

Edgegap deployments go through several lifecycle stages, denoted by deployment status.

#### 1. Start a Deployment

A deployment for **testing purposes** may be started with:

* [unreal-engine](https://docs.edgegap.com/unreal-engine "mention") - Docker Extension or plugin for Unreal Engine projects,
* [unity](https://docs.edgegap.com/unity "mention") - plugin for Unity projects,
* [Dashboard Web UI](https://app.edgegap.com/deployment-management/deployments/list) - easy to use web interface for testing server integration.

A deployment for **live production environment** should be started with:

* [matchmaking](https://docs.edgegap.com/learn/matchmaking "mention") - find other players and start servers on-demand ([#match-bound](#match-bound "mention")).
* [server-browser](https://docs.edgegap.com/learn/server-browser "mention") - pre-warm servers with long initialization ([#regional-standby](#regional-standby "mention")).
* [Deploy API](https://docs.edgegap.com/api/#tag/Deployments/operation/deploy) - server-to-server customized integration (custom scaling).

{% hint style="success" %}
**Save** `request_id`  **(Deployment ID) and tag Deployments** to identify and troubleshoot issues later.
{% endhint %}

{% hint style="info" %}
When testing with [Deploy API](https://docs.edgegap.com/api/#tag/Deployments/operation/deploy), you may override default Dockerfile `CMD` with custom command.
{% endhint %}

#### 2. Deploying

Once a deployment is started, our system will perform a number of steps in rapid succession:

* Telemetry - we’re measuring network responsivity from available data centers to each player,
* Deployment - we’re reserving capacity and preparing to start your server container,
* Container Boot - we’re starting the container, installing dependencies, and initializing,
* Post Processing - we’re adding log storage, monitoring, and finalizing the deployment.

{% hint style="success" %}
**Enable** [**Active Caching in your App Version**](https://docs.edgegap.com/learn/application-and-versions#active-caching) **to deploy servers within seconds.**
{% endhint %}

{% hint style="warning" %}
**Too Many Requests 429** - to ensure stability and prevent surprise invoices, we rate limit your organization at **40 req/s**. [Contact us](mailto:info@edgegap.com) to plan releases, estimate launch traffic, and prepare for success.
{% endhint %}

#### 3. Deployment Ready

Your container is fully initialized and your server is starting up now. For a few seconds to a minute, your server may be still initializing and may not respond to player requests until your game engine (or custom runtime) is fully ready to accept player connections.

{% hint style="success" %}
Once the deployment is Ready, **retry player connection until successful**, or until pre-defined client timeout.
{% endhint %}

{% hint style="danger" %}
**Unexpected crash of server will cause your server to restart automatically.** [Server state may be lost](https://docs.edgegap.com/learn/persistence#state-management).
{% endhint %}

#### 4. Deployment Error

Your deployment may end up in Error state at any point in time, for unexpected reasons. This is more likely to happen while testing your integration, or testing new server builds.

**You are not charged for deployments in Error, which are automatically stopped after 24 hours.**

Troubleshooting steps:

* Verify Edgegap Service Status with [our uptime monitoring page](https://status.edgegap.com/).
* Try testing your server container locally using Docker Desktop to rule out Edgegap issues.

{% hint style="info" %}
If you need help, [please reach out to us over Discord](https://discord.gg/MmJf8fWjnt). For live games support see our [ticketing system](https://edgegap.atlassian.net/servicedesk/customer/portal/3).
{% endhint %}

{% hint style="success" %}
**When asking for help,** **include your deployment ID and any useful details** so we can investigate promptly!
{% endhint %}

#### 5. Deployment Stopped

**We never stop your servers without your directive**, to prevent impacting your players’ experience negatively. Your deployment may be stopped for these reasons:

* **Self-Stop via** [**DELETE\_URL**](#injected-environment-variables) - deployment stopped itself after players left and match ended,
  * see [Unreal Engine](https://docs.edgegap.com/unreal-engine#stop-deployments) and [Unity](https://docs.edgegap.com/unity#stop-deployments) guides for stopping deployments correctly,
* **Stop from your backend** - your backend stopped this deployment using [Deployments API](https://docs.edgegap.com/api/#tag/Deployments/operation/deployment-delete),
* **Game Max Duration** - the allotted time in your [#safety-guardrails](https://docs.edgegap.com/learn/application-and-versions#safety-guardrails "mention") has expired,
* [private-fleets](https://docs.edgegap.com/learn/orchestration/private-fleets "mention") Host running your deployment was deleted through a scheduled action.

{% hint style="info" %}
Once a deployment is stopped, **we trigger graceful termination** by sending `SIGTERM` signal to your main process, allowing a short termination period. Once expired, a `SIGKILL` signal is sent to stop deployment.
{% endhint %}

## 👀 Observability

Allow game servers to interoperate with third parties and gain operational insights.

### Discoverability

Once Ready, deployment is assigned a URL ([fqdn](https://en.wikipedia.org/wiki/Fully_qualified_domain_name)) and an external port for each internal port.

{% hint style="success" %}
Use **deployment tags to easily mark your deployments** and [#filter-deployments](#filter-deployments "mention").
{% endhint %}

{% hint style="info" %}
**Outbound traffic (to clients or backend) from your game servers is never blocked** or filtered.
{% endhint %}

#### **Websockets (WS) and Secure Websockets (WSS)**

To use websocket-based netcode with Edgegap, you have two options:

* **managed certificate**, set up in 1 minute without writing any code:
  * configure your [application-and-versions](https://docs.edgegap.com/learn/orchestration/application-and-versions "mention") to **use Websocket (WS) and Enable TLS Upgrade,**
  * use Edgegap URL to connect clients (e.g. `https://5fa53fa00a57.pr.edgegap.net/`)
* **self-managed certificate**, if you want to use your own custom domain:
  * configure your [application-and-versions](https://docs.edgegap.com/learn/orchestration/application-and-versions "mention") to **use Secure Websocket (WSS)**,
  * configure your own TLS certificate flow with a custom DNS record (e.g. on [Cloudflare](https://www.cloudflare.com/application-services/products/ssl/)).

{% hint style="danger" %}
Uncaught server exceptions will cause the deployment's container to restart and invalidate TLS security. In such case, [stop your server](#id-5.-deployment-stopped) and [rematch players to a new deployment](https://docs.edgegap.com/matchmaking#custom-lobby). [Server state may be lost](https://docs.edgegap.com/learn/persistence#state-management).
{% endhint %}

### Injected Variables <a href="#injected-environment-variables" id="injected-environment-variables"></a>

Game servers often need additional information, such as server IP, internal port values, or other. Injecting read-only environment variables is a reliable cloud-agnostic way to pass parameters.

{% hint style="success" %}
Get variable values using [GetEnvironmentVariable in C#](https://learn.microsoft.com/en-us/dotnet/api/system.environment.getenvironmentvariable?view=net-8.0) or [GetEnvironmentVariable in C++](https://dev.epicgames.com/documentation/en-us/unreal-engine/API/Runtime/Core/GenericPlatform/FGenericPlatformMisc/GetEnvironmentVariable).
{% endhint %}

{% hint style="info" %}
See [App Version Variables](https://docs.edgegap.com/learn/application-and-versions#injected-variables) and [Matchmaker Variables](https://docs.edgegap.com/matchmaking/matchmaker-in-depth#injected-variables) in addition to Deployment Variables below.
{% endhint %}

#### **Custom Variables**

Define up to 20 custom variables for each deployment, each containing up to 4KB of string data.

{% hint style="warning" %}
**Avoid using reserved names (below), your custom variables will be overwritten otherwise!**
{% endhint %}

Access important information by reading variables injected to your servers by Edgegap:

#### **Identifiers**

* **`ARBITRIUM_REQUEST_ID`**  - e.g. `f68e011bfb01` .
  * Unique deployment ID, also referred to as request ID. Used to retrieve more information.
  * Deployment URLs always have format `{ARBITRIUM_REQUEST_ID}.pr.edgegap.net`.
* **`ARBITRIUM_PUBLIC_IP`**  - e.g. `162.254.141.66` .
  * Public IP address of this host, can be used to connect instead of URL.
* **`ARBITRIUM_HOST_ID`**  - e.g. `alpha-north-america-70364ef8` .
  * Unique identifier of the machine hosting your deployment, shared with other deployments.
* **`ARBITRIUM_DEPLOYMENT_TAGS`**  - e.g. `tag1,tag2` .
  * Comma-delimited user-defined deployment tags, [useful for easy searching and filtering](#filter-deployments).
* **`ARBITRIUM_PRIVATE_FLEET_ID`** - e.g. `PUBLIC_CLOUD` , or fleet ID if hosted on [private-fleets](https://docs.edgegap.com/learn/orchestration/private-fleets "mention").

#### Resource Specifications

* **`ARBITRIUM_HOST_IN_PRIVATE_FLEET`** - e.g. `false` , indicating if hosted on [private-fleets](https://docs.edgegap.com/learn/orchestration/private-fleets "mention").
* **`ARBITRIUM_HOST_BASE_CLOCK_FREQUENCY`**  - e.g. `2000` , processor frequency in MHz.
* **`ARBITRIUM_DEPLOYMENT_VCPU_UNITS`**  - e.g. `256`, allocated vCPU units (1024 = 1 vCPU).
* **`ARBITRIUM_DEPLOYMENT_MEMORY_MB`**  - e.g. `512`, allocated RAM in MB (1024 = 1 GB).

#### **Lifecycle Management**

* **`ARBITRIUM_DELETE_URL`**  - e.g. `https://api.edgegap.com/v1/self/stop/9f511e17/660`.
  * Callable from the deployment, [deployment will be gracefully stopped](#id-5.-deployment-stopped).
  * Requires unique one-time `ARBITRIUM_DELETE_TOKEN` in `Authorization` header.
* **`ARBITRIUM_DELETE_TOKEN`**  - e.g. `7df4cd933df87084b34ae80d8abde293`.
* **`ARBITRIUM_CONTEXT_URL`**  - e.g. `https://api.edgegap.com/v1/context/9170f5211e17/17`.
  * Only callable from the deployment, returns more deployment details.
  * Requires unique `ARBITRIUM_CONTEXT_TOKEN` in `Authorization` header.
* **`ARBITRIUM_CONTEXT_TOKEN`**  - e.g. `dfaf50b9333b9ee07b22ed247e4a17e6`.

#### **Discoverability**

* **`ARBITRIUM_PORT_GAMEPORT_INTERNAL`**  - e.g. `7777` , internal port for server listener.
* **`ARBITRIUM_PORT_GAMEPORT_EXTERNAL`**  - e.g. `31504` , external port for client connections.
  * External port values are randomized for each deployment for security purposes.
* **`ARBITRIUM_PORT_GAMEPORT_PROTOCOL`**  - e.g. `UDP` , protocol of your netcode transport.

{% hint style="success" %}
Examples assume you have named your port `gameport` (default). **Each port adds an additional set of sanitized** [#port-mapping](https://docs.edgegap.com/learn/application-and-versions#port-mapping "mention") **variables:** `@Super Port!` ⇒ `ARBITRIUM_PORT_SUPER_PORT_INTERNAL` .
{% endhint %}

* **`ARBITRIUM_BEACON_ENABLED`**  - e.g. `true`, if deploying on [private-fleets](https://docs.edgegap.com/learn/orchestration/private-fleets "mention") with [ping-beacons](https://docs.edgegap.com/learn/orchestration/ping-beacons "mention").
* **`ARBITRIUM_HOST_BEACON_PUBLIC_IP`**  - e.g. `139.177.198.69` , public IP of the closest beacon.
* **`ARBITRIUM_HOST_BEACON_PORT_UDP_EXTERNAL`**  - e.g. `30199`, for ping measurement over UDP.
* **`ARBITRIUM_HOST_BEACON_PORT_TCP_EXTERNAL`**  - e.g. `30456`, for ping measurement over TCP.

#### **Structured Information (JSON as string)**

{% hint style="info" %}
Environment variables are **stored as stringified JSONs**, parse them using an SDK or a custom method.
{% endhint %}

<details>

<summary><strong>ARBITRIUM_DEPLOYMENT_LOCATION</strong>:<br>- Detailed information about deployment location.</summary>

```json
ARBITRIUM_DEPLOYMENT_LOCATION="{
  "city": "Montreal",
  "country": "Canada",
  "continent": "North America",
  "administrative_division": "Quebec",
  "timezone": "Eastern Time",
  "latitude": 45.513707,
  "longitude": -73.619073
}"
```

</details>

<details>

<summary><strong>ARBITRIUM_PORTS_MAPPING</strong>:<br>- Detailed information about your internal and external ports.</summary>

```json
ARBITRIUM_PORTS_MAPPING="{
  "ports": {
    "gameport": {
      "name": "Game Port",
      "internal": 7777,
      "external": 31504,
      "protocol": "UDP"
    },
    "webport": {
      "name": "Web Port",
      "internal": 8888,
      "external": 31553,
      "protocol": "TCP"
    }
  }
}"
```

</details>

### Dashboard Monitoring

Our [Dashboard](https://app.edgegap.com/) provides utilities to monitor your server scalability and assist with operations.

#### Analytics

{% hint style="success" %}
Find [analytics dashboards in the sidebar menu](https://app.edgegap.com/analytics/dashboards/list) under category Server Hosting & Orchestration.
{% endhint %}

:star2: [**Upgrade to Pay as You Go tier**](https://app.edgegap.com/user-settings?tab=memberships) **to unlock detailed server performance metrics and insights:**

* **General Insights:** monitor releases with live server count per version + resource usage overview,
* **CPU Insights**: troubleshoot lagging servers due to processor-heavy operations,
* **Memory Insights**: mitigate server restarts due to exceeding allocated memory,
* **Networking Insights:** detect inefficient networking patterns and optimize netcode.

<figure><img src="https://3027732442-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2FLxDp1yFvkj5kB6AC4xVb%2Fimage.png?alt=media&#x26;token=c0eff5f1-a374-41e0-a49a-9b3ecf0bfd1b" alt=""><figcaption></figcaption></figure>

#### Deployment Map

{% hint style="success" %}
Find deployment map in [your deployment details page on Dashboard](https://app.edgegap.com/deployment-management/deployments/list).
{% endhint %}

Preview deployment location, available locations, and estimated player locations on the map:

<figure><img src="https://3027732442-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2FM4h0itPU5ntPaV5N5ZlW%2Fimage.png?alt=media&#x26;token=98028901-9a40-4a2d-969e-db5f990e334f" alt=""><figcaption></figcaption></figure>

#### Deployment Balance Points

{% hint style="success" %}
Find deployment balance points heatmap in [your application details page on Dashboard](https://app.edgegap.com/application-management/applications/list).
{% endhint %}

Preview deployment balance points heatmap and filter by [application-and-versions](https://docs.edgegap.com/learn/orchestration/application-and-versions "mention"). Balance points are approximate locations with equal network proximity to each player in a given deployment:

<figure><img src="https://3027732442-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2FfDpIQxoFUJZNE77LJIwZ%2Fimage.png?alt=media&#x26;token=94e730ad-3907-486b-8a06-0f469acd19ea" alt=""><figcaption></figcaption></figure>

{% hint style="warning" %}
Balance point hotspots in strange locations (e.g. Greenland) indicate matchmaking of players far from each other. Learn about [#connection-quality](#connection-quality "mention") and [ping-beacons](https://docs.edgegap.com/learn/orchestration/ping-beacons "mention") to optimize your matchmaking.
{% endhint %}

#### Deployment Logs

{% hint style="success" %}
Find deployment logs in [your deployment details page on Dashboard](https://app.edgegap.com/deployment-management/deployments/list).
{% endhint %}

Deployment logs display information about [#deployment-lifecycle](#deployment-lifecycle "mention"):

<figure><img src="https://3027732442-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2FfkyAYtylnOFmSp3yyiId%2Fimage.png?alt=media&#x26;token=6a4f6ac4-5780-46a7-bcdd-1d8829c4abd7" alt=""><figcaption></figcaption></figure>

#### Container Logs

{% hint style="success" %}
Find container logs in [your deployment details page on Dashboard](https://app.edgegap.com/deployment-management/deployments/list).
{% endhint %}

Inspect your game server’s logs in case of issues, or when debugging:

<figure><img src="https://3027732442-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2FTiaARmb6aAZfm0rjQmiT%2Fimage.png?alt=media&#x26;token=7eb49138-954d-44a1-a025-1f88ed855366" alt=""><figcaption></figcaption></figure>

{% hint style="warning" %}
**Once deployment stops, container logs are deleted.** Set up [third party S3 log storage](https://docs.edgegap.com/docs/endpoint-storage) to save logs.
{% endhint %}

#### Container Metrics

{% hint style="success" %}
Find container metrics in [your deployment details page on Dashboard](https://app.edgegap.com/deployment-management/deployments/list).
{% endhint %}

Review container metrics (processor, memory, networking) to:

* identify common connection issues when [#troubleshooting](#troubleshooting "mention"),
* detect inefficient implementation patterns causing spikes in resource usage,
* pinpoint inefficient resource usage in particular scenarios,
* verify changes in your server’s resource usage during optimization,
* benchmark your server initialization resource consumption and duration.

History metrics display value averages with 1 minute time period, available in Free tier.

:star2: [**Upgrade to Pay as You Go tier**](https://app.edgegap.com/user-settings?tab=memberships) **to unlock precise metrics with 1 second time intervals.**

<figure><img src="https://3027732442-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2FoIpCR3x9ibiXMEIWFgKG%2Fimage.png?alt=media&#x26;token=86dcd914-db9f-4e81-8444-6c83805be9b6" alt=""><figcaption></figcaption></figure>

{% hint style="info" %}
[Contact us](mailto:info@edgegap.com) prior to your release to request live hosting support for large scale releases.
{% endhint %}

### Context & Status

Additional deployment information can be retrieved in JSON format:

* from inside the deployment (game server), using [Deployment Context API](https://docs.edgegap.com/api/#tag/Context/operation/context-get),
* from outside the deployment (backend / third party), using [Deployment Status API](https://docs.edgegap.com/api/#tag/Deployments/operation/deployment-status-get).

{% hint style="info" %}
Context API (from deployment) requires Context API token, while Status API uses your Edgegap token.
{% endhint %}

{% hint style="warning" %}
**Too Many Requests 429** - we rate limit your organization at **20 req/s** for Context and Status API endpoints. Use [#injected-environment-variables](#injected-environment-variables "mention") and [Webhooks](https://docs.edgegap.com/docs/deployment/arbitrium-deploy-webhook) for a scalable solution.
{% endhint %}

### Filter Deployments

To quickly search amongst all deployments, you can [use our dashboard](https://app.edgegap.com/deployment-management/deployments/list):

<figure><img src="https://3027732442-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2F42IaKG0pFQXSkvPCRH1T%2Fimage.png?alt=media&#x26;token=6aba8781-13c9-4c0f-87e9-2d9612a57342" alt=""><figcaption></figcaption></figure>

{% hint style="success" %}
Alternatively, let players **pick a persistent (always online) server** from a list with [server-browser](https://docs.edgegap.com/learn/server-browser "mention").
{% endhint %}

[List deployments with API](https://docs.edgegap.com/api/#tag/Deployments/operation/deployments-get) and apply filters with backend integrations:

<table><thead><tr><th width="237">Deployment Attribute</th><th width="193">Operators</th><th>Example Value</th></tr></thead><tbody><tr><td><a href="#deployment-lifecycle"><code>status</code></a></td><td><a data-footnote-ref href="#user-content-fn-2"><code>eq</code></a>  or <a data-footnote-ref href="#user-content-fn-3"><code>neq</code></a></td><td><code>"ready"</code> or <code>"error"</code></td></tr><tr><td><a href="#observability"><code>request_id</code></a></td><td><a data-footnote-ref href="#user-content-fn-2"><code>eq</code></a> </td><td><a data-footnote-ref href="#user-content-fn-4"><code>"7e709a0d8efd"</code></a></td></tr><tr><td></td><td><a data-footnote-ref href="#user-content-fn-5"><code>in</code></a>  or <a data-footnote-ref href="#user-content-fn-6"><code>nin</code></a></td><td><a data-footnote-ref href="#user-content-fn-4"><code>[ "7e709a0d8efd", "4ba353100b4b" ]</code></a></td></tr><tr><td><a href="#discoverability"><code>tags</code></a></td><td><a data-footnote-ref href="#user-content-fn-2"><code>eq</code></a>  or <a data-footnote-ref href="#user-content-fn-3"><code>neq</code></a></td><td><code>"tagA"</code></td></tr><tr><td></td><td><a data-footnote-ref href="#user-content-fn-5"><code>in</code></a>  or <a data-footnote-ref href="#user-content-fn-6"><code>nin</code></a></td><td><code>[ "tagA", "tagB" ]</code></td></tr><tr><td><a href="#id-1.-start-a-deployment"><code>created_at</code></a></td><td><a data-footnote-ref href="#user-content-fn-2"><code>eq</code></a>  or <a data-footnote-ref href="#user-content-fn-7"><code>lte</code></a>  or <a data-footnote-ref href="#user-content-fn-8"><code>gte</code></a></td><td><a href="https://en.wikipedia.org/wiki/ISO_8601"><code>2025-05-12T20:03:20Z</code></a></td></tr><tr><td><a href="application-and-versions"><code>application</code></a></td><td><a data-footnote-ref href="#user-content-fn-2"><code>eq</code></a>  or <a data-footnote-ref href="#user-content-fn-3"><code>neq</code></a></td><td><code>"my-app"</code></td></tr><tr><td></td><td><a data-footnote-ref href="#user-content-fn-5"><code>in</code></a>  or <a data-footnote-ref href="#user-content-fn-6"><code>nin</code></a></td><td><code>[ "my-app", "my-other-app" ]</code></td></tr><tr><td><a href="application-and-versions"><code>version</code></a></td><td><a data-footnote-ref href="#user-content-fn-2"><code>eq</code></a>  or <a data-footnote-ref href="#user-content-fn-3"><code>neq</code></a></td><td><code>"1.0.0"</code></td></tr><tr><td></td><td><a data-footnote-ref href="#user-content-fn-9"><code>in</code></a>  or <a data-footnote-ref href="#user-content-fn-6"><code>nin</code></a></td><td><code>[ "1.0.0", "prod" ]</code></td></tr><tr><td><a href="../../docs/session"><code>is_joinable_by_session</code></a></td><td><a data-footnote-ref href="#user-content-fn-2"><code>eq</code></a> </td><td><code>true</code> or <code>false</code></td></tr><tr><td><a href="../../docs/session"><code>available_session_sockets</code></a></td><td><p><a data-footnote-ref href="#user-content-fn-2"><code>eq</code></a>  or <a data-footnote-ref href="#user-content-fn-3"><code>neq</code></a>  or </p><p><a data-footnote-ref href="#user-content-fn-10"><code>lt</code></a>  or <a data-footnote-ref href="#user-content-fn-7"><code>lte</code></a> or </p><p><a data-footnote-ref href="#user-content-fn-11"><code>gt</code></a>  or <a data-footnote-ref href="#user-content-fn-8"><code>gte</code></a>  </p></td><td><code>5</code></td></tr></tbody></table>

{% hint style="info" %}
Each attribute can have at most 1 filter operator in a single request. See [api](https://docs.edgegap.com/docs/api "mention") for more.
{% endhint %}

Sort results by multiple fields in the order they appear in request:

| Deployment Attribute                                                 | Order                                                                   |
| -------------------------------------------------------------------- | ----------------------------------------------------------------------- |
| [`created_at`](#id-1.-start-a-deployment)                            | [`asc`](#user-content-fn-12)[^12] or [`desc`](#user-content-fn-13)[^13] |
| [`available_session_sockets`](https://docs.edgegap.com/docs/session) | [`asc`](#user-content-fn-14)[^14] or [`desc`](#user-content-fn-15)[^15] |

Example filter queries:

<details>

<summary>List <a href="#id-4.-deployment-error">Deployments in Error</a> to troubleshoot and remove.</summary>

Encoded URL:

```
https://api.edgegap.com/v1/deployments?query={"filters":[{"field":"status","operator":"eq","value":"error"},{"field":"application","operator":"eq","value":"my-app"},{"field":"version","operator":"eq","value":"green"}],"order_by":[{"field":"created_at","order":"desc"}]}
```

Formatted JSON query:

```json
{
  "filters": [
    {
      "field": "status",
      "operator": "eq",
      "value": "error"
    },
    {
      "field": "application",
      "operator": "eq",
      "value": "my-app"
    },
    {
      "field": "version",
      "operator": "eq",
      "value": "green"
    }
  ],
  "order_by": [
    {
      "field": "created_at",
      "order": "desc"
    }
  ]
}
```

</details>

<details>

<summary>List <a href="../../matchmaking/matchmaker-in-depth#rolling-updates-and-ab-tests">Deployments with outdated App version</a> to confirm a release is complete.</summary>

Encoded URL:

```
https://api.edgegap.com/v1/deployments?query={"filters":[{"field":"status","operator":"eq","value":"ready"},{"field":"application","operator":"eq","value":"my-app"},{"field":"version","operator":"eq","value":"blue"}],"order_by":[{"field":"created_at","order":"desc"}]}
```

Formatted JSON query:

```json
{
  "filters": [
    {
      "field": "status",
      "operator": "eq",
      "value": "ready"
    },
    {
      "field": "application",
      "operator": "eq",
      "value": "my-app"
    },
    {
      "field": "version",
      "operator": "eq",
      "value": "blue"
    }
  ],
  "order_by": [
    {
      "field": "created_at",
      "order": "desc"
    }
  ]
}
```

</details>

{% hint style="success" %}
Don’t forget to add the `Authorization` header with your Edgegap API token in the request.
{% endhint %}

### Webhooks & Postbacks

Receive simple HTTP notifications in your game backend for changes in [#deployment-lifecycle](#deployment-lifecycle "mention") by specifying a webhook URL in your [deployment API request](https://docs.edgegap.com/api/#tag/Deployments/operation/deploy). Available for:

* On Ready: deployment container [started successfully](#id-1.-start-a-deployment) (server starts initializing after this),
* On Error: deployment couldn't be started and a [#id-4.-deployment-error](#id-4.-deployment-error "mention") occurred,
* On Terminate: [#id-5.-deployment-stopped](#id-5.-deployment-stopped "mention") and game server is no longer reachable.

Ready and Error webhooks will never be triggered for the same deployment.

<details>

<summary>Example Webhook Payload</summary>

```json
{
  "request_id": "f68e011bfb01",
  "application": "my-game-server",
  "version": "2024.01.30-16.23.00-UTC",
  "fqdn": "f68e011bfb01.pr.edgegap.net",
  "public_ip": "162.254.141.66",
  "deployed_at": "2026-02-10T20:35:48Z",
  "termination_scheduled_at": "2026-02-10T21:35:48Z",
  "ports": {
    "gameport": {
      "external": 31504,
      "internal": 7777,
      "protocol": "UDP",
      "name": "gameport",
      "tls_upgrade": false,
      "link": "f68e011bfb01.pr.edgegap.net:31504",
      "proxy": null
    }
  },
  "location": {
    "city": "Montreal",
    "country": "Canada",
    "continent": "North America",
    "administrative_division": "Quebec",
    "timezone": "Eastern Time",
    "latitude": 45.513707,
    "longitude": -73.619073
  },
  "tags": [
    "tag1",
    "tag2"
  ],
  "host_id": "alpha-north-america-70364ef8",
  "host_in_private_fleet": false,
  "private_fleet_id": "PUBLIC_CLOUD",
  "vcpu_units": 256,
  "memory_mib": 512
}
```

</details>

{% hint style="warning" %}
**Webhooks are not retried**, so if your backend does not process the request due to rate limiting or an error, the webhook may be lost. Use webhooks only for **non-critical use cases or debugging purposes**.
{% endhint %}

{% hint style="info" %}
Webhooks observe deployment lifecycle, but are not aware of your scene/level initialization state. To observe loading progress of your scene/level, implement a custom webhook in your game server.
{% endhint %}

## 🚨 Troubleshooting

When troubleshooting deployments:

1. verify there are no errors in your [#deployment-logs](#deployment-logs "mention") and [#container-logs](#container-logs "mention"),
2. run your server locally to rule out integration bugs,
3. review troubleshooting steps on this page,
4. reach out to us in [Community Discord](https://discord.gg/MmJf8fWjnt) and include your deployment ID.

{% hint style="info" %}
See [#player-issue-resolution](#player-issue-resolution "mention") for our recommendations on navigating player community feedback.
{% endhint %}

<details>

<summary>Can’t connect clients to server - <code>Request timed out.</code>, <code>请求超时</code> , <code>ConnectionFailed</code> , or <code>Port verification failed</code>.</summary>

* First, make sure that the deployment is Ready, and there are no runtime exceptions or errors in your deployment log. If your deployment stopped, inspect logs in our [Dashboard](https://app.edgegap.com/deployment-management/deployments/list).
* If you’re using Mirror netcode you need to have ["Auto Start Server”](https://mirror-networking.gitbook.io/docs/hosting/edgegap-hosting-plugin-guide#build-and-push) selected in your `NetworkManager` , rebuild, push, and redeploy your server.
* If you’re using FishNet netcode you need to enable [“Start on Headless”](https://fish-networking.gitbook.io/docs/manual/components/managers/server-manager#settings-are-general-settings-related-to-the-servermanager) in your `ServerManager`, rebuild, push, and redeploy your server.
* If you’re using Photon Fusion 2 netcode, please ensure that your server is passing the deployment public IP, external port and the `roomCode` on the server, and the same room code in the client in the [“NeworkRunner.StartGame”](https://doc.photonengine.com/fusion/current/manual/network-runner#creating-or-joining-a-room) parameter `StartGameArgs`. Deployment ID (e.g. `b63e6003b19f`) is a great choice as it’s globally unique and easily accessible to client by [Matchmaker](https://docs.edgegap.com/learn/matchmaking/matchmaker-in-depth) assignment and to the [#injected-environment-variables](https://docs.edgegap.com/matchmaking/matchmaker-in-depth#injected-environment-variables "mention").
* Next, please verify that your port setting in your server build’s netcode settings matches the internal port in your [App version](https://app.edgegap.com/application-management/applications/list). You can change the port mapping by editing the [App version](https://app.edgegap.com/application-management/applications/list) without rebuilding. Find your protocol in your netcode integration.
* Please ensure that your game client is connecting to the **external port** shown on your Deployment details page, this value will be always randomized due to security reasons.
* If you’re using Secure Websocket (WSS) protocol in your netcode integration, please ensure that your [App version](https://app.edgegap.com/application-management/applications/list) port configuration for the WSS port has TLS Upgrade enabled.
* Are you located in China and are using [Smart Fleets](https://docs.edgegap.com/docs/deployment/session/fleet-manager/fleet)? Your connection may be blocked by the Great Firewall. Consider adding a server located in China to your fleet, or using a VPN to connect.

</details>

<details>

<summary>My deployment stopped/restarted and I can’t access it’s logs anymore.</summary>

* In case the server process crashes due to an exception, our system will attempt restarting the server automatically. Consider testing your server locally to uncover the root cause.
* We only keep logs for the duration of the deployment, if you wish to inspect logs after deployment stops, please [integrate a third party log storage](https://docs.edgegap.com/docs/deployment/endpoint-storage).
* See [#id-5.-deployment-stopped](#id-5.-deployment-stopped "mention") to discover all causes for stopping your deployment.

</details>

<details>

<summary>My deployment stopped automatically after X minutes.</summary>

* Free Tier deployments have a 60 minute time limit, please consider upgrading your account.
* All deployments will be terminated after 24 hours of runtime following our server sanitization policy, for infrastructure maintenance, and to prevent racking up unexpected costs when deployment wasn’t shut down properly. For long-running servers, consider using [private-fleets](https://docs.edgegap.com/learn/orchestration/private-fleets "mention") with [persistence](https://docs.edgegap.com/learn/orchestration/persistence "mention").
* See [#id-5.-deployment-stopped](#id-5.-deployment-stopped "mention") to discover all causes for stopping your deployment.

</details>

<details>

<summary>My deployment is ready but I’m not able to connect for several minutes afterwards.</summary>

* Once a deployment is Ready, your game engine initialization begins. This process may take anywhere from seconds to minutes, and the server doesn’t accept to player connections during this period.
* Consider optimizing your server initialization to decrease this time period.
* Game clients should retry connection in 1 second intervals for a limited amount of time (depending on your initialization duration), after which they return to matchmaking.
* Consider adding a loading scene so the server can perform initialization (and travel in case of Unreal Engine) at the same time as clients, while synchronizing state of both.

</details>

<details>

<summary>My Meta Quest device throws <code>HTTP 0: Cannot resolve destination host</code> .</summary>

* When building Unity apps for Android target, your Internet Access permission may be removed from the output APK client build artifact automatically.
* Re-add the permissions in (requires rebuilding client afterwards):
  * Project Settings / OpenXR / :gear: Meta Quest Support / Force Remove Internet Permissions (uncheck).
  * Player Settings / Internet Access (set to require).

</details>

<details>

<summary>What will happen if a player leaves my deployment?</summary>

* By default, servers don’t reject player connections. Authenticating players is up to your devs, since many different methods and player authentication providers can be used.
* Game clients may store connection information locally to attempt reconnecting in case of unexpected client crashes.
* To allow players to join games in progress, consider using [#backfill](https://docs.edgegap.com/matchmaking/matchmaker-in-depth#backfill "mention") or [Sessions](https://docs.edgegap.com/docs/deployment/session).

</details>

<details>

<summary>My server shows 100% CPU utilization after becoming ready.</summary>

* This may not be an issue, as game engines tend to perform CPU-heavy operations during server initializations. If the CPU usage doesn’t drop after 2-3 minutes from deployment start, you may need to optimize your server or increase app version resources.
* Reducing tick rate can impact CPU usage as the server performs less messaging operations.
* If you’re using Mirror netcode you need to have ["Auto Start Server”](https://mirror-networking.gitbook.io/docs/hosting/edgegap-hosting-plugin-guide#build-and-push) selected in your `NetworkManager` , rebuild, push, and redeploy your server.
* If you’re using FishNet netcode you need to enable [“Start on Headless”](https://fish-networking.gitbook.io/docs/manual/components/managers/server-manager#settings-are-general-settings-related-to-the-servermanager) in your `ServerManager`, rebuild, push, and redeploy your server.
* You’re limited to 1.5 vCPU and 3GB of memory (RAM) in Free Tier.
* You may increase allocated resources when creating a new app version. You can duplicate your App version in our Dashboard and adjust these values as needed, without rebuilding your server or image.

</details>

<details>

<summary>My deployment is restarting repeatedly and shows error `OOM kill` .</summary>

* This behavior is caused by exceeding allocated memory amount. Consider optimizing memory usage with object pooling, compression, or removing unneeded objects in your scene.
* Ensure your project is loading the default scene containing your `NetworkManager` and the scene is included in Unity’s Build Settings.
* You’re limited to 1.5 vCPU and 3GB of memory (RAM) in Free Tier.
* You may increase allocated resources when creating a new app version. You can duplicate your App version in our Dashboard and adjust these values as needed, without rebuilding your server or image.

</details>

<details>

<summary>Sometimes, my server’s memory (RAM) usage spikes to a high value, is that a problem?</summary>

* As long as you stay within the allocated app version memory amount, this is not an issue.&#x20;
* Exceeding the allocated app version memory amount will cause \`OOM kill\` (see above).

</details>

<details>

<summary>Will my server performance be impacted by other servers running on the same machine?</summary>

* No, our platform ensures that allocated resources will not be used by other studios, or other servers on shared infrastructure. With Edgegap, there are no noisy neighbors.

</details>

[^1]: sessions may last up to 24 hours

[^2]: equals

[^3]: not equals

[^4]: request\_id (deployment ID)

[^5]: in array

[^6]: not in array

[^7]: lower than or equal

[^8]: greater than or equal

[^9]: &#x20;in array

[^10]: lower than

[^11]: greater than

[^12]: ascending, oldest first

[^13]: descending, newest first

[^14]: ascending, full first

[^15]: descending, empty first


# Persistence

Learn how to manage persistent worlds with 24/7 always online deployments on [private-fleets](https://docs.edgegap.com/learn/orchestration/private-fleets "mention").

Many genres (MMOs, Sandboxes, Social Games) leverage persistent worlds to let players:

* meet and socialize with new friends; to nurture organic player communities,
* explore a living open world filled with user-generated content placed by players,
* engage in epic raid battles lasting hours with large groups or entire guilds.

Explore strategies to **provide the best possible player experience, keep cost under control, and remove player frustration due to outages or rollbacks**. Enhance the traditional server model by bringing the advantages of edge computing packaged for easy use by game developers.

{% hint style="success" %}
&#x20;Alternatively, see [#match-bound](https://docs.edgegap.com/learn/deployments#match-bound "mention") orchestration to utilize fractional vCPU pricing.
{% endhint %}

## ✔️ Preparation

To enable persistent, uninterrupted 24/7 always online deployments:

* [create a new (or update an existing one) App Version with our API](https://docs.edgegap.com/docs/api/versioning#post-v1-app-app_name-version),
  * specify `"max_duration": -1`  to prevent automated termination after 24h,
* Use [private fleet deploy API](https://docs.edgegap.com/docs/api/dedicated-servers#post-private-fleets-deploy) to start [standby servers](https://docs.edgegap.com/learn/deployments#regional-standby) with [persistence](https://docs.edgegap.com/learn/orchestration/persistence "mention").
  * Choose between Virtual Machines (Performance) or Bare Metal (Overdrive) specifications.

{% hint style="warning" %}
**Test your server scaling and** [**termination process**](https://docs.edgegap.com/learn/deployments#id-5.-deployment-stopped) **to verify reliability of your cost controls. Server state stored in memory will be lost once the deployment is stopped, see** [#configuration-and-state](#configuration-and-state "mention").
{% endhint %}

{% hint style="info" %}
If you need help, [please reach out to us over Discord](https://discord.gg/MmJf8fWjnt). For live games support see our [ticketing system](https://edgegap.atlassian.net/servicedesk/customer/portal/3).
{% endhint %}

## 🔑 Server Ownership

Explore pros and cons of modern and traditional ownership models with an edge computing twist.

### Studio Hosting

Server hosting is traditionally managed by the studio, covering cost of hosting from game revenue.

👍 **Advantages**

* transparent product pricing - cost of hosting is covered by license/subscription of player,
* strong client/server compatibility with loose coupling of clients, services, and scaling,
* more resilient to cheating and reverse engineering due to closed source nature of servers.

👎 **Disadvantages**

* community modding support is limited to ensure server integrity and stability.

### Community Servers

Let your players host and fund their own servers and remove need for third party rental services. Funnel revenue through your studio instead of third party lacking insight into quality of end user experience.

👍 **Advantages**

* enhanced modding support through curated list of modded [application-and-versions](https://docs.edgegap.com/learn/orchestration/application-and-versions "mention"),
* improved player feedback loop due to closer collaboration with community,
* reduced financial risk due to players covering cost of hosting.

👎 **Disadvantages**

* more operations for studio - moderating player requests and collecting payments,
* weaker client/server compatibility due to increased number of modded versions,
* prone to cheaters due to distributed codebase and possibility of reverse engineering.

## 🥛 Capacity & Scaling

Learn advanced techniques to optimize server availability, hosting cost, and quality of service.

### Capacity

**Deployments don't track or manage active player connections** after you [#id-1.-start-a-deployment](https://docs.edgegap.com/learn/deployments#id-1.-start-a-deployment "mention") to give you absolute control and freedom to implement any design.

Implement capacity management to ensure your servers:

* maximize cost savings - [benchmark](https://docs.edgegap.com/learn/deployments#container-metrics) and utilize server resources efficiently,
* provide smooth gameplay - prevent overloading servers with too many concurrent players,
* prevent bad reviews due to crashes - catch and handle unexpected exceptions.

To ensure efficient server capacity management:

* release player slots if [players matched to game server](https://docs.edgegap.com/matchmaking/matchmaker-in-depth#player-tickets) don't connect within a few seconds,
* frequently send a minimal heartbeat message from clients to server to keep track of activity,
* disconnect clients and release player slots if no activity is detected for several seconds,
* prevent players from being added to servers with full capacity and no available player slots.

{% hint style="success" %}
See [Broken link](https://docs.edgegap.com/learn/orchestration/broken-reference "mention") for automated capacity handling with our managed service.
{% endhint %}

{% hint style="warning" %}
**Amount of reserved deployment resources can't be changed during runtime.** Scale horizontally with new server instances utilizing adjusted [application versions](https://docs.edgegap.com/learn/orchestration/application-and-versions) requiring more CPU or memory resources.
{% endhint %}

### Scale Up

**Scaling persistent servers doesn't require "guesstimating"** regional traffic or server cost. Reserve [private-fleets](https://docs.edgegap.com/learn/orchestration/private-fleets "mention") capacity for [low tide](#user-content-fn-1)[^1] and automatically overflow to cloud during unexpected peaks.

{% hint style="success" %}
**Enable** [**Active Caching in your App Version**](https://docs.edgegap.com/learn/application-and-versions#active-caching) **to deploy servers within seconds.**
{% endhint %}

Implement server scaling strategies to:

* enable large scale hosting while carefully protecting against abuse,
* minimize wasted server cost due to empty standby servers,
* prevent long queue times by responding to increased player demand quickly.

<figure><img src="https://3027732442-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2FWVZEdEvyAcAROhqNYbKQ%2Fimage.png?alt=media&#x26;token=a26d6f3a-9071-41aa-b27f-ee96555f84a9" alt=""><figcaption><p>Auto-scaling Reference Architecture</p></figcaption></figure>

#### Integration Key Points

1. Clients integrate Scaling Authority - [matchmaking](https://docs.edgegap.com/learn/matchmaking "mention"), [server-browser](https://docs.edgegap.com/learn/server-browser "mention"), or a custom solution.
   1. Discover other players, reserve capacity in running servers, or request new servers if needed.
2. Scaling Authority assigns running servers or starts new servers to serve players.
3. Server notifies Scaling Authority in real time about server start/stop and player connection changes.
   1. Scaling Authority deletes (expires) stale records of unresponsive (crashed) servers.
4. Clients connect and establish game sessions with Server directly, proceed to gameplay.

**We strongly recommend scaling based on number of connections instead of physical load** (CPU & RAM), since momentary fluctuations in physical load may result in unpredictable availability.

{% hint style="warning" %}
**Amount of reserved deployment resources can't be changed during runtime.** Scale horizontally with new server instances utilizing adjusted [application versions](https://docs.edgegap.com/learn/orchestration/application-and-versions) requiring more CPU or memory resources.
{% endhint %}

### Scale Down

Efficient scale-down policies are key to optimizing cost, but [shutting down servers](https://docs.edgegap.com/docs/api/dedicated-servers#v1-self-stop-request_id-access_point_id) without caution may impact player experience negatively. **Consider these factors and test changes before releasing:**

**Is your detection of player activity / disconnection reliable?**

* Does absence of input reliably indicate player inactivity? Players often use bots, macros, and other techniques to fake activity and maintain active connection to avoid queue times.
* Are there any actions taken by active players often which are hard to fake?
* Is using bots or macros an issue or a feature with [#studio-hosting](#studio-hosting "mention") servers?

**Is shutting off servers easily and quickly reversible (scale back up)?**

* Once reaching [#id-3.-deployment-ready](https://docs.edgegap.com/learn/deployments#id-3.-deployment-ready "mention"), your server may require additional time to perform engine initialization and [#state-management](#state-management "mention") (restoration of state). Do you incur any additional costs for compute or data transfer with game services? Does this wait time impact player experience?
* Can you hide server loading with a loading scene, mini-game, a lobby, or through other means?

**Are players bound to specific server instances or can they migrate easily?**

* How does connecting to a different server influence player's account, purchase history, social experience, progression, inventory, and other gameplay aspects?
* Review your [#recovery-objectives](#recovery-objectives "mention") and ensure critical data isn't lost.
* Implement automated methods or player tools for restoring critical data.
* Provide human support and communicate with your community about outages and issues.

## 🔎 Discoverability

To find active servers accepting new players, implement one or more discovery methods:

* Let players browse servers and pick from a list with [server-browser](https://docs.edgegap.com/learn/server-browser "mention").
* Start new games when sufficient players join [matchmaking](https://docs.edgegap.com/learn/matchmaking "mention").
  * Add players to [replace leavers in existing matches with backfill](https://docs.edgegap.com/matchmaking/matchmaker-in-depth#backfill).
* [Implement custom or third party game backend to discover servers](https://docs.edgegap.com/advanced-features/managed-clusters#nakama-by-heroic-labs).

## 💭 Configuration & State

Integrate services to define initial server requirements and manage player and server state.

### Configuration Management

Configuration refers to the **initial data passed to your server during deployment:**

* [environment-specific injected variables](https://docs.edgegap.com/learn/application-and-versions#other-parameters-optional):
  * e.g. client/server version compatibility data,
* [server location](https://docs.edgegap.com/learn/deployments#arbitrium_deployment_location-detailed-information-about-deployment-location), [server ports](https://docs.edgegap.com/learn/deployments#arbitrium_ports_mapping-detailed-information-about-your-internal-and-external-ports) and [other server information](https://docs.edgegap.com/learn/deployments#injected-environment-variables),
* [matchmaking information](https://docs.edgegap.com/matchmaking/matchmaker-in-depth#injected-environment-variables) or [custom deployment variables](https://docs.edgegap.com/learn/deployments#custom-variables),
* third party integration parameters, keys, and secrets.

{% hint style="info" %}
**Configuration is immutable** - it's read once after starting your server and doesn't change later on.
{% endhint %}

### State Management

State refers to data describing the **result of a series of previous player actions and server events:**

* player connection, player-controlled state changes (e.g. [Pawn](https://dev.epicgames.com/documentation/en-us/unreal-engine/pawn-in-unreal-engine)),
* changes related to objects contained in the level/scene (e.g. [Actor](https://dev.epicgames.com/documentation/en-us/unreal-engine/actors-in-unreal-engine), [Game Object](https://docs.unity3d.com/6000.0/Documentation/Manual/GameObjects.html)),
* changes related to [game mode](https://dev.epicgames.com/documentation/en-us/unreal-engine/game-mode-and-game-state-in-unreal-engine#gamemodes), [game state](https://dev.epicgames.com/documentation/en-us/unreal-engine/game-mode-and-game-state-in-unreal-engine#gamestate), or [game scene](https://docs.unity3d.com/6000.0/Documentation/Manual/CreatingScenes.html) information.

{% hint style="info" %}
**State data changes frequently.** Clients are selectively updated on relevant information by server authority.
{% endhint %}

{% hint style="success" %}
**Perform frequent state backups to prevent data loss** in case of unexpected client or server issues:

* asynchronously in real time using a third party service, e.g. [Nakama by Heroic Labs](https://docs.edgegap.com/advanced-features/managed-clusters#nakama-by-heroic-labs),
* on client/server startup or shutdown, as deserialized state files in [cloud object storage](https://www.linode.com/products/object-storage/).
  {% endhint %}

Game objects typically designate an owner who controls them, this can be either server or a player.&#x20;

#### Server Owned Objects

Server owned objects can be manipulated only by server. Connected players have limited read access to server owned objects. Server owned objects are usually not shared with other servers.

{% hint style="success" %}
Server owned objects can be **loaded by a replacement server in case of unexpected server crash**. Use [deployment ID](https://docs.edgegap.com/learn/deployments#basic-information) to identify your new save file when first launched, and to store server owned object state.
{% endhint %}

#### Player Owned Objects

Player owned objects can be manipulated both by players and server. Assigning ownership of persistent objects to players makes migration to other servers easier later on.

{% hint style="success" %}
**Back up state of player owned objects on player device or a game backend** between play sessions.
{% endhint %}

{% hint style="info" %}
Prevent cheating by validating changes with server authority. Authority and ownership can be separate.
{% endhint %}

### Recovery Objectives

In case of issues, some categories of data may be more sensitive to data loss, for example:

* account, subscription, purchase, and microtransaction data - **critical**,
* progression, achievement, leaderboards, and inventory data - **important**,
* cheat detection, moderation, performance, and error tracking data - **important**,
* player behavior, social, chat data - **low importance**.

{% hint style="success" %}
**Implement restoring purchases from independent transaction history source** for best experience.
{% endhint %}

We highly recommend discussing the following amongst your team:

* categories of data handled in your game clients and servers,
* importance and sensitivity of each category for your business and players,
* Recovery Point Objective (RPO) - acceptable amount of data loss before serious harm occurs,
* Recovery Time Objective (RTO) - acceptable amount of downtime before serious harm occurs.

{% hint style="danger" %}
**Unexpected crash of server will cause your server to restart automatically.** [Server state may be lost](#state-management).
{% endhint %}

## 👀 Observability

Long running persistent servers bring new observability challenges, specifically detecting anomalies in monitoring, logging, and bug tracking.

We **strongly recommend implementing alerts for server restarts** to gain more visibility over issues.

Our [endpoint-storage](https://docs.edgegap.com/docs/endpoint-storage "mention") **log integration** **only transfers logs** **after** [#id-5.-deployment-stopped](https://docs.edgegap.com/learn/deployments#id-5.-deployment-stopped "mention"), add custom logs and bug tracking (such as [Sentry](https://sentry.io/welcome/)) to troubleshoot partial failures and bugs.

{% hint style="success" %}
Consider reserving [private-fleets](https://docs.edgegap.com/learn/orchestration/private-fleets "mention") standby capacity for games with predictable traffic patterns.
{% endhint %}

[^1]: lowest CCU during the day


# Private Fleets

Reserve standby capacity on monthly basis for persistent 24/7 always online servers. Choose your preference between Virtual Machines (Performance) or Bare Metal (Overdrive) specifications.

**Private Fleets are an optional addition to Edgegap Cloud (default),** a popular hosting option enabling [persistence](https://docs.edgegap.com/learn/orchestration/persistence "mention") with 24/7 always online servers and favorable pricing for games with predictable traffic.

🌟 [**Upgrade to Pay as You Go tier**](https://app.edgegap.com/user-settings?tab=memberships) **to unlock private fleets hosting with standby capacity!**

{% hint style="success" %}
&#x20;Alternatively, see [#match-bound](https://docs.edgegap.com/learn/deployments#match-bound "mention") orchestration to utilize fractional vCPU pricing.
{% endhint %}

{% hint style="warning" %}
[Smart Fleets (legacy)](https://docs.edgegap.com/docs/fleet) and [Sessions (legacy)](https://docs.edgegap.com/docs/session) will be deprecated and replaced by [private-fleets](https://docs.edgegap.com/learn/orchestration/private-fleets "mention") and [server-browser](https://docs.edgegap.com/learn/server-browser "mention") on March 1st 2026. [**Reach out over Discord**](https://discord.gg/MmJf8fWjnt) **to learn more and get help with migration.**
{% endhint %}

## ✔️ Introduction

Private Fleets let you pick specific host locations and reserve dedicated standby compute capacity within our globally available cloud infrastructure, suitable for:

* [**persistent 24/7 servers**](https://docs.edgegap.com/learn/orchestration/persistence) featuring open worlds with user-generated content placed by players,
* **MMO games** prioritizing social experiences with high amount of concurrent users per server,
* **released games with mostly predictable daily traffic** patterns and stable player communities.

## ☁️ Hardware

Pick one of our generic host specifications:

| Specification                                                            |                                                                                                                                     Performance |                                                                                                                                       Overdrive |
| ------------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------: | ----------------------------------------------------------------------------------------------------------------------------------------------: |
| Best Suited For                                                          |                                                                                        <p>match-based games,<br>or with predictable traffic</p> |                                                                                  <p>CPU-intensive games (AI),<br>or above 1:2 CPU/RAM ratio</p> |
| CPU Specifications                                                       | <p>16 vCPU<br><a data-footnote-ref href="#user-content-fn-1">2.0</a> - <a data-footnote-ref href="#user-content-fn-2">3.7</a> GHz frequency</p> | <p>16 vCPU<br><a data-footnote-ref href="#user-content-fn-1">3.7</a> - <a data-footnote-ref href="#user-content-fn-2">5.1</a> GHz frequency</p> |
| RAM Specifications                                                       |                                                                                                                                           32 GB |                                                                                                                                           64 GB |
| Free Egress Included                                                     |                                                                                                                                   5 TB per Host |                                                                                                                                   5 TB per Host |
| <p><strong>Price, pre-paid monthly</strong></p><p>(commitment based)</p> |                                                                                                                            **$250.00 per Host** |                                                                                                                            **$290.00 per Host** |

{% hint style="success" %}
[**Preview a pricing estimate during configuration of your fleet in dashboard**](https://app.edgegap.com/private-fleet-management/private-fleets/list)**.**
{% endhint %}

**Your first month reservation price and free egress quota are pro-rated.** This means you are charged only for the portion of time until the end of current month.

**Reservations automatically renew on the&#x20;first day of every month at 00:00 UTC until deleted.** Your card will be automatically charged the monthly amount for renewed hosts at this time.

{% hint style="success" %}
A fleet with [active hosts](#lifecycle) may not swap specifications. Create a new fleet or delete active hosts first.
{% endhint %}

{% hint style="info" %}
Small amount of resources on each host is reserved for Operating System, Monitoring, and Orchestration.
{% endhint %}

#### Modifying Schedule and Deleting Hosts

You may modify or delete this schedule at any time prior to the scheduled time, at no charge. You may designate any number of reserved (active) private hosts for deletion at the end of the current billing period, prior to the renewal date. Deleted hosts will not be charged for subsequent renewals. Any deployments running on private hosts scheduled for deletion will be gracefully shut down at the time of deletion without additional warnings.

#### Delayed Start or Insufficient Provider Capacity

In the event of delayed private host start or insufficient provider capacity, your payment amount and invoice for the scheduled or renewal periods will be adjusted accordingly.

## 📍 Locations

Choose a centroid by dropping a pin and preview your primary/fallback locations for new hosts.

Select a fallback strategy to control suitable locations for each centroid:

* **Proximity (default)** - 700 km centroid radius, for more latency-sensitive designs,
* **Redundancy** - 1,400 km centroid radius, allowing further locations as fallbacks.

<figure><img src="https://3027732442-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2F0otdBhulhvgFgO6mNWtg%2Fimage.png?alt=media&#x26;token=6388d70c-7cf4-469f-8ce4-9735c67aeb4d" alt=""><figcaption></figcaption></figure>

{% hint style="info" %}
Location availability depends on chosen hardware specification. Overdrive availability is limited.
{% endhint %}

📢 API provisioning under development, [let us know](https://discord.gg/NgCnkHbsGp) about your Continuous Integration needs!

## 🔄 Host Lifecycle

Private Fleet hosts follow a simple three step lifecycle sequence.

📢 Scheduling new host additions is under development, [let us know](https://discord.gg/NgCnkHbsGp) about your release process!

#### 1. Pending

New hosts have been requested, we're starting them in order of distance from centroid.

#### 2. Active

Host is active and responsive, ready to [#id-1.-start-a-deployment](https://docs.edgegap.com/learn/deployments#id-1.-start-a-deployment "mention").

#### 3. Scheduled for Deletion

While stile active, this host will be deleted at the end of the current billing period (month). This action can be reverted (cancelled) at any time until deletion takes place.

{% hint style="warning" %}
Deployments running on private hosts will be [gracefully stopped](https://docs.edgegap.com/learn/deployments#id-5.-deployment-stopped) once the host is deleted.
{% endhint %}

{% hint style="success" %}
**Prevent frustration due to rollbacks and gameplay disruption** by notifying players and rerouting new deployments to other private fleet hosts, once a private host scheduled for deletion is nearing shutdown.
{% endhint %}

## ⚡ Deployment

[Deployments for Private Fleet](https://docs.edgegap.com/docs/api/dedicated-servers#post-private-fleets-deploy) work exactly the same as [regular cloud deployments](https://docs.edgegap.com/docs/api/dedicated-servers#post-deployments), except you must specify a prioritized [list of host IDs](https://docs.edgegap.com/docs/api/dedicated-servers#get-private-fleets-fleet-name-hosts) to deploy to.

* Deployment will be started on the first private host in your list with sufficient resources.
* If no private host has available capacity, deployment will [#overflow-to-cloud](#overflow-to-cloud "mention").

### Overflow to Cloud

If your selected private fleet hosts don't have sufficient capacity at the time of deployment, your request will automatically use [#server-score](https://docs.edgegap.com/learn/deployments#server-score "mention") strategy and deploy to Edgegap Cloud.

To account for this possibility and prepare:

* Read [#resource-specifications](https://docs.edgegap.com/learn/deployments#resource-specifications "mention") injected variables to identify overflow case within deployment.
  * Cloud hosts may provide lower CPU frequency than private host Overdrive [#hardware](#hardware "mention"), restrict player capacity or other CPU-intensive features in server to prevent bottlenecking.
* Substitute missing private host beacon with one of the low latency cloud [ping-beacons](https://docs.edgegap.com/learn/orchestration/ping-beacons "mention").
* Prepare for your deployment [gracefully shutting down](https://docs.edgegap.com/learn/deployments#id-5.-deployment-stopped) after 24 hours (max cloud lifetime).
  * Manage [persistence](https://docs.edgegap.com/learn/orchestration/persistence "mention") and [#recovery-objectives](https://docs.edgegap.com/learn/persistence#recovery-objectives "mention") to prevent data loss.

## 🔎 Discoverability

Find deployments running on private fleets and establish player sessions using [server-browser](https://docs.edgegap.com/learn/server-browser "mention"), or [#filter-deployments](https://docs.edgegap.com/learn/deployments#filter-deployments "mention") to integrate a custom backend / third party solutions.

📢 [matchmaking](https://docs.edgegap.com/learn/matchmaking "mention") integration under development, [let us know](https://discord.gg/NgCnkHbsGp) about your needs!

### Ping Beacons

Enable beacons for your fleet to automatically deploy and maintain highly-available [#ping-beacons](#ping-beacons "mention") on each of your private hosts. Hosting beacons on the same machine as your deployments will provide the most precise ping measurement.

[^1]: base frequency

[^2]: turbo - short CPU bursts


# Ping Beacons

Use Ping Beacons to prevent matching with players in a far regions and improve player experience.

## 🟢 Connection Quality

Server connection quality varies for each player and is impacted by many factors, including:

* wifi signal strength (if wireless or mobile),
* Internet Service Provider condition,
* local network conditions,
* networking protocol used,
* usage of Virtual Private Networks (VPNs),
* or country-specific restrictions.

In order to minimize player ping and **provide the best possible player match** and make [#server-placement](https://docs.edgegap.com/learn/deployments#server-placement "mention") optimal, game clients **utilize Ping Beacons to measure latency** to several major networking nodes worldwide in real time. Measuring real packet round-trip time accounts for all of the factors mentioned above and provides the most accurate metric at any given point in time.

Keep in mind that **high beacon ping doesn’t equate to high server ping**, since servers are populated more densely than beacons. Number of beacons is balanced real-time for best coverage, least required data transfer, and shortest time to complete measurement.

In addition to Edgegap’s monitoring, we recommend **implementing your own client-side analytics** to keep track of your player demographics and connection quality when matchmaking, so issues can be discovered, triaged, and resolved as fast as possible.

## 🗼 About Ping Beacons

Retrieve a list of beacons that players can ping directly from:

* Matchmaker [#matchmaking-api](https://docs.edgegap.com/matchmaking/matchmaker-in-depth#matchmaking-api "mention") from a game client,
* Edgegap API [endpoint /locations/beacons](https://docs.edgegap.com/api/#tag/Locations/operation/location-beacon-list) using [Edgegap API token](https://app.edgegap.com/user-settings?tab=tokens) (from your backend).

Ping beacons may be used for multiple purposes simultaneously:

* prevent high latency matches by [#measuring-round-trip-time](#measuring-round-trip-time "mention") automatically.
* provide a [#hub-selection-ui](#hub-selection-ui "mention") for players to cherry-pick favorite hubs,
* provide a [#region-selection-ui](#region-selection-ui "mention") for players to exclude far away regions,

{% hint style="info" %}
**Too Many Requests 429** - to ensure platform stability, we **rate limit your organization at** **40 req/s** for this API endpoint. Implement an [#active-cache](#active-cache "mention") to prevent hitting the rate limit.
{% endhint %}

{% hint style="success" %}
[#measuring-round-trip-time](#measuring-round-trip-time "mention") using **ICMP, UDP, or TCP ping is not rate limited**.
{% endhint %}

## 🗺️ Region Selection UI

Prevent users matchmaking against other users in a particular region by offering a list of regions to enable or disable in your game UI.

**Automatically disable high latency regions:**

* list all available beacons,
* perform [#measuring-round-trip-time](#measuring-round-trip-time "mention") to all beacons,
* **disable region if measured latency against all beacons exceeds a given threshold.**

Your threshold depends on game design specifics, we recommend matching in regions with latency below 250ms (milliseconds).

{% hint style="info" %}
To let players override [#server-placement](https://docs.edgegap.com/learn/deployments#server-placement "mention") provide beacon IP when [matchmaking](https://docs.edgegap.com/matchmaking/matchmaker-in-depth#endpoint-tickets) or [deploying](https://docs.edgegap.com/docs/api/dedicated-servers#deployments). For best player experience, warn players this may result in increased latency due to remotely located server.
{% endhint %}

Some players with high ping to all beacons due to ISP[^1] issues or slow connection (e.g. wireless/mobile) may cause lags and degrade game experience for others. To mitigate this issue:

* Gradually expand allowed latency maximum and difference (see [Advanced Example Config](https://docs.edgegap.com/matchmaking#advanced-example)),
  * players with high ping may have to wait longer than usual to find a match.
* Alternatively, allow players to override measurement with manual region selection, only sending fake ping values for the player-selected regions only (e.g. 25ms for fast match),
  * this may negatively impact player experience of the players' teammates and opponents.

{% hint style="info" %}
**High beacon ping doesn’t always result in high server ping**. Deployments are available in more locations than beacons. Beacons are orchestrated in real time to prioritize global coverage and reliability.
{% endhint %}

{% hint style="success" %}
See [matchmaking](https://docs.edgegap.com/learn/matchmaking "mention") for **automated ping measurement using our SDKs**.
{% endhint %}

## 📍 Hub Selection UI

Some game players prefer being able to select from an exhaustive list of locations.

**Automatically disable high latency Hubs:**

* list all available beacons,
* perform [#measuring-round-trip-time](#measuring-round-trip-time "mention") to all beacons,
* **disable hubs if measured latency exceeds a given threshold,**
* identify enabled Hubs in game UI using the City beacon property.

Your threshold will depend on your game design specifics, but we generally recommend matching in Hubs with latency below 150ms (milliseconds).

We also recommend choosing the name “Hub” in your UI, or a different **name that does not imply these are the only server locations available**. Edgegap orchestrate game servers worldwide across 615+ physical locations and 17+ data center providers to ensure deployment to the ideal location.

{% hint style="info" %}
To let players override [#server-placement](https://docs.edgegap.com/learn/deployments#server-placement "mention") provide beacon IP when [matchmaking](https://docs.edgegap.com/matchmaking/matchmaker-in-depth#endpoint-tickets) or [deploying](https://docs.edgegap.com/docs/api/dedicated-servers#deployments). For best player experience, warn players this may result in increased latency due to remotely located server.
{% endhint %}

Some players with high ping to all beacons due to ISP[^1] issues or slow connection (e.g. wireless/mobile) may cause lags and degrade game experience for others. To mitigate this issue:

* Gradually expand allowed latency maximum and difference (see [Advanced Example Config](https://docs.edgegap.com/matchmaking#advanced-example)),
  * players with high ping may have to wait longer than usual to find a match.
* Alternatively, allow players to override measurement with manual region selection, only sending fake ping values for the player-selected regions only (e.g. 25ms for fast match),
  * this may negatively impact player experience of the players' teammates and opponents.

{% hint style="info" %}
**High beacon ping doesn’t always result in high server ping**. Deployments are available in more locations than beacons. Beacons are orchestrated in real time to prioritize global coverage and reliability.
{% endhint %}

{% hint style="success" %}
See [matchmaking](https://docs.edgegap.com/learn/matchmaking "mention") for **automated ping measurement using our SDKs**.
{% endhint %}

## 🌡️ Measuring Round-Trip Time

In game development both terms “ping” and “latency” usually refer to [packet Round-Trip Time](https://www.cloudflare.com/learning/cdn/glossary/round-trip-time-rtt/).

See [#id-5.-game-integration](https://docs.edgegap.com/matchmaking#id-5.-game-integration "mention") for automatic ping measurement:

* Unity [#matchmaking-sdk](https://docs.edgegap.com/unity/developer-tools#matchmaking-sdk "mention") by Edgegap:
  * [install package using Unity Package Manager for free](https://github.com/edgegap/edgegap-unity-gen2-sdk?tab=readme-ov-file#install-with-git-recommended),
  * [import simple example script](https://github.com/edgegap/edgegap-unity-gen2-sdk?tab=readme-ov-file#import-simple-example) and customize for your needs,
* Unreal Engine [#integration-kit](https://docs.edgegap.com/unreal-engine/developer-tools#integration-kit "mention"):
  * [install from Fab Marketplace](https://www.fab.com/listings/ff17ad88-12a1-49cf-9a41-31695ed11e16) (free for Personal use),
  * [import simple example blueprint](https://blueprintue.com/blueprint/m33u1okj/) and customize to your needs.

Detailed overview of latency measurement process in [Matchmaker](https://docs.edgegap.com/learn/matchmaking/matchmaker-in-depth):

<figure><img src="https://3027732442-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2Fn6ke8Ed6jijjdlPQ4CfP%2Fimage.png?alt=media&#x26;token=c85c70b2-73af-4980-a962-488393d264e6" alt=""><figcaption></figcaption></figure>

## ⏰ High Availability

{% hint style="danger" %}
Beacons are automatically rescaled in real time - adding/removing/replacing existing beacons. Your clients and backend should account for this and **reload list of beacons before each matchmaking round**.
{% endhint %}

## 🧠 Active Cache

**If not using** [**Matchmaker**](https://docs.edgegap.com/learn/matchmaking) (e.g. Advanced Matchmaker users), we recommend implementing additional scalability insurance before a large scale release. **Create your own game backend service** which keeps a centralized cache in memory, responding with beacon locations to game clients without using our Beacons List API for each client request.

This service should actively **make a single API request to update list of beacons every 60 seconds.**

[^1]: Internet Service Provider


# Matchmaking

Get started with Matchmaking quickly and explore example scenarios for various genres.

Matchmaking in match-based games generally aims to:

* **find other players** based on criteria like region, latency, skill, or game parameters;
* **search for servers** to join based on available capacity \[or ping, region, skill, map, mode];
* **start new server** if existing servers are full or don't satisfy player criteria.

Player experience comes first, defining our core objectives:

* high match fill rate and social feature integration (play with friends in groups),
* fast matches with controlled match quality (low latency, shared preferences),
* reliable and predictable matchmaking process with global availability.

{% hint style="success" %}
Alternatively, let players **pick a persistent (always online) server** from a list with [server-browser](https://docs.edgegap.com/learn/server-browser "mention").
{% endhint %}

Follow along this video to get started with our Matchmaker service:

{% embed url="<https://youtu.be/HxtvzvJ1FTk>" %}

## ✔️ Preparation

**Testing this service is entirely free, no credit card required.**

Free Tier allows up to 3 hours of runtime on our shared test cluster, after each restart.

This tutorial assumes you have already:

* [understood Edgegap’s deployment model](https://docs.edgegap.com/orchestration/deployments#id-1.-just-in-time-deployment-dedicated-servers),
* published your server application on Edgegap ([unreal-engine](https://docs.edgegap.com/unreal-engine "mention"), [unity](https://docs.edgegap.com/unity "mention")),
* successfully connected from a game client to your server on Edgegap.

### Matchmaking Architecture

This guide will focus on **Matchmaking API and Backfill API**.

<figure><img src="https://3027732442-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2Fp2QpL1MXYtwSWB2VJN2A%2Fimage.png?alt=media&#x26;token=ecc73799-c2e6-4884-965f-48e4c125659c" alt=""><figcaption></figcaption></figure>

There are four (4) important flows of data when matchmaking is involved:

1. [Matchmaking API](https://docs.edgegap.com/learn/matchmaker-in-depth#matchmaking-api) **is used by Game Clients to communicate with Matchmaker:**
   1. for group management, server assignment, and monitoring,
   2. for ping measurement with [ping-beacons](https://docs.edgegap.com/learn/orchestration/ping-beacons "mention").
2. [deployments](https://docs.edgegap.com/learn/orchestration/deployments "mention") API is used to deploy, scale, and manage your Dedicated Servers by Matchmaker.
3. [Netcode Transports](https://docs.edgegap.com/docs/sample-projects) are used to communicate between Game Clients and Dedicated Servers.
4. [#backfill-match](https://docs.edgegap.com/learn/matchmaker-in-depth#backfill-match "mention") **to replace or add players to a running Server.**

{% hint style="info" %}
After release, **your matchmaker will need to run 24/7** to ensure players across the world can join servers.
{% endhint %}

## 🍀 Simple Example

Start with a simple example and test the basic matchmaking player flow:

* creating the matchmaker instance on the shared [#hosting-cluster](https://docs.edgegap.com/learn/matchmaker-in-depth#hosting-cluster "mention"),
* defining rules and settings in your matchmaker [#configuration](https://docs.edgegap.com/learn/matchmaker-in-depth#configuration "mention"),
* testing player flow and managing tickets with [#matchmaking-api](https://docs.edgegap.com/learn/matchmaker-in-depth#matchmaking-api "mention").

### 1. Set Up on Free Tier

☑️ [Register for your free Edgegap account](https://app.edgegap.com/auth/register) and open the [Matchmaker dashboard page](https://app.edgegap.com/matchmaker-management-v2/matchmakers/list).

☑️ Click on **Create Matchmaker** first, then input:

* matchmaker name - for your own reference, e.g. `quickstart-dev` ,
* upload our Simple Example JSON configuration.

🍀 **Simple Example (Minimal Recommended Configuration):**

{% hint style="danger" %}
**Make sure to change the application** **`name`**  **and** **`version`**  **to match your** [application-and-versions](https://docs.edgegap.com/learn/orchestration/application-and-versions "mention").
{% endhint %}

<pre class="language-json"><code class="lang-json">{
  "version": "3.2.1",
  "inspect": true,
  "max_deployment_retry_count": 3,
  "profiles": {
    "simple-example": {
      "ticket_expiration_period": "5m",
      "ticket_removal_period": "1m",
      "group_inactivity_removal_period": "5m",
      "application": {
        "name": "<a data-footnote-ref href="#user-content-fn-1">my-game-server</a>",
        "version": "<a data-footnote-ref href="#user-content-fn-2">2024.01.30-16.23.00-UTC</a>"
      },
      "rules": {
        "initial": {
          "match_size": {
            "type": "player_count",
            "attributes": {
              "team_count": 1,
              "min_team_size": 2,
              "max_team_size": 2
            }
          },
          "beacons": {
            "type": "latencies",
            "attributes": {
              "difference": 100,
              "max_latency": 200
            }
          }
        },
        "expansions": {}
      }
    }
  }
}
</code></pre>

**Troubleshooting and FAQ:**

<details>

<summary><code>The application configuration is not valid for profile XYZ.</code></summary>

* We couldn’t find your [application-and-versions](https://docs.edgegap.com/learn/orchestration/application-and-versions "mention"), please verify `application`  values.

</details>

<details>

<summary><code>Docker image for '2024.01.30-16.23.00-UTC' is not cached.</code></summary>

[**🌟 Upgrade to Pay as You Go tier**](https://app.edgegap.com/user-settings?tab=memberships) **to unlock** [**instant deployments with Caching**](https://docs.edgegap.com/orchestration/deployments#id-1.-start-a-deployment)**.**

* 4GB+ uncached images may take longer to deploy, resulting in [#id-4.-deployment-error](https://docs.edgegap.com/orchestration/deployments#id-4.-deployment-error "mention"). Consider optimizing your server image size ([Unreal Engine](https://docs.edgegap.com/unreal-engine#optimize-server-build-size) / [Unity](https://docs.edgegap.com/unity#optimize-server-build-size)).
* You may proceed anyway, though we recommend testing your deployment time.

</details>

☑️ If no validation errors appear, hit **Create and Start** and wait for the process to complete. This will result in a new free cluster starting, with your Simple Example matchmaker.

✅ You may now proceed to the next step.

### 2. Explore Configuration

As we release updates to Matchmaker, each new version uses [semantic versioning](https://docs.edgegap.com/learn/matchmaker-in-depth#changelog) to clearly communicate the impact of changes by interpreting format `major.minor.patch`:

* 🔥 `major` versions include breaking changes and require integration review,
* 🌟 `minor` versions include substantial backwards-compatible improvements,
* 🩹 `patch` versions include bug fixes and minor improvements.

[Inspect tickets](https://docs.edgegap.com/learn/matchmaker-in-depth#matchmaking-api) to better understand and debug possible matchmaking flows while in development. We recommend disabling inspect API for your live matchmaker.

**Some** [**deployments may result in Errors**](https://docs.edgegap.com/orchestration/deployments#id-4.-deployment-error)**.** We attempt to resolve this by retrying deployment up to `max_deployment_retry_count` times automatically (without client confirmation).

To ensure that unexpected client crashes or abandoned tickets do not linger and take up your matchmaker resources, unmatched tickets will be cancelled after `ticket_expiration_period` causing their status to change to `CANCELLED` and then permanently deleted after `ticket_removal_period` .

{% hint style="info" %}
[Learn how matchmaker maximizes match fill rate and reduce queue times to less than 10 seconds.](https://docs.edgegap.com/learn/matchmaker-in-depth#find-match)
{% endhint %}

The core of our matchmaking logic is configured in [#matchmaking-profiles](https://docs.edgegap.com/learn/matchmaker-in-depth#matchmaking-profiles "mention"). Each profile is a completely isolated matchmaking queue, pointing to [#app-versions](https://docs.edgegap.com/orchestration/application-and-versions#app-versions "mention") with pre-defined amount of required CPU and memory (RAM) resources.

[#matchmaking-rules](https://docs.edgegap.com/learn/matchmaker-in-depth#matchmaking-rules "mention") in the initial rule set must be met for players to be grouped together, each defined by three properties:

* name of your choosing, e.g. - `match size`,
* rule type, also known as operator, e.g. - `player_count`,
* and lastly operator attributes, e.g. `team_count` or `max_team_size`.

**Player Count Rule**

This is a special rule defining how many players need to match to initiate assignment:

* `team_count` refers to number of teams, 1 team may be used for cooperative or free-for-all modes,
* `min_team_size` refers to the minimum number of players per team.
* `max_team_size` refers to the maximum number of players per team.

Our simple example demonstrates a cooperative game with 2 players.

{% hint style="warning" %}
Player Count rule **is required and may only be defined once** in your initial configuration rules.
{% endhint %}

**Latencies Rule**

**`latencies`** is a special rule optimizing the ping of player matches:

* reduce client-server latency by removing regions with high latency (above threshold),
* improve match fairness by grouping players with similar latency (below difference).

<details>

<summary>Rule Example: <code>beacons</code></summary>

`beacons` rule configured with `"difference": 100, "max_latency": 200`  will match:

:white\_check\_mark: Alice and Bob may match:

* Tokyo is discarded (>200 ms),
* latency for Chicago within 100 ms absolute difference.

<table><thead><tr><th width="180">Beacon City</th><th width="80">Match</th><th width="132">abs(A - B) [ms]</th><th width="164">Alice [ms]</th><th width="164">Bob [ms]</th></tr></thead><tbody><tr><td>Chicago</td><td><span data-gb-custom-inline data-tag="emoji" data-code="2705">✅</span></td><td>75.0</td><td>12.3</td><td>87.3</td></tr><tr><td>Los Angeles</td><td><span data-gb-custom-inline data-tag="emoji" data-code="274c">❌</span></td><td><a data-footnote-ref href="#user-content-fn-3">113.2</a> <span data-gb-custom-inline data-tag="emoji" data-code="274c">❌</span></td><td>145.6</td><td>32.4</td></tr><tr><td><del>Tokyo</del></td><td>n/a</td><td>n/a</td><td><a data-footnote-ref href="#user-content-fn-4"><del>233.2</del></a> <span data-gb-custom-inline data-tag="emoji" data-code="274c">❌</span></td><td><a data-footnote-ref href="#user-content-fn-4"><del>253.2</del></a> <span data-gb-custom-inline data-tag="emoji" data-code="274c">❌</span></td></tr></tbody></table>

:x: Alice and Charlie will never match:

* no beacons have < 200 ms latency for both players,
* Alice lives in North America - Illinois,
* Charlie lives in Asia - Japan.

<table><thead><tr><th width="180">Beacon City</th><th width="80">Match</th><th width="132">abs(A - B) [ms]</th><th width="164">Alice [ms]</th><th width="164">Charlie [ms]</th></tr></thead><tbody><tr><td><del>Chicago</del></td><td>n/a</td><td>n/a</td><td>12.3</td><td><a data-footnote-ref href="#user-content-fn-4"><del>215.6</del></a> <span data-gb-custom-inline data-tag="emoji" data-code="274c">❌</span></td></tr><tr><td><del>Los Angeles</del></td><td>n/a</td><td>n/a</td><td>145.6</td><td><a data-footnote-ref href="#user-content-fn-4"><del>238.3</del></a> <span data-gb-custom-inline data-tag="emoji" data-code="274c">❌</span></td></tr><tr><td><del>Tokyo</del></td><td>n/a</td><td>n/a</td><td><a data-footnote-ref href="#user-content-fn-4"><del>233.2</del></a> <span data-gb-custom-inline data-tag="emoji" data-code="274c">❌</span></td><td>24.2</td></tr></tbody></table>

</details>

{% hint style="warning" %}
Rule `latencies`  is **optional and may only be defined once in your initial configuration** rules.
{% endhint %}

✅ You may now proceed to the next step.

### 3. Review Instance Details

☑️ Review details of your new matchmaker in our dashboard once it’s initialized:

<figure><img src="https://3027732442-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2FY4Byy46pgEoXXmrtH92n%2Fimage.png?alt=media&#x26;token=3fb5fd0e-526e-4f89-ac9a-9ee6809aeaf1" alt=""><figcaption></figcaption></figure>

* **Status** indicates service health, may be ONLINE, OFFLINE, or ERROR.
* **Identifier** helps Edgegap staff find your matchmaker quickly if you need help troubleshooting.
* **Started at** can be useful to track down the latest update time.
* **Size** corresponds to one of our [Pricing Tiers](https://edgegap.com/resources/pricing#matchmaker).
* **API URL** will be used by Game Clients and Game Servers to communicate with your matchmaker.
* **Swagger URL** is a handy openAPI specification GUI we provide to explore API schema.
* **Auth Token** is a unique secret token used by Game Clients and Game Server for authentication.

{% hint style="danger" %}
**Edgegap staff will never ask for your tokens. Regenerate your token if you suspect a security breach.**
{% endhint %}

To test your new matchmaker, **you will need the Swagger URL, API URL and Auth Token**.

✅ You may now proceed to the next step.

{% hint style="info" %}
To update your matchmaker rules in development, edit your configuration and restart it.
{% endhint %}

{% hint style="success" %}
See [#rolling-updates-and-ab-tests](https://docs.edgegap.com/learn/matchmaker-in-depth#rolling-updates-and-ab-tests "mention") for live games and zero-downtime updates.
{% endhint %}

### 4. Test Tickets API

{% hint style="info" %}
**Please wait for up to 5 minutes** after starting your matchmaker to allow DNS propagation to complete.
{% endhint %}

☑️ First, **open your Swagger URL** to inspect your openAPI schema in the swagger GUI:

<figure><img src="https://3027732442-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2FyFErlc8rw9KHMOqloIUF%2Fimage.png?alt=media&#x26;token=5a806adf-d644-4af6-b65e-9af82232bfcd" alt=""><figcaption></figcaption></figure>

☑️ Click on **Authorize** 🔒, paste your **Auth Token**, and confirm by clicking on **Authorize**.

<figure><img src="https://3027732442-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2FWnFM0p4UwDuo6Z5IOiUf%2Fimage.png?alt=media&#x26;token=7cbdff75-7f6b-467c-8df3-fa568b846dac" alt=""><figcaption></figcaption></figure>

☑️ Scroll down to **Ticket API** **- POST /tickets**, expand and click **Try it out**.

<figure><img src="https://3027732442-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2FpxA3FxrxhlelzSWvb5CO%2Fimage.png?alt=media&#x26;token=8fc4fa97-44d5-48e3-8c02-c2dd49c6cd74" alt=""><figcaption></figcaption></figure>

☑️ Preview your request:

* notice `player_ip` set to `null` - this will cause Matchmaker to use the IP address automatically added to your request (see [#server-to-server-api](https://docs.edgegap.com/learn/matchmaker-in-depth#server-to-server-api "mention") for alternatives),
* `profile` refers to your [#matchmaking-profiles](https://docs.edgegap.com/learn/matchmaker-in-depth#matchmaking-profiles "mention"),
* `attributes` include values for your matchmaker rules, in this case for the `latencies` rule,
  * rule `player_count` is the only rule which doesn’t require any attributes in player tickets.

☑️ Click **Execute** and review the response to your player ticket request:

* `id` is your unique matchmaking ticket ID, save this to check on your ticket later,
* `profile` confirming the choice of [#matchmaking-profiles](https://docs.edgegap.com/learn/matchmaker-in-depth#matchmaking-profiles "mention"),
* `group_id` is a unique [group ID issued to every ticket, a solo player is represented as a group of 1](https://docs.edgegap.com/learn/matchmaker-in-depth#group-up),
* `team_id` is a unique team ID issued to every player once `TEAM_FOUND` status is reached,
  * [each team can contain multiple groups, not exceeding the configured team size](https://docs.edgegap.com/learn/matchmaker-in-depth#matchmaking-rules),
* `player_ip` is the resolved public IP address of the player, regardless of the identification method,
* `assignment` is set to `null` to indicate the ticket has not been matched or assigned to a server,
* `created_at` provides information about when the player ticket was created for game UI usage,
* `status` indicates the current status of the ticket, all tickets start in `SEARCHING` .

<figure><img src="https://3027732442-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2FZauPhgT9t1roetX4yc7g%2Fimage.png?alt=media&#x26;token=7834faf8-ce73-42dc-bae0-0293f05f1ea1" alt=""><figcaption></figcaption></figure>

☑️ Create a second ticket by hitting **Execute** again, so our two players match and a server is started.

☑️ Collapse POST /tickets and open **GET /tickets/{ticketId}**, then click **Try it out**.

☑️ Input ticket ID from the response in previous step and click **Execute**.

<figure><img src="https://3027732442-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2FNznf5aHqhWefs77SFbzJ%2Fimage.png?alt=media&#x26;token=1d04803c-fbe6-4a19-9ef7-f814ea87affe" alt=""><figcaption></figcaption></figure>

☑️ Review the updated assignment for your player ticket:

* status changed to `MATCH_FOUND` first, while keeping `assignment` set to `null` to indicate players have matched and a server is being assigned,

<figure><img src="https://3027732442-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2FGzBkyUepbqP71lFWG052%2Fimage.png?alt=media&#x26;token=a0412446-cc4f-4070-a14c-fef79046f3f7" alt=""><figcaption></figcaption></figure>

☑️ Click **Execute** again to check on your ticket, and review the updated assignment for your ticket:

* status changed to `HOST_ASSIGNED` with `assignment` containing details of the assigned server.

<figure><img src="https://3027732442-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2FWnbG4B1KFoxttkz5bALl%2Fimage.png?alt=media&#x26;token=12a10044-2117-4a6d-845a-76c243231552" alt=""><figcaption></figcaption></figure>

<details>

<summary>Troubleshooting &#x26; FAQ</summary>

My ticket is stuck in `SEARCHING` .

* Please verify that you’ve created enough tickets with overlapping criteria adhering to your configuration.

***

My ticket is stuck switching between `MATCH_FOUND` and `TEAM_FOUND` repeatedly.

* Free Tier accounts are limited to 1 deployment at a time. Please consider upgrading or stop your current deployment to start a new one.

***

My ticket goes straight to `CANCELLED`.

* Your ticket reached it’s expiration. Recreate a new ticket or increase the expiration period in your configuration for testing purposes.

***

I receive HTTP 404 Not Found when checking on my ticket.

* Your ticket was removed either by a DELETE request, or by reaching it’s removal period (starts after ticket is expired, defined in your configuration). Recreate a new ticket or increase the expiration/removal periods in your configuration for testing purposes.

</details>

☑️ [Inspect your new deployment in our dashboard](https://app.edgegap.com/deployment-management/deployments/list):

* notice each deployment is tagged with all ticket IDs and profile for added traceability.

<figure><img src="https://3027732442-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2FG4Ear9NrMHhgFH6T4ODB%2Fimage.png?alt=media&#x26;token=acc9831c-a9d2-4eb2-8c39-c81b8e61ddd2" alt=""><figcaption></figcaption></figure>

A few seconds after finding a match, memberships proceed to `status:HOST_ASSIGNED`  indicating that your [deployment is now ready and your game server is initializing](https://docs.edgegap.com/orchestration/deployments#id-3.-deployment-ready).

Each player reads their `ticket_id`  and  `assignment`  and attempt connection using the [**FQDN**](#user-content-fn-5)[^5] **(deployment URL)** and the **External Port**. Your game server may be still initializing at this time, so **players must retry connection several times**, until exceeding your usual server initialization time:

{% tabs %}
{% tab title="Unreal Engine" %}
To **connect from PIE (Editor)** during development and testing, press the tilde key `~`  and type `open {URL}:{port}`  and wait for your editor to load the map.

To **connect from a game client build** (and in live production environment) try

* Unreal Engine [⚡ Integration Kit](https://docs.edgegap.com/learn/unreal-engine-games/developer-tools#integration-kit):
  * [install from Fab Marketplace](https://www.fab.com/listings/ff17ad88-12a1-49cf-9a41-31695ed11e16) (free for Personal use),
  * [import simple example blueprint](https://blueprintue.com/blueprint/m33u1okj/) and customize to your needs.

{% hint style="success" %}
In case of failed connections or dark screen consult our [troubleshooting guide](https://docs.edgegap.com/unreal-engine#troubleshooting-and-faq).
{% endhint %}
{% endtab %}

{% tab title="Unity" %}
To **connect your Unity Editor** or **game client** to your cloud deployment, input:

* **Deployment** **URL** pointing to the server's IP, usually in `NetworkManager` component.
* **External port** mapping to the [server's internal listen port](https://docs.edgegap.com/orchestration/application-and-versions#port-mapping), usually in a Transport component.

{% hint style="success" %}
In case of connection timeout or other issues consult our [troubleshooting guide](https://docs.edgegap.com/unity#troubleshooting-and-faq-4).
{% endhint %}
{% endtab %}
{% endtabs %}

{% hint style="info" %}
We do not ask players to confirm the match, as we aim to provide shortest possible time to gameplay, high match fill rate, and minimize queue dodging and match cancellations.
{% endhint %}

Players should **save their assignment ID persistently between game restarts**, so that in case of game client crash they can retrieve the connection details and attempt reconnecting.

{% hint style="success" %}
See [matchmaking](https://docs.edgegap.com/learn/matchmaking "mention") and our SDKs with automatic reconnect function and more.
{% endhint %}

☑️ Try connecting from your game client to the assigned server.

{% hint style="warning" %}
If you’re experiencing high latency, your netcode integration may be configured to simulate network latency. **Disable VPN when testing** for more realistic conditions and receive a [low-latency deployment](https://docs.edgegap.com/orchestration/deployments#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.

✅ You may now proceed to the next step.

{% hint style="info" %}
Find the openAPI specification for testing at `{matchmaker-url}/swagger/v1/swagger.json`.
{% endhint %}

### 5. Game Integration

Matchmaker integrates with:

* **Game Client**, to [manage groups, memberships, assignments, and tickets](https://docs.edgegap.com/learn/matchmaker-in-depth#group-up),
* **Dedicated Server**, to [#backfill-match](https://docs.edgegap.com/learn/matchmaker-in-depth#backfill-match "mention") after a player leaves.

☑️ In **Game Client**, we recommend providing ticket status updates to players using in-game UI for best player experience. See:

* Unity [#matchmaking-sdk](https://docs.edgegap.com/unity/developer-tools#matchmaking-sdk "mention") by Edgegap:
  * [install package using Unity Package Manager for free](https://github.com/edgegap/edgegap-unity-gen2-sdk?tab=readme-ov-file#install-with-git-recommended),
  * [import simple example script](https://github.com/edgegap/edgegap-unity-gen2-sdk?tab=readme-ov-file#import-simple-example) and customize for your needs,
* Unreal Engine [#integration-kit](https://docs.edgegap.com/unreal-engine/developer-tools#integration-kit "mention"):
  * [install from Fab Marketplace](https://www.fab.com/listings/ff17ad88-12a1-49cf-9a41-31695ed11e16) (free for Personal use),
  * [import simple example blueprint](https://blueprintue.com/blueprint/m33u1okj/) and customize to your needs.

☑️ In **Game Client**, ensure you’re handling retryable `429 Too Many Requests`  errors with an exponential backoff and retry, giving matchmaker time to recover during sudden traffic bursts.

☑️ In **Game Client**, ensure you’re handling non-retryable errors:

* `404 Not Found` - ticket has been deleted,
* `500 Internal Server Error` - temporary service outage.

☑️ In **Game Server**, read player preferences and initial server context:

1. [Injected Variables (Matchmaker)](https://docs.edgegap.com/learn/matchmaker-in-depth#injected-environment-variables) **to retrieve initial players’ matchmaking data.**
2. [Injected Variables (App Versions)](https://docs.edgegap.com/orchestration/application-and-versions#other-parameters-optional) for version parameters, settings, and secrets.
3. [Injected Variables (Deployment)](https://docs.edgegap.com/orchestration/deployments#injected-environment-variables) for deployment information, IP, location, etc...

{% hint style="info" %}
Use [GetEnvironmentVariable in C#](https://learn.microsoft.com/en-us/dotnet/api/system.environment.getenvironmentvariable?view=net-8.0) or [GetEnvironmentVariable in C++](https://dev.epicgames.com/documentation/en-us/unreal-engine/API/Runtime/Core/GenericPlatform/FGenericPlatformMisc/GetEnvironmentVariable) to get variable values.
{% endhint %}

☑️ Once players connect, **Game Server and Game Clients** start a loading scene - 3D scene, a lobby-like social UI, or a loading screen with a progress bar, to indicate initialization is progressing.

☑️ Ensure your [deployment will be stopped](https://docs.edgegap.com/docs/deployment#stop-a-deployment) properly once the match concluded.

🙌 Congratulations, you’ve completed Matchmaking integration! To learn more, keep reading.

## 🏁 Advanced Example

A full fledged configuration utilizing all matchmaking features including [#matchmaking-profiles](https://docs.edgegap.com/learn/matchmaker-in-depth#matchmaking-profiles "mention"), [#matchmaking-rules](https://docs.edgegap.com/learn/matchmaker-in-depth#matchmaking-rules "mention"), and [#rule-expansion](https://docs.edgegap.com/learn/matchmaker-in-depth#rule-expansion "mention") may look like this:

<details>

<summary>🏁 Advanced Example (Complete Example Configuration)</summary>

```json
{
  "version": "3.2.1",
  "inspect": true,
  "max_deployment_retry_count": 3,
  "allowed_cors_origins": [
    "https://*.my-game-server.com"
  ],
  "profiles": {
    "advanced-example": {
      "ticket_expiration_period": "5m",
      "ticket_removal_period": "1m",
      "group_inactivity_removal_period": "5m"
      "application": {
        "name": "my-game-server",
        "version": "2024.01.30-16.23.00-UTC"
      },
      "rules": {
        "initial": {
          "match_size": {
            "type": "player_count",
            "attributes": {
              "team_count": 1,
              "min_team_size": 4,
              "max_team_size": 4
            }
          },
          "beacons": {
            "type": "latencies",
            "attributes": {
              "difference": 125,
              "max_latency": 125
            }
          },
          "elo_rating": {
            "type": "number_difference",
            "attributes": {
              "max_difference": 50
            }
          },
          "selected_game_mode": {
            "type": "string_equality"
          },
          "selected_map": {
            "type": "intersection",
            "attributes": {
              "overlap": 1
            }
          },
          "backfill_group_size": {
            "type": "intersection",
            "attributes": {
              "overlap": 1
            }
          }
        },
        "expansions": {
          "30": {
            "elo_rating": {
              "max_difference": 150
            },
            "beacons": {
              "difference": 125,
              "max_latency": 250
            }
          },
          "60": {
            "elo_rating": {
              "max_difference": 200
            }
          },
          "180": {
            "match_size": {
              "team_count": 1,
              "min_team_size": 1,
              "max_team_size": 4
            },
            "beacons": {
              "difference": 99999,
              "max_latency": 99999
            }
          }
        }
      }
    }
  }
}
```

</details>

## 🎾 Custom Lobby

Custom lobbies (private lobbies, sandbox levels) are a very popular option for couch multiplayer and testing new features in games before they enter main game modes. Typically require the least amount of restrictions, but aim to ensure that players can [#group-up](https://docs.edgegap.com/learn/matchmaker-in-depth#group-up "mention").

<details>

<summary>🎾 Custom Lobby Example</summary>

```json
{
  "version": "3.2.1",
  "inspect": true,
  "max_deployment_retry_count": 3,
  "profiles": {
    "custom-lobby-example": {
      "ticket_expiration_period": "3m",
      "ticket_removal_period": "1m",
      "group_inactivity_removal_period": "5m"
      "application": {
        "name": "my-game-server",
        "version": "2024.01.30-16.23.00-UTC"
      },
      "rules": {
        "initial": {
          "match_size": {
            "type": "player_count",
            "attributes": {
              "team_count": 1,
              "min_team_size": 4,
              "max_team_size": 4
            }
          },
          "lobby_id": {
            "type": "intersection",
            "attributes": {
              "overlap": 1
            }
          }
        },
        "expansions": {
          "10": {
            "match_size": {
              "team_count": 1,
              "min_team_size": 1,
              "max_team_size": 4
            }
          }
        }
      }
    }
  }
}
```

</details>

{% hint style="info" %}
For private lobbies without public access, set `"team_size": 1`  and make the group owner start the game alone. Owner may share group and host assignment details to any number of members to join up.
{% endhint %}

{% hint style="success" %}
Add `custom-lobby-example`  profile **in your existing matchmaker** to support custom lobbies.
{% endhint %}

## 🥛 Backfill Showcase

Building on [#simple-example](#simple-example "mention"), this configuration showcases [Backfill](https://docs.edgegap.com/learn/matchmaker-in-depth#backfill-match) with [Groups](https://docs.edgegap.com/learn/matchmaker-in-depth#group-up).

<details>

<summary><span data-gb-custom-inline data-tag="emoji" data-code="1f95b">🥛</span> Backfill Configuration Example</summary>

```json
{
  "version": "3.2.1",
  "inspect": true,
  "max_deployment_retry_count": 3,
  "profiles": {
    "backfill-example": {
      "ticket_expiration_period": "5m",
      "ticket_removal_period": "1m",
      "group_inactivity_removal_period": "5m",
      "application": {
        "name": "my-game-server",
        "version": "2024.01.30-16.23.00-UTC"
      },
      "rules": {
        "initial": {
          "match_size": {
            "type": "player_count",
            "attributes": {
              "team_count": 1,
              "min_team_size": 4,
              "max_team_size": 4
            }
          },
          "beacons": {
            "type": "latencies",
            "attributes": {
              "difference": 100,
              "max_latency": 200
            }
          },
          "backfill_group_size": {
            "type": "intersection",
            "attributes": {
              "overlap": 1
            }
          }
        },
        "expansions": {}
      }
    }
  }
}
```

</details>

Optionally, some games may have special matchmaking needs, such as:

* allow new players to join games in progress (friends or "randoms"),
* replace players who abandon (leavers) after server starts to avoid restarting match,
* allow spectators to join and observe tournament or friends’ matches (e-sports),
* centralize players in larger servers to provide more social interactions (MMOs).

Backfill is a **server-owned ticket representing players currently connected to the server.** This ensures newly added players will respect your matchmaking rules when matched with current players.

{% hint style="warning" %}
[#backfill-match](https://docs.edgegap.com/learn/matchmaker-in-depth#backfill-match "mention") to replace Seat/Match sessions. Matchmaker only supports Default session.
{% endhint %}

<figure><img src="https://3027732442-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2FJhdLAJYga4z2sjxLj6LM%2FUntitled-2024-10-29-1018.png?alt=media&#x26;token=279136ba-a15e-46b0-a119-8419b8aca044" alt=""><figcaption><p>Backfill Scenarios Visualized</p></figcaption></figure>

{% hint style="success" %}
**Backfills ignore** `player_count`  **rule, and always match exactly one group**. `backfill_group_size`  controls team capacity with round-robin strategy, filling teams evenly in a controlled manner.
{% endhint %}

**The steps to complete a successful backfill are:**

1. Server creates one Backfill per team missing players, using values from:
   * Real `assignment`  data retrieved from [#injected-environment-variables](https://docs.edgegap.com/orchestration/deployments#injected-environment-variables "mention") (deployment).
   * Currently connected players' `tickets`:
     * from [#injected-variables](https://docs.edgegap.com/learn/matchmaker-in-depth#injected-variables "mention") (matchmaker), previous backfills' `assigned_ticket` response, or mock data manipulated to match specific players,
     * replace `backfill_group_size`  values with possible group sizes [up to available capacity](#user-content-fn-6)[^6],
2. Game clients create new tickets (memberships) and include `backfill_group_size`  values:
   * `"1"`  if the player is matchmaking alone.
   * [`"2"`  if the player is a part of a matchmaking group with 2x members total](#user-content-fn-7)[^7].
   * `"new"`  if players enabled starting new games in addition to joining in-progress games.
3. Game clients proceed to [#find-match](https://docs.edgegap.com/learn/matchmaker-in-depth#find-match "mention") and pair players with the matching backfill.
4. If the backfilled group didn't completely fill the team, the server may repeat this process with the newly backfilled players' tickets, to add more players and reach desired team sizes.

{% hint style="info" %}
To create a Backfill-only profile, set `min_team_size`  to 999,999 and disable ticket + ticket matches.
{% endhint %}

<details>

<summary>🥛 Backfill Example (Backfill Showcase)</summary>

```json
{
  "profile": "backfill-example",
  "attributes": {
    "assignment": {
      "request_id": "cd28e6c66554",
      "fqdn": "cd28e6c66554.pr.edgegap.net",
      "public_ip": "192.168.2.14",
      "ports": {
        "game": {
          "internal": 7777,
          "external": 56890,
          "link": "cd28e6c66554.pr.edgegap.net:56890",
          "protocol": "UDP"
        },
        "web": {
          "internal": 22,
          "external": 57440,
          "link": "cd28e6c66554.pr.edgegap.net:57440",
          "protocol": "TCP"
        },
        "server": {
          "internal": 80,
          "external": 50110,
          "link": "cd28e6c66554.pr.edgegap.net:50110",
          "protocol": "TCP"
        }
      },
      "location": {
        "city": "Montreal",
        "country": "Canada",
        "continent": "North America",
        "administrative_division": "Quebec",
        "timezone": "America/Toronto"
      }
    }
  },
  "tickets": {
    "c3d057h5h6f7j889fk43": {
      "player_ip": "174.25.48.238",
      "attributes": {
        "beacons": {
          "New York": 12.2,
          "Los Angeles": 45.3,
          "Paris": 78.3
        },
        "backfill_group_size": [
          "2",
          "1"
        ]
      },
      "group_id": "192bb97e-7fd6-4d86-8ce4-61c53c9fef16",
      "id": "c3d057h5h6f7j889fk43",
      "created_at": "2024-08-20T13:38:05.251393+00:00"
    },
    "cqg0bg9583s738h9dkf6": {
      "player_ip": "217.34.85.142",
      "attributes": {
        "beacons": {
          "New York": 21.0,
          "Los Angeles": 30.2,
          "Paris": 101.1
        },
        "backfill_group_size": [
          "2",
          "1"
        ]
      },
      "group_id": "aea7df3c-d391-4ea3-a3ec-dded422fe7c8",
      "id": "cqg0bg9583s738h9dkf6",
      "created_at": "2024-08-20T13:38:05.251393+00:00"
    }
  },
  "assigned_ticket": null
}
```

</details>

<details>

<summary>🥛 Backfill Assignment Example (Backfill Showcase)</summary>

```json
{
  "profile": "backfill-example",
  "attributes": {
    "assignment": {
      "request_id": "cd28e6c66554",
      "fqdn": "cd28e6c66554.pr.edgegap.net",
      "public_ip": "192.168.2.14",
      "ports": {
        "game": {
          "internal": 7777,
          "external": 56890,
          "link": "cd28e6c66554.pr.edgegap.net:56890",
          "protocol": "UDP"
        },
        "web": {
          "internal": 22,
          "external": 57440,
          "link": "cd28e6c66554.pr.edgegap.net:57440",
          "protocol": "TCP"
        },
        "server": {
          "internal": 80,
          "external": 50110,
          "link": "cd28e6c66554.pr.edgegap.net:50110",
          "protocol": "TCP"
        }
      },
      "location": {
        "city": "Montreal",
        "country": "Canada",
        "continent": "North America",
        "administrative_division": "Quebec",
        "timezone": "America/Toronto"
      }
    }
  },
  "tickets": {
    "c3d057h5h6f7j889fk43": {
      "player_ip": "174.25.48.238",
      "attributes": {
        "beacons": {
          "New York": 12.2,
          "Los Angeles": 45.3,
          "Paris": 78.3
        },
        "backfill_group_size": [
          "2",
          "1"
        ]
      },
      "group_id": "192bb97e-7fd6-4d86-8ce4-61c53c9fef16",
      "id": "c3d057h5h6f7j889fk43",
      "created_at": "2024-08-20T13:38:05.251393+00:00"
    },
    "cqg0bg9583s738h9dkf6": {
      "player_ip": "217.34.85.142",
      "attributes": {
        "beacons": {
          "New York": 21.0,
          "Los Angeles": 30.2,
          "Paris": 101.1
        },
        "backfill_group_size": [
          "2",
          "1"
        ]
      },
      "group_id": "aea7df3c-d391-4ea3-a3ec-dded422fe7c8",
      "id": "cqg0bg9583s738h9dkf6",
      "created_at": "2024-08-20T13:38:05.251393+00:00"
    }
  },
  "assigned_ticket": {
    "profile": "backfill-example",
    "player_ip": "244.13.201.244",
    "attributes": {
      "beacons": {
        "New York": 30.2,
        "Los Angeles": 10.5,
        "Paris": 123.9
      },
      "backfill_group_size": [
        "new",
        "1"
      ]
    },
    "id": "cqg0bg550h7uujd77khg",
    "group_id": "e0cf41c0-f88f-456e-a032-03b1d6821a9a",
    "created_at": "2024-08-20T13:38:08.251393+00:00",
    "status": "HOST_ASSIGNED"
  }
}
```

</details>

{% hint style="info" %}
See [Mirror Seat Management](https://docs.edgegap.com/docs/sample-projects/mirror-on-edgegap#bonus-seat-sessions-management) and [FishNet Seat Management](https://docs.edgegap.com/docs/sample-projects/fishnet-on-edgegap#bonus-seat-sessions-management) for **player connection monitoring**.
{% endhint %}

## ⚔️ Competitive Games

Competitive games focus on players competing against each other to achieve victory, whether as individuals (free for all) or teams. Ensure fair and balanced matches by pairing players or teams of similar skill levels, and maintain game pace by quickly finding fair competition.

<details>

<summary>⚔️ Competitive Game Example</summary>

```json
{
  "version": "3.2.1",
  "inspect": true,
  "max_deployment_retry_count": 3,
  "profiles": {
    "casual-example": {
      "ticket_expiration_period": "5m",
      "ticket_removal_period": "1m",
      "group_inactivity_removal_period": "5m",
      "application": {
        "name": "my-game-server",
        "version": "2024.01.30-16.23.00-UTC"
      },
      "rules": {
        "initial": {
          "match_size": {
            "type": "player_count",
            "attributes": {
              "team_count": 2,
              "min_team_size": 5,
              "max_team_size": 5
            }
          },
          "beacons": {
            "type": "latencies",
            "attributes": {
              "difference": 125,
              "max_latency": 150
            }
          },
          "selected_maps": {
            "type": "intersection",
            "attributes": {
              "overlap": 1
            }
          },
          "backfill_group_size": {
            "type": "intersection",
            "attributes": {
              "overlap": 1
            }
          }
        },
        "expansions": {
          "30": {
            "beacons": {
              "difference": 125,
              "max_latency": 250
            }
          },
          "180": {
            "beacons": {
              "difference": 99999,
              "max_latency": 99999
            }
          }
        }
      }
    },
    "competitive-example": {
      "ticket_expiration_period": "5m",
      "ticket_removal_period": "1m",
      "group_inactivity_removal_period": "5m"
      "application": {
        "name": "my-game-server",
        "version": "2024.01.30-16.23.00-UTC"
      },
      "rules": {
        "initial": {
          "match_size": {
            "type": "player_count",
            "attributes": {
              "team_count": 2,
              "min_team_size": 5,
              "max_team_size": 5
            }
          },
          "beacons": {
            "type": "latencies",
            "attributes": {
              "difference": 125,
              "max_latency": 150
            }
          },
          "versus_ranks": {
            "type": "intersection",
            "attributes": {
              "overlap": 1
            }
          }
        },
        "expansions": {
          "120": {
            "beacons": {
              "difference": 125,
              "max_latency": 250
            }
          }
        }
      }
    },
    "challenger-example": {
      "ticket_expiration_period": "5m",
      "ticket_removal_period": "1m",
      "group_inactivity_removal_period": "5m"
      "application": {
        "name": "my-game-server",
        "version": "2024.01.30-16.23.00-UTC"
      },
      "rules": {
        "initial": {
          "match_size": {
            "type": "player_count",
            "attributes": {
              "team_count": 2,
              "min_team_size": 5,
              "max_team_size": 5
            }
          },
          "beacons": {
            "type": "latencies",
            "attributes": {
              "difference": 125,
              "max_latency": 150
            }
          },
          "elo_rating": {
            "type": "number_difference",
            "attributes": {
              "max_difference": 50
            }
          }
        },
        "expansions": {
          "120": {
            "beacons": {
              "difference": 125,
              "max_latency": 250
            }
          }
        }
      }
    }
  }
}
```

</details>

You may **define multiple teams with 1 or more players each**, for example:

<table><thead><tr><th width="300">Game Mode</th><th>Team Count</th><th>Team Size</th><th>Total Players</th></tr></thead><tbody><tr><td>5v5 FPS</td><td>2</td><td>5</td><td><strong>10</strong></td></tr><tr><td>5v5 MOBA</td><td>2</td><td>5</td><td><strong>10</strong></td></tr><tr><td>20x3 Battle Royale</td><td>20</td><td>3</td><td><strong>60</strong></td></tr><tr><td>10p Free For All</td><td>1</td><td>10</td><td><strong>10</strong></td></tr></tbody></table>

Define multiple [#matchmaking-profiles](https://docs.edgegap.com/learn/matchmaker-in-depth#matchmaking-profiles "mention") for game mode specific rules and settings, and [expand as needed](https://docs.edgegap.com/learn/matchmaker-in-depth#rule-expansion).

* **For all matches:**
  * restrict [matchmaking latency](https://docs.edgegap.com/learn/matchmaker-in-depth#ping-optimization) to prevent matching players far away,
  * [#group-up](https://docs.edgegap.com/learn/matchmaker-in-depth#group-up "mention") for pre-made parties and prevent exceeding team sizes,
  * slowly relax latency restrictions over time to find more players,
  * allocate more CPU or memory with different [#app-versions](https://docs.edgegap.com/orchestration/application-and-versions#app-versions "mention") for specific profiles,
* **For casual matches:**
  * omit rank restrictions to maximize match speed and match fill rate,
  * let players provide their map preferences to find a map suitable for everyone,
  * specify backfill group size to replace leavers without exceeding team sizes,
  * remove latency limitations to guarantee a match after 3 minutes (180s) of queue time.
* **For competitive matches:**
  * restrict rank to only allow opponents with similar skill level,
  * use rank-up or rank-down ranks to match players at the league's rank extremes.
* **For the top 1% of high skill matches (challengers):**
  * use numerical skill ratings (ELO) to gain fine control over skill distribution in matches,
  * wait longer before relaxing latency requirements due to lower amount of players.

{% hint style="success" %}
Using multiple profiles to **separate casual game modes, competitive game modes, and top-tier challenger** players allows you to customize rules and expansions for each type of player separately.
{% endhint %}

## 🤝 Cooperative Games

Cooperative games require players to work together as a team towards a common goal, or AI opponent. Align players with similar preferences and gameplay habits. Replace players who leave, and improve [#connection-quality](https://docs.edgegap.com/orchestration/ping-beacons#connection-quality "mention") to provide a responsive player experience.

<details>

<summary>🤝 Cooperative Game Example</summary>

```json
{
  "version": "3.2.1",
  "inspect": true,
  "max_deployment_retry_count": 3,
  "profiles": {
    "cooperative-example": {
      "ticket_expiration_period": "3m",
      "ticket_removal_period": "1m",
      "group_inactivity_removal_period": "5m",
      "application": {
        "name": "my-game-server",
        "version": "2024.01.30-16.23.00-UTC"
      },
      "rules": {
        "initial": {
          "match_size": {
            "type": "player_count",
            "attributes": {
              "team_count": 1,
              "min_team_size": 4,
              "max_team_size": 4
            }
          },
          "beacons": {
            "type": "latencies",
            "attributes": {
              "difference": 125,
              "max_latency": 150
            }
          },
          "selected_difficulty": {
            "type": "string_equality"
          },
          "selected_map": {
            "type": "intersection",
            "attributes": {
              "overlap": 1
            }
          },
          "player_level": {
            "type": "number_difference",
            "attributes": {
              "max_difference": 10
            }
          },
          "backfill_group_size": {
            "type": "intersection",
            "attributes": {
              "overlap": 1
            }
          },
          "moderation_flags": {
            "type": "intersection",
            "attributes": {
              "overlap": 1
            }
          }
        },
        "expansions": {
          "30": {
            "beacons": {
              "difference": 125,
              "max_latency": 250
            },
            "player_level": {
              "max_difference": 20
            }
          },
          "60": {
            "match_size": {
              "team_count": 1,
              "min_team_size": 2,
              "max_team_size": 4
            }
          },
          "150": {
            "match_size": {
              "team_count": 1,
              "min_team_size": 1,
              "max_team_size": 4
            }
          }
        }
      }
    }
  }
}
```

</details>

With team count 1 and maximum team size of 4, **require up to 4 players per match**.

Define multiple [#matchmaking-profiles](https://docs.edgegap.com/learn/matchmaker-in-depth#matchmaking-profiles "mention") for game modes specific rules and settings:

* start with minimum of 4 players to keep players in queue and maximize match fill rate,
* restrict [matchmaking latency](https://docs.edgegap.com/learn/matchmaker-in-depth#ping-optimization) to prevent matching players far away,
* let players choose a particular game difficulty to suit everybody’s skill level,
* let players provide their map preferences to find a map suitable for everyone,
* restrict player level difference to require similar degree of game progression,
* specify backfill group size to replace leavers without exceeding server capacity,
* use moderation flags to separate low-karma players and cheaters from general population,
* [#group-up](https://docs.edgegap.com/learn/matchmaker-in-depth#group-up "mention") for pre-made parties and to fill teams without exceeding server capacity,
* allocate more CPU or memory using different [#app-versions](https://docs.edgegap.com/orchestration/application-and-versions#app-versions "mention") for other profiles.

Start with the ideal conditions, and [expand restrictions](https://docs.edgegap.com/learn/matchmaker-in-depth#rule-expansion) to ensure quick matches:

* relax latency restrictions over time to find more players,
* increase allowed player level difference to find more players,
* decrease minimum team size to require less players and start the game sooner,
  * server may fill empty slots with AI teammates,
  * or [#backfill-match](https://docs.edgegap.com/learn/matchmaker-in-depth#backfill-match "mention") to add players later,
* set minimum team size to 1 to launch the game solo after 150s of queue time

## 🎈 Social Games

Social games focus on building connections and relationships between players through collaboration, communication, and shared experience. Support high number of players, maximize match fill rate, and align player preferences and gameplay habits. Replace players who leave, and ensure high [#connection-quality](https://docs.edgegap.com/orchestration/ping-beacons#connection-quality "mention") to provide a responsive player experience.

<details>

<summary>🎈 Social Game Example</summary>

```json
{
  "version": "3.2.1",
  "inspect": true,
  "max_deployment_retry_count": 3,
  "profiles": {
    "social-example": {
      "ticket_expiration_period": "3m",
      "ticket_removal_period": "1m",
      "group_inactivity_removal_period": "5m",
      "application": {
        "name": "my-game-server",
        "version": "2024.01.30-16.23.00-UTC"
      },
      "rules": {
        "initial": {
          "match_size": {
            "attributes": {
              "team_count": 1,
              "min_team_size": 50,
              "max_team_size": 50
            },
            "type": "player_count"
          },
          "beacons": {
            "attributes": {
              "difference": 125,
              "max_latency": 150
            },
            "type": "latencies"
          },
          "selected_mode": {
            "type": "intersection",
            "attributes": {
              "overlap": 1
            }
          },
          "backfill_group_size": {
            "type": "intersection",
            "attributes": {
              "overlap": 1
            }
          },
          "moderation_flags": {
            "type": "intersection",
            "attributes": {
              "overlap": 1
            }
          }
        },
        "expansions": {
          "15": {
            "beacons": {
              "difference": 125,
              "max_latency": 250
            },
            "match_size": {
              "team_count": 1,
              "min_team_size": 20,
              "max_team_size": 50
            }
          },
          "30": {
            "match_size": {
              "team_count": 1,
              "min_team_size": 10,
              "max_team_size": 50
            }
          },
          "150": {
            "match_size": {
              "team_count": 1,
              "min_team_size": 1,
              "max_team_size": 50
            }
          }
        }
      }
    }
  }
}
```

</details>

With team count 1 (free for all) and maximum team size of 50, **require up to 50 players per match**.

Define [#matchmaking-profiles](https://docs.edgegap.com/learn/matchmaker-in-depth#matchmaking-profiles "mention") for game modes specific rules and settings:

* restrict [matchmaking latency](https://docs.edgegap.com/learn/matchmaker-in-depth#ping-optimization) to prevent matching players far away,
* let players provide their game mode preferences and find a mode suitable for everyone,
* specify backfill group size to replace leavers without exceeding server capacity,
* use moderation flags to separate low-karma players and cheaters from general population,
* [#group-up](https://docs.edgegap.com/learn/matchmaker-in-depth#group-up "mention") for pre-made lobbies or to fill teams without exceeding server capacity,
* allocate more CPU or memory using different [#app-versions](https://docs.edgegap.com/orchestration/application-and-versions#app-versions "mention") for other profiles.

Start with the ideal conditions, and [expand restrictions](https://docs.edgegap.com/learn/matchmaker-in-depth#rule-expansion) to ensure quick matches:

* relax latency restrictions over time to find more players,
* slowly decrease minimum team size to require less players and start the game sooner,
  * server may fill empty slots with AI players,
  * or [#backfill-match](https://docs.edgegap.com/learn/matchmaker-in-depth#backfill-match "mention") to add players later,
* set minimum team size to 1 to launch the game solo after 150s of queue time.

[^1]: replace with your own application name

[^2]: replace with your own application version

[^3]: maximum difference exceeded

[^4]: maximum latency exceeded

[^5]: Fully Qualified Domain Name

[^6]: e.g. for 3 free slots = \["3", "2", "1"]

[^7]: replace "2" with the number of actual group members


# In-Depth Look

Learn more about Edgegap’s no-code matchmaker concepts in-depth and customize to your needs.

{% hint style="info" %}
If you need help, [please reach out to us over Discord](https://discord.gg/MmJf8fWjnt). For live games support see our [ticketing system](https://edgegap.atlassian.net/servicedesk/customer/portal/3).
{% endhint %}

## ✔️ Introduction

Matchmaking in match-based games generally aims to:

* **find other players** based on criteria like region, latency, skill, or game parameters;
* **search for servers** to join based on available capacity \[or ping, region, skill, map, mode];
* **start new server** if existing servers are full or don't satisfy player criteria.

Player experience comes first, defining our core objectives:

* high match fill rate and social feature integration (play with friends in groups),
* fast matches with controlled match quality (low latency, shared preferences),
* reliable and predictable matchmaking process with global availability.

{% hint style="success" %}
Alternatively, let players **pick a persistent (always online) server** from a list with [server-browser](https://docs.edgegap.com/learn/server-browser "mention").
{% endhint %}

**Get started within 5 minutes and test the all features for free, no credit card required.**

Upgrade when you're ready for a more powerful, private (dedicated) cluster. Native integration with Edgegap [deployments](https://docs.edgegap.com/learn/orchestration/deployments "mention") delivers best-in-class ping no matter where your players are located.

{% hint style="info" %}
Free Tier allows 3 hours of runtime after each restart. Your matchmaker will run on shared infrastructure with limited resources, suitable for testing. **After your public release, matchmaker needs to run 24/7.**
{% endhint %}

There are three essential concepts to each Matchmaker:

* [#hosting-cluster](#hosting-cluster "mention") - underlying server infrastructure, fully managed and operated by Edgegap.
* [#configuration](#configuration "mention") - set of rules and settings which define how the matchmaker operates.
* 🌐 Service Instance **-** live matchmaking service running 24/7 on the Cluster, using Configuration to match players together and produce deployment (server) assignments.

{% hint style="success" %}
[Update your matchmaker version frequently](#changelog) to **take advantage of new features and bug fixes.**
{% endhint %}

## ▶️ Start Matchmaking

Learn about matchmaking process to customize, troubleshoot, and optimize your game integration.

<figure><img src="https://3027732442-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2Fm4U4bgwucX6iGEieMISU%2Fimage.png?alt=media&#x26;token=39b97619-700b-4062-9dd9-73fa08fb96c2" alt=""><figcaption><p>Matchmaking Sequence</p></figcaption></figure>

1. [Authenticate Player](#authenticate) - prevents pirated copies from playing online,
2. [Create Lobby](#create-group) - join up with your friends and share player/match preferences,
3. [**Group Up**](#group-up) **- register your Lobby as a Matchmaking Group,**
4. [**Find Match**](#find-match) **- get ready and start looking for a match (new or existing),**
   1. Assign Server & Inject Tickets - server is automatically assigned after a few seconds,
5. [**Connect and Authenticate**](#connect-to-server) **- attempt secure connection to game server,**
   1. Confirm Identity - server verifies identity of game client using third party tokens,
   2. Accept Player or Kick Player - server decides if the player is allowed to join.

**Get started quickly - add our matchmaking starter sample to your game**:

* Unreal Engine [#integration-kit](https://docs.edgegap.com/unreal-engine/developer-tools#integration-kit "mention"):
  * [install from Fab Marketplace](https://www.fab.com/listings/ff17ad88-12a1-49cf-9a41-31695ed11e16) (free for Personal use),
  * [import simple example blueprint](https://blueprintue.com/blueprint/m33u1okj/) and customize to your needs.
* Unity [#matchmaking-sdk](https://docs.edgegap.com/unity/developer-tools#matchmaking-sdk "mention") by Edgegap:
  * [install package using Unity Package Manager for free](https://github.com/edgegap/edgegap-unity-gen2-sdk?tab=readme-ov-file#install-with-git-recommended),
  * [import simple example script](https://github.com/edgegap/edgegap-unity-gen2-sdk?tab=readme-ov-file#import-simple-example) and customize for your needs,

### Authenticate

All requests must send an `Authorization`  HTTP header with your secret **Auth Token:**

<pre><code>Authorization: <a data-footnote-ref href="#user-content-fn-1">xxxxxxxx-e458-4592-b607-c2c28afd8b62</a>
</code></pre>

{% hint style="warning" %}
**Keep your tokens secret and safe! Edgegap staff will never ask you for your tokens.**
{% endhint %}

{% hint style="success" %}
**This token may be included in your game client safely, as it doesn't grant access to Edgegap API.**
{% endhint %}

Individual players can be identified using their ticket ID, available on clients and server. Optionally, add custom authentication or limits with a custom proxy using [#server-to-server-api](#server-to-server-api "mention") API.

### Group Up

Creating a Group (party) ensures players join the same team and server with their friends.

{% hint style="success" %}
Create a group marked ready to [#find-match](#find-match "mention") quickly as a **solo player without group members**.
{% endhint %}

<figure><img src="https://3027732442-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2FzPLV5ap16XQn0vYZsnQb%2FUntitled-2024-10-29-1018.png?alt=media&#x26;token=aa7165ab-abe1-4f7d-a84e-d2c4af8f36ad" alt=""><figcaption><p>Group Lifecycle Activity Diagram</p></figcaption></figure>

#### Lobby and Group

Use a Lobby service if your game design requires setting player-controlled matchmaking preferences (e.g. character choice, difficulty, map, etc.). As players join and leave the Lobby, they also update the matchmaking Group to prepare for finding a match later.

{% hint style="success" %}
**Don't have time for a Lobby service?** Guide players to share group IDs through Discord or DMs.
{% endhint %}

<table><thead><tr><th width="390">Game Design - Feature / Requirement</th><th>Pre-Match Lobby</th><th>Matchmaker Group</th></tr></thead><tbody><tr><td><a data-footnote-ref href="#user-content-fn-2">invite friends to play with me</a></td><td>✅</td><td>✅</td></tr><tr><td>modify my player/match preferences</td><td>✅</td><td>❌</td></tr><tr><td>view other lobby member preferences</td><td>✅</td><td>❌</td></tr><tr><td>store and manage custom key-value data</td><td>✅</td><td>❌</td></tr><tr><td>notify group members that I'm ready to play</td><td>❌</td><td>✅</td></tr><tr><td>show matchmaking progress and find match</td><td>❌</td><td>✅</td></tr><tr><td>get team assignment for a player/group</td><td>❌</td><td>✅</td></tr><tr><td>retrieve game server connection details</td><td>❌</td><td>✅</td></tr></tbody></table>

Our cross-platform matchmaker supports all commercial and custom Lobby services:

<table><thead><tr><th>Lobby Service (Third Party)</th><th width="120" data-type="checkbox">Unreal Engine</th><th width="75" data-type="checkbox">Unity</th><th width="50" data-type="checkbox">PC</th><th width="90" data-type="checkbox">Consoles</th><th width="65" data-type="checkbox">VR/XR</th><th width="100" data-type="checkbox">Mobile</th></tr></thead><tbody><tr><td><a href="https://dev.epicgames.com/docs/game-services/lobbies-and-sessions/lobbies/lobbies-intro">Epic Online Services Lobby</a><br>(Epic Games)</td><td>true</td><td>true</td><td>true</td><td>true</td><td>true</td><td>true</td></tr><tr><td><a href="https://partner.steamgames.com/doc/features/multiplayer/matchmaking#friends">Steamworks Lobby</a><br>(Valve Corporation)</td><td>true</td><td>true</td><td>true</td><td>true</td><td>true</td><td>true</td></tr><tr><td><a href="https://heroiclabs.com/docs/nakama/concepts/groups/">Nakama Group</a><br>(Heroic Labs)</td><td>true</td><td>true</td><td>true</td><td>true</td><td>true</td><td>true</td></tr><tr><td><a href="https://learn.microsoft.com/en-us/gaming/playfab/community/associations/groups/quickstart">Playfab Lobby</a><br>(Microsoft)</td><td>true</td><td>true</td><td>true</td><td>true</td><td>true</td><td>true</td></tr><tr><td><a href="https://docs.braincloudservers.com/learn/key-concepts/multiplayer/lobbies/#lobby-experience">brainCloud Lobby</a><br>(bitHeads)</td><td>true</td><td>true</td><td>true</td><td>true</td><td>true</td><td>true</td></tr><tr><td><a href="https://developer.apple.com/documentation/gamekit/connecting-players-with-their-friends-in-your-game">Gamekit Friends</a><br>(Apple)</td><td>true</td><td>true</td><td>false</td><td>false</td><td>false</td><td>true</td></tr><tr><td>Custom Lobby<br>(your company)</td><td>true</td><td>true</td><td>true</td><td>true</td><td>true</td><td>true</td></tr></tbody></table>

Lobby owner (the player sending invites) must also create the matchmaking group.

**Store your group's ID in your shared lobby data**, so other lobby members can easily find and join a matchmaking group associated with the third party lobby. Players invited to the group use the group ID to **create their memberships (join)**, and to **securely store their** [**matchmaking attributes**](#matchmaking-rules)**.**

{% hint style="warning" %}
**Once a group starts matchmaking, it can't be joined.** [#abandon-queue](#abandon-queue "mention") and create a new one.
{% endhint %}

#### Ping Optimization

If [#configuration](#configuration "mention") includes [`latencies` rule](#rule-example-elo_rating) all group members send their [ping-beacons](https://docs.edgegap.com/learn/orchestration/ping-beacons "mention") measurements to **prevent matching players in distant regions** or much higher/lower ping (latency).

{% code title="Example Game Client Ping Measurements in milliseconds" %}

```json
{
  "Chicago": 224.4,
  "Frankfurt": 23.2,
  "Tokyo": 167.4
}
```

{% endcode %}

#### **Abandon Queue**

Group owner may delete the group, automatically deleting all group memberships. Deleting the group after matchmaking started will cancel all memberships, and delete them shortly after.

Group members (besides owner) may delete their memberships (leave group) at any time before [#find-match](#find-match "mention"). Deleting a membership afterwards will cancel matchmaking for the whole group.

{% hint style="info" %}
Once matchmaking is cancelled, members are [removed from matchmaking automatically](#matchmaking-profiles) and notified through membership `status:CANCELLED`  in their next status polling response.
{% endhint %}

Once cancelled, if the group wishes to restart matchmaking, the group owner must re-create the group, share the new group ID to members, and have them re-create their memberships.

**Once a match is found, group can't be deleted** (`409 Conflict`), and will be [removed automatically](#connect-to-server). Your server should allow some time (e.g. 60s) for players to connect before assuming a player abandoned. In such case your server may:

* replace the leaver with an AI character to immediately start the match,
* or create a [backfill](#backfill-match) to find a new player to replace the leaver,
* or proceed without replacing the leaver, if your game design permits variable player count.

### Find Match

To start looking for a match, all members and the owner must mark themselves ready.

{% hint style="success" %}
To let the group owner **start matchmaking immediately, mark memberships ready at creation**. Once the owner marks themselves ready the matchmaking will start, since everyone is ready.
{% endhint %}

{% hint style="info" %}
For best experience, **provide status updates to players using in-game UI**.
{% endhint %}

**All players must poll their membership in regular intervals** (recommended 3-5s) to detect when matchmaking starts, and to communicate matchmaking progress through in-game UI.

Players should **save their membership and group IDs persistently**, so that in case of game client crash they can restart the game and resume without losing matchmaking progress.

Once we find enough players to put into the same team adhering to your [#matchmaking-rules](#matchmaking-rules "mention"), players will be notified in their membership response with `status:TEAM_FOUND`.

Deleting a membership at this stage will result in all group memberships being cancelled and all other groups' assigned to the same team returning to `status:SEARCHING` .

Teams continue matchmaking with other teams using the overlapping values across their groups (or average in case of `number_difference` ) until enough teams are assembled. Memberships indicate this with response  `status:MATCH_FOUND` , which means your [deployment is being started](https://docs.edgegap.com/orchestration/deployments#id-1.-start-a-deployment).

**Matchmaker aims to maximize match fill rate, and will not proceed to `MATCH_FOUND` until either:**

1. enough teams are matched with the configured maximum team size,
2. or if [#rule-expansion](#rule-expansion "mention") defined AND expansion time reached, AND enough teams are matched with the configured minimum team size,
3. or the configured ticket expiration time elapsed AND enough teams are matched with the configured minimum team size.

If neither scenario succeeds before configured ticket expiration, group and tickets are cancelled.

{% hint style="info" %}
Experiencing long queue times during testing, or with players in less popular regions? Set a lower ticket expiration period (e.g. 30s) and re-create group (or tickets) on client side upon expiration.
{% endhint %}

Ticket expiration automatically resets whenever a group (or a player) is matched to a team.

{% hint style="success" %}
Store `team_id`  and `match_id` in your game backend to display team members information in-game.
{% endhint %}

{% hint style="info" %}
Every player receives a **unique Ticket ID, which can be used to** [#authenticate](#authenticate "mention") **with game servers.**
{% endhint %}

If the player has been matched and assigned to a game server, their ticket is deleted automatically. Players who abandon queue after `status:HOST_ASSIGNED`  can be replaced with [backfill](#backfill-match).

Once players receive `status:HOST_ASSIGNED`  they proceed to [#connect-to-server](#connect-to-server "mention").

### Connect to Server

A few seconds after finding a match, memberships proceed to `status:HOST_ASSIGNED`  indicating that your [deployment is now ready and your game server is initializing](https://docs.edgegap.com/orchestration/deployments#id-3.-deployment-ready).

Each player reads their `ticket_id`  and  `assignment`  and attempt connection using the [**FQDN**](#user-content-fn-3)[^3] **(deployment URL)** and the **External Port**. Your game server may be still initializing at this time, so **players must retry connection several times**, until exceeding your usual server initialization time:

{% tabs %}
{% tab title="Unreal Engine" %}
To **connect from PIE (Editor)** during development and testing, press the tilde key `~`  and type `open {URL}:{port}`  and wait for your editor to load the map.

To **connect from a game client build** (and in live production environment) try

* Unreal Engine [⚡ Integration Kit](https://docs.edgegap.com/learn/unreal-engine-games/developer-tools#integration-kit):
  * [install from Fab Marketplace](https://www.fab.com/listings/ff17ad88-12a1-49cf-9a41-31695ed11e16) (free for Personal use),
  * [import simple example blueprint](https://blueprintue.com/blueprint/m33u1okj/) and customize to your needs.

{% hint style="success" %}
In case of failed connections or dark screen consult our [troubleshooting guide](https://docs.edgegap.com/unreal-engine#troubleshooting-and-faq).
{% endhint %}
{% endtab %}

{% tab title="Unity" %}
To **connect your Unity Editor** or **game client** to your cloud deployment, input:

* **Deployment** **URL** pointing to the server's IP, usually in `NetworkManager` component.
* **External port** mapping to the [server's internal listen port](https://docs.edgegap.com/orchestration/application-and-versions#port-mapping), usually in a Transport component.

{% hint style="success" %}
In case of connection timeout or other issues consult our [troubleshooting guide](https://docs.edgegap.com/unity#troubleshooting-and-faq-4).
{% endhint %}
{% endtab %}
{% endtabs %}

{% hint style="info" %}
We do not ask players to confirm the match, as we aim to provide shortest possible time to gameplay, high match fill rate, and minimize queue dodging and match cancellations.
{% endhint %}

Players should **save their assignment ID persistently between game restarts**, so that in case of game client crash they can retrieve the connection details and attempt reconnecting.

{% hint style="success" %}
See [](https://docs.edgegap.com/learn/matchmaking "mention") and our SDKs with automatic reconnect function and more.
{% endhint %}

### Backfill Match

Optionally, some games may have special matchmaking needs, such as:

* allow new players to join games in progress (friends or "randoms"),
* replace players who abandon (leavers) after server starts to avoid restarting match,
* allow spectators to join and observe tournament or friends’ matches (e-sports),
* centralize players in larger servers to provide more social interactions (MMOs).

Backfill is a **server-owned ticket representing players currently connected to the server.** This ensures newly added players will respect your matchmaking rules when matched with current players.

{% hint style="warning" %}
[#backfill-match](#backfill-match "mention") to replace Seat/Match sessions. Matchmaker only supports Default session.
{% endhint %}

<figure><img src="https://3027732442-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2FJhdLAJYga4z2sjxLj6LM%2FUntitled-2024-10-29-1018.png?alt=media&#x26;token=279136ba-a15e-46b0-a119-8419b8aca044" alt=""><figcaption><p>Backfill Scenarios Visualized</p></figcaption></figure>

{% hint style="success" %}
**Backfills ignore** `player_count`  **rule, and always match exactly one group**. `backfill_group_size`  controls team capacity with round-robin strategy, filling teams evenly in a controlled manner.
{% endhint %}

**The steps to complete a successful backfill are:**

1. Server creates one Backfill per team missing players, using values from:
   * Real `assignment`  data retrieved from [#injected-environment-variables](https://docs.edgegap.com/orchestration/deployments#injected-environment-variables "mention") (deployment).
   * Currently connected players' `tickets`:
     * from [#injected-variables](#injected-variables "mention") (matchmaker), previous backfills' `assigned_ticket` response, or mock data manipulated to match specific players,
     * replace `backfill_group_size`  values with possible group sizes [up to available capacity](#user-content-fn-4)[^4],
2. Game clients create new tickets (memberships) and include `backfill_group_size`  values:
   * `"1"`  if the player is matchmaking alone.
   * [`"2"`  if the player is a part of a matchmaking group with 2x members total](#user-content-fn-5)[^5].
   * `"new"`  if players enabled starting new games in addition to joining in-progress games.
3. Game clients proceed to [#find-match](#find-match "mention") and pair players with the matching backfill.
4. If the backfilled group didn't completely fill the team, the server may repeat this process with the newly backfilled players' tickets, to add more players and reach desired team sizes.

{% hint style="info" %}
To create a Backfill-only profile, set `min_team_size`  to 999,999 and disable ticket + ticket matches.
{% endhint %}

<details>

<summary>🥛 Backfill Example (Backfill Showcase)</summary>

```json
{
  "profile": "backfill-example",
  "attributes": {
    "assignment": {
      "request_id": "cd28e6c66554",
      "fqdn": "cd28e6c66554.pr.edgegap.net",
      "public_ip": "192.168.2.14",
      "ports": {
        "game": {
          "internal": 7777,
          "external": 56890,
          "link": "cd28e6c66554.pr.edgegap.net:56890",
          "protocol": "UDP"
        },
        "web": {
          "internal": 22,
          "external": 57440,
          "link": "cd28e6c66554.pr.edgegap.net:57440",
          "protocol": "TCP"
        },
        "server": {
          "internal": 80,
          "external": 50110,
          "link": "cd28e6c66554.pr.edgegap.net:50110",
          "protocol": "TCP"
        }
      },
      "location": {
        "city": "Montreal",
        "country": "Canada",
        "continent": "North America",
        "administrative_division": "Quebec",
        "timezone": "America/Toronto"
      }
    }
  },
  "tickets": {
    "c3d057h5h6f7j889fk43": {
      "player_ip": "174.25.48.238",
      "attributes": {
        "beacons": {
          "New York": 12.2,
          "Los Angeles": 45.3,
          "Paris": 78.3
        },
        "backfill_group_size": [
          "2",
          "1"
        ]
      },
      "group_id": "192bb97e-7fd6-4d86-8ce4-61c53c9fef16",
      "id": "c3d057h5h6f7j889fk43",
      "created_at": "2024-08-20T13:38:05.251393+00:00"
    },
    "cqg0bg9583s738h9dkf6": {
      "player_ip": "217.34.85.142",
      "attributes": {
        "beacons": {
          "New York": 21.0,
          "Los Angeles": 30.2,
          "Paris": 101.1
        },
        "backfill_group_size": [
          "2",
          "1"
        ]
      },
      "group_id": "aea7df3c-d391-4ea3-a3ec-dded422fe7c8",
      "id": "cqg0bg9583s738h9dkf6",
      "created_at": "2024-08-20T13:38:05.251393+00:00"
    }
  },
  "assigned_ticket": null
}
```

</details>

<details>

<summary>🥛 Backfill Assignment Example (Backfill Showcase)</summary>

```json
{
  "profile": "backfill-example",
  "attributes": {
    "assignment": {
      "request_id": "cd28e6c66554",
      "fqdn": "cd28e6c66554.pr.edgegap.net",
      "public_ip": "192.168.2.14",
      "ports": {
        "game": {
          "internal": 7777,
          "external": 56890,
          "link": "cd28e6c66554.pr.edgegap.net:56890",
          "protocol": "UDP"
        },
        "web": {
          "internal": 22,
          "external": 57440,
          "link": "cd28e6c66554.pr.edgegap.net:57440",
          "protocol": "TCP"
        },
        "server": {
          "internal": 80,
          "external": 50110,
          "link": "cd28e6c66554.pr.edgegap.net:50110",
          "protocol": "TCP"
        }
      },
      "location": {
        "city": "Montreal",
        "country": "Canada",
        "continent": "North America",
        "administrative_division": "Quebec",
        "timezone": "America/Toronto"
      }
    }
  },
  "tickets": {
    "c3d057h5h6f7j889fk43": {
      "player_ip": "174.25.48.238",
      "attributes": {
        "beacons": {
          "New York": 12.2,
          "Los Angeles": 45.3,
          "Paris": 78.3
        },
        "backfill_group_size": [
          "2",
          "1"
        ]
      },
      "group_id": "192bb97e-7fd6-4d86-8ce4-61c53c9fef16",
      "id": "c3d057h5h6f7j889fk43",
      "created_at": "2024-08-20T13:38:05.251393+00:00"
    },
    "cqg0bg9583s738h9dkf6": {
      "player_ip": "217.34.85.142",
      "attributes": {
        "beacons": {
          "New York": 21.0,
          "Los Angeles": 30.2,
          "Paris": 101.1
        },
        "backfill_group_size": [
          "2",
          "1"
        ]
      },
      "group_id": "aea7df3c-d391-4ea3-a3ec-dded422fe7c8",
      "id": "cqg0bg9583s738h9dkf6",
      "created_at": "2024-08-20T13:38:05.251393+00:00"
    }
  },
  "assigned_ticket": {
    "profile": "backfill-example",
    "player_ip": "244.13.201.244",
    "attributes": {
      "beacons": {
        "New York": 30.2,
        "Los Angeles": 10.5,
        "Paris": 123.9
      },
      "backfill_group_size": [
        "new",
        "1"
      ]
    },
    "id": "cqg0bg550h7uujd77khg",
    "group_id": "e0cf41c0-f88f-456e-a032-03b1d6821a9a",
    "created_at": "2024-08-20T13:38:08.251393+00:00",
    "status": "HOST_ASSIGNED"
  }
}
```

</details>

{% hint style="info" %}
See [Mirror Seat Management](https://docs.edgegap.com/docs/sample-projects/mirror-on-edgegap#bonus-seat-sessions-management) and [FishNet Seat Management](https://docs.edgegap.com/docs/sample-projects/fishnet-on-edgegap#bonus-seat-sessions-management) for **player connection monitoring**.
{% endhint %}

Once game server initialization concludes, **your server should**:

* **Start abandonment timer for each new player.** We recommend indicating loading progress to connected players with a loading scene/level - either a full fledged 3D scene, a lobby-like social UI, or a loading screen with a progress bar.
* **Keep track of new player connections or existing players leaving over time**:
  1. New players must announce ticket ID to the server for authentication and to map their connection to matchmaker [#injected-variables](#injected-variables "mention") or `assigned_ticket` (if backfilled).
  2. Create new Backfills for unused player capacity (leavers) throughout server lifespan.
  3. Renew expired Backfills, which are deleted after `ticket_expiration_period`.
* **Clean up (delete) any leftover Backfills** once the [#id-5.-deployment-stopped](https://docs.edgegap.com/orchestration/deployments#id-5.-deployment-stopped "mention"):
  * Unity - [`OnApplicationQuit`](https://docs.unity3d.com/6000.0/Documentation/ScriptReference/MonoBehaviour.OnApplicationQuit.html) callback or custom game end callback,
  * Unreal Engine - [`OnWorldDestroyed`](https://forums.unrealengine.com/t/call-function-before-quit-game/344954/2) , [`PreExit`](https://forums.unrealengine.com/t/event-on-close/298087/2) , or a custom game end callback.

{% hint style="info" %}
Use [GetEnvironmentVariable in C#](https://learn.microsoft.com/en-us/dotnet/api/system.environment.getenvironmentvariable?view=net-8.0) or [GetEnvironmentVariable in C++](https://dev.epicgames.com/documentation/en-us/unreal-engine/API/Runtime/Core/GenericPlatform/FGenericPlatformMisc/GetEnvironmentVariable) to get variable values.
{% endhint %}

Any profile can be used for Backfill as long as valid server assignment and at least one ticket is provided. See [#backfill-showcase](https://docs.edgegap.com/learn/matchmaking/..#backfill-showcase "mention") for a minimal example.

## ⚙️ Configuration

Matchmaker API is generated from a JSON configuration specified when you create a new (or quick-restart) Matchmaker. You may specify any number of profiles with varying rules and expansions:

{% hint style="success" %}
See [](https://docs.edgegap.com/learn/matchmaking "mention") for our SDKs and detailed example scenarios.
{% endhint %}

<details>

<summary>🍀 Simple Example (Minimal Recommended Configuration)</summary>

<pre class="language-json"><code class="lang-json">{
  "version": "3.2.1",
  "inspect": true,
  "max_deployment_retry_count": 3,
  "profiles": {
    "simple-example": {
      "ticket_expiration_period": "5m",
      "ticket_removal_period": "1m",
      "group_inactivity_removal_period": "5m",
      "application": {
        "name": "<a data-footnote-ref href="#user-content-fn-6">my-game-server</a>",
        "version": "<a data-footnote-ref href="#user-content-fn-7">2024.01.30-16.23.00-UTC</a>"
      },
      "rules": {
        "initial": {
          "match_size": {
            "type": "player_count",
            "attributes": {
              "team_count": 1,
              "min_team_size": 2,
              "max_team_size": 2
            }
          },
          "beacons": {
            "type": "latencies",
            "attributes": {
              "difference": 100,
              "max_latency": 200
            }
          }
        },
        "expansions": {}
      }
    }
  }
}
</code></pre>

</details>

<details>

<summary>🏁 Advanced Example (Complete Example Configuration)</summary>

```json
{
  "version": "3.2.1",
  "inspect": true,
  "max_deployment_retry_count": 3,
  "allowed_cors_origins": [
    "https://*.my-game-server.com"
  ],
  "profiles": {
    "advanced-example": {
      "ticket_expiration_period": "5m",
      "ticket_removal_period": "1m",
      "group_inactivity_removal_period": "5m"
      "application": {
        "name": "my-game-server",
        "version": "2024.01.30-16.23.00-UTC"
      },
      "rules": {
        "initial": {
          "match_size": {
            "type": "player_count",
            "attributes": {
              "team_count": 1,
              "min_team_size": 4,
              "max_team_size": 4
            }
          },
          "beacons": {
            "type": "latencies",
            "attributes": {
              "difference": 125,
              "max_latency": 125
            }
          },
          "elo_rating": {
            "type": "number_difference",
            "attributes": {
              "max_difference": 50
            }
          },
          "selected_game_mode": {
            "type": "string_equality"
          },
          "selected_map": {
            "type": "intersection",
            "attributes": {
              "overlap": 1
            }
          },
          "backfill_group_size": {
            "type": "intersection",
            "attributes": {
              "overlap": 1
            }
          }
        },
        "expansions": {
          "30": {
            "elo_rating": {
              "max_difference": 150
            },
            "beacons": {
              "difference": 125,
              "max_latency": 250
            }
          },
          "60": {
            "elo_rating": {
              "max_difference": 200
            }
          },
          "180": {
            "match_size": {
              "team_count": 1,
              "min_team_size": 1,
              "max_team_size": 4
            },
            "beacons": {
              "difference": 99999,
              "max_latency": 99999
            }
          }
        }
      }
    }
  }
}
```

</details>

<details>

<summary>🎾 Custom Lobby Example</summary>

```json
{
  "version": "3.2.1",
  "inspect": true,
  "max_deployment_retry_count": 3,
  "profiles": {
    "custom-lobby-example": {
      "ticket_expiration_period": "3m",
      "ticket_removal_period": "1m",
      "group_inactivity_removal_period": "5m"
      "application": {
        "name": "my-game-server",
        "version": "2024.01.30-16.23.00-UTC"
      },
      "rules": {
        "initial": {
          "match_size": {
            "type": "player_count",
            "attributes": {
              "team_count": 1,
              "min_team_size": 4,
              "max_team_size": 4
            }
          },
          "lobby_id": {
            "type": "intersection",
            "attributes": {
              "overlap": 1
            }
          }
        },
        "expansions": {
          "10": {
            "match_size": {
              "team_count": 1,
              "min_team_size": 1,
              "max_team_size": 4
            }
          }
        }
      }
    }
  }
}
```

</details>

<details>

<summary><span data-gb-custom-inline data-tag="emoji" data-code="1f95b">🥛</span> Backfill Configuration Example</summary>

```json
{
  "version": "3.2.1",
  "inspect": true,
  "max_deployment_retry_count": 3,
  "profiles": {
    "backfill-example": {
      "ticket_expiration_period": "5m",
      "ticket_removal_period": "1m",
      "group_inactivity_removal_period": "5m",
      "application": {
        "name": "my-game-server",
        "version": "2024.01.30-16.23.00-UTC"
      },
      "rules": {
        "initial": {
          "match_size": {
            "type": "player_count",
            "attributes": {
              "team_count": 1,
              "min_team_size": 4,
              "max_team_size": 4
            }
          },
          "beacons": {
            "type": "latencies",
            "attributes": {
              "difference": 100,
              "max_latency": 200
            }
          },
          "backfill_group_size": {
            "type": "intersection",
            "attributes": {
              "overlap": 1
            }
          }
        },
        "expansions": {}
      }
    }
  }
}
```

</details>

<details>

<summary>⚔️ Competitive Game Example</summary>

```json
{
  "version": "3.2.1",
  "inspect": true,
  "max_deployment_retry_count": 3,
  "profiles": {
    "casual-example": {
      "ticket_expiration_period": "5m",
      "ticket_removal_period": "1m",
      "group_inactivity_removal_period": "5m",
      "application": {
        "name": "my-game-server",
        "version": "2024.01.30-16.23.00-UTC"
      },
      "rules": {
        "initial": {
          "match_size": {
            "type": "player_count",
            "attributes": {
              "team_count": 2,
              "min_team_size": 5,
              "max_team_size": 5
            }
          },
          "beacons": {
            "type": "latencies",
            "attributes": {
              "difference": 125,
              "max_latency": 150
            }
          },
          "selected_maps": {
            "type": "intersection",
            "attributes": {
              "overlap": 1
            }
          },
          "backfill_group_size": {
            "type": "intersection",
            "attributes": {
              "overlap": 1
            }
          }
        },
        "expansions": {
          "30": {
            "beacons": {
              "difference": 125,
              "max_latency": 250
            }
          },
          "180": {
            "beacons": {
              "difference": 99999,
              "max_latency": 99999
            }
          }
        }
      }
    },
    "competitive-example": {
      "ticket_expiration_period": "5m",
      "ticket_removal_period": "1m",
      "group_inactivity_removal_period": "5m"
      "application": {
        "name": "my-game-server",
        "version": "2024.01.30-16.23.00-UTC"
      },
      "rules": {
        "initial": {
          "match_size": {
            "type": "player_count",
            "attributes": {
              "team_count": 2,
              "min_team_size": 5,
              "max_team_size": 5
            }
          },
          "beacons": {
            "type": "latencies",
            "attributes": {
              "difference": 125,
              "max_latency": 150
            }
          },
          "versus_ranks": {
            "type": "intersection",
            "attributes": {
              "overlap": 1
            }
          }
        },
        "expansions": {
          "120": {
            "beacons": {
              "difference": 125,
              "max_latency": 250
            }
          }
        }
      }
    },
    "challenger-example": {
      "ticket_expiration_period": "5m",
      "ticket_removal_period": "1m",
      "group_inactivity_removal_period": "5m"
      "application": {
        "name": "my-game-server",
        "version": "2024.01.30-16.23.00-UTC"
      },
      "rules": {
        "initial": {
          "match_size": {
            "type": "player_count",
            "attributes": {
              "team_count": 2,
              "min_team_size": 5,
              "max_team_size": 5
            }
          },
          "beacons": {
            "type": "latencies",
            "attributes": {
              "difference": 125,
              "max_latency": 150
            }
          },
          "elo_rating": {
            "type": "number_difference",
            "attributes": {
              "max_difference": 50
            }
          }
        },
        "expansions": {
          "120": {
            "beacons": {
              "difference": 125,
              "max_latency": 250
            }
          }
        }
      }
    }
  }
}
```

</details>

<details>

<summary>🤝 Cooperative Game Example</summary>

```json
{
  "version": "3.2.1",
  "inspect": true,
  "max_deployment_retry_count": 3,
  "profiles": {
    "cooperative-example": {
      "ticket_expiration_period": "3m",
      "ticket_removal_period": "1m",
      "group_inactivity_removal_period": "5m",
      "application": {
        "name": "my-game-server",
        "version": "2024.01.30-16.23.00-UTC"
      },
      "rules": {
        "initial": {
          "match_size": {
            "type": "player_count",
            "attributes": {
              "team_count": 1,
              "min_team_size": 4,
              "max_team_size": 4
            }
          },
          "beacons": {
            "type": "latencies",
            "attributes": {
              "difference": 125,
              "max_latency": 150
            }
          },
          "selected_difficulty": {
            "type": "string_equality"
          },
          "selected_map": {
            "type": "intersection",
            "attributes": {
              "overlap": 1
            }
          },
          "player_level": {
            "type": "number_difference",
            "attributes": {
              "max_difference": 10
            }
          },
          "backfill_group_size": {
            "type": "intersection",
            "attributes": {
              "overlap": 1
            }
          },
          "moderation_flags": {
            "type": "intersection",
            "attributes": {
              "overlap": 1
            }
          }
        },
        "expansions": {
          "30": {
            "beacons": {
              "difference": 125,
              "max_latency": 250
            },
            "player_level": {
              "max_difference": 20
            }
          },
          "60": {
            "match_size": {
              "team_count": 1,
              "min_team_size": 2,
              "max_team_size": 4
            }
          },
          "150": {
            "match_size": {
              "team_count": 1,
              "min_team_size": 1,
              "max_team_size": 4
            }
          }
        }
      }
    }
  }
}
```

</details>

<details>

<summary>🎈 Social Game Example</summary>

```json
{
  "version": "3.2.1",
  "inspect": true,
  "max_deployment_retry_count": 3,
  "profiles": {
    "social-example": {
      "ticket_expiration_period": "3m",
      "ticket_removal_period": "1m",
      "group_inactivity_removal_period": "5m",
      "application": {
        "name": "my-game-server",
        "version": "2024.01.30-16.23.00-UTC"
      },
      "rules": {
        "initial": {
          "match_size": {
            "attributes": {
              "team_count": 1,
              "min_team_size": 50,
              "max_team_size": 50
            },
            "type": "player_count"
          },
          "beacons": {
            "attributes": {
              "difference": 125,
              "max_latency": 150
            },
            "type": "latencies"
          },
          "selected_mode": {
            "type": "intersection",
            "attributes": {
              "overlap": 1
            }
          },
          "backfill_group_size": {
            "type": "intersection",
            "attributes": {
              "overlap": 1
            }
          },
          "moderation_flags": {
            "type": "intersection",
            "attributes": {
              "overlap": 1
            }
          }
        },
        "expansions": {
          "15": {
            "beacons": {
              "difference": 125,
              "max_latency": 250
            },
            "match_size": {
              "team_count": 1,
              "min_team_size": 20,
              "max_team_size": 50
            }
          },
          "30": {
            "match_size": {
              "team_count": 1,
              "min_team_size": 10,
              "max_team_size": 50
            }
          },
          "150": {
            "match_size": {
              "team_count": 1,
              "min_team_size": 1,
              "max_team_size": 50
            }
          }
        }
      }
    }
  }
}
```

</details>

{% hint style="warning" %}
Editing a running matchmaker will **trigger a quick reload**, deleting all tickets and causing short downtime.
{% endhint %}

<details>

<summary><code>The application configuration is not valid for profile XYZ.</code></summary>

* We couldn’t find your [application-and-versions](https://docs.edgegap.com/learn/orchestration/application-and-versions "mention"), please verify `application`  values.

</details>

<details>

<summary><code>Docker image for '2024.01.30-16.23.00-UTC' is not cached.</code></summary>

[**🌟 Upgrade to Pay as You Go tier**](https://app.edgegap.com/user-settings?tab=memberships) **to unlock** [**instant deployments with Caching**](https://docs.edgegap.com/orchestration/deployments#id-1.-start-a-deployment)**.**

* 4GB+ uncached images may take longer to deploy, resulting in [#id-4.-deployment-error](https://docs.edgegap.com/orchestration/deployments#id-4.-deployment-error "mention"). Consider optimizing your server image size ([Unreal Engine](https://docs.edgegap.com/unreal-engine#optimize-server-build-size) / [Unity](https://docs.edgegap.com/unity#optimize-server-build-size)).
* You may proceed anyway, though we recommend testing your deployment time.

</details>

### Profiles (Queues) <a href="#matchmaking-profiles" id="matchmaking-profiles"></a>

Profiles represent entirely separated matchmaking queues, sharing the same matchmaker version. You can **configure any number of profiles for each matchmaker.** Splitting up your player base in multiple profiles may result in longer queue times for your players.

Each matchmaker profile uses an [App Version](https://docs.edgegap.com/learn/orchestration/application-and-versions) as a template to start new deployments (servers).

{% hint style="success" %}
Some game modes may require more vCPU / RAM, especially if they support a higher number of players. Each **matchmaker may include multiple profiles**, each linked to an app version with adjusted resources.
{% endhint %}

### Rules <a href="#matchmaking-rules" id="matchmaking-rules"></a>

Every player and group joins matchmaking queue and finds matches using  `initial` rules at first.

Each entry in profile at path `.rules.initial` represents a rule, where:

* **key** is a string value to name the rule however you prefer; e.g. `match_size` , and
* **value** is an object defining the type and attributes of the rule, adhering to our standard ruleset.

{% hint style="info" %}
All rules have to be met simultaneously to initiate host assignment and start or find a deployment.
{% endhint %}

**Operators (Rule Type)**

**`player_count`** is a special rule defining how many players need to match to initiate assignment.

{% hint style="warning" %}
Rule `player_count`  **is required and may only be defined once** in your initial configuration rules.
{% endhint %}

Matchmaker always strives to maximize match fill rate, up to specified `max_team_size` :

1. if max team size is reached the match is made immediately,
2. otherwise, players wait in queue to fill match until [expansion](#rule-expansion) (or expiration) is about to elapse,
3. shortly before [expanding](#rule-expansion) (or expiring), if partial match is possible (≥ min and < max team size), this match will be made with all players in same expansion stage (assuming other rules pass).

{% hint style="success" %}
For cooperative, free-for-all, or asymmetric team size game modes, set your `"team_count": 1` .
{% endhint %}

Team count may be configured to compose multiple balanced teams for competitive games:

* **group attributes are calculated as average/overlap** of the group's **player attributes,**
* **team attributes are calculated as average/overlap** of the team's **group attributes.**

Assuming a fixed team size of 4 players:

<figure><img src="https://3027732442-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2FSFEzBayk3XNEUTIynjNd%2Fimage.png?alt=media&#x26;token=11a43fdf-3a99-4caa-8d2b-639e0f3cc06f" alt=""><figcaption><p>Example Match Scenarios</p></figcaption></figure>

{% hint style="info" %}
**Groups match in teams without overfilling,** only if a team has sufficient capacity to fit the whole group.
{% endhint %}

**`string_equality`** matches players with the exact same string value.

<details>

<summary>Rule Example: <code>selected_game_mode</code></summary>

`selected_game_mode`  rule will match players case sensitively:

:white\_check\_mark: Alice + Bob + Dave may match,

:x: Alice + Erin, or Charlie + Frank will never match.

| "Free For All" | "Capture The Flag" | "capture the flag" |
| -------------- | ------------------ | ------------------ |
| Alice          | Erin               | Frank              |
| Bob            | Charlie            |                    |
| Dave           |                    |                    |

</details>

**`number_difference`** matches players within the absolute numerical difference from each other.

<details>

<summary>Rule Example: <code>elo_rating</code></summary>

`elo_rating`  rule above with `"max_difference": 50` initially:

:white\_check\_mark: Alice + Bob may match, or Bob + Charlie may match,

:x: Alice + Bob + Charlie will never match.

<figure><img src="https://3027732442-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2FxtTxZ7TPSa8a8WtnGNAE%2Fimage.png?alt=media&#x26;token=c48b843b-c4e5-47bf-9154-07254a788067" alt=""><figcaption></figcaption></figure>

</details>

**`latencies`** is a special rule optimizing the ping of player matches:

* reduce client-server latency by removing regions with high latency (above threshold),
* improve match fairness by grouping players with similar latency (below difference).

<details>

<summary>Rule Example: <code>beacons</code></summary>

`beacons` rule configured with `"difference": 100, "max_latency": 200`  will match:

:white\_check\_mark: Alice and Bob may match:

* Tokyo is discarded (>200 ms),
* latency for Chicago within 100 ms absolute difference.

<table><thead><tr><th width="180">Beacon City</th><th width="80">Match</th><th width="132">abs(A - B) [ms]</th><th width="164">Alice [ms]</th><th width="164">Bob [ms]</th></tr></thead><tbody><tr><td>Chicago</td><td><span data-gb-custom-inline data-tag="emoji" data-code="2705">✅</span></td><td>75.0</td><td>12.3</td><td>87.3</td></tr><tr><td>Los Angeles</td><td><span data-gb-custom-inline data-tag="emoji" data-code="274c">❌</span></td><td><a data-footnote-ref href="#user-content-fn-8">113.2</a> <span data-gb-custom-inline data-tag="emoji" data-code="274c">❌</span></td><td>145.6</td><td>32.4</td></tr><tr><td><del>Tokyo</del></td><td>n/a</td><td>n/a</td><td><a data-footnote-ref href="#user-content-fn-9"><del>233.2</del></a> <span data-gb-custom-inline data-tag="emoji" data-code="274c">❌</span></td><td><a data-footnote-ref href="#user-content-fn-9"><del>253.2</del></a> <span data-gb-custom-inline data-tag="emoji" data-code="274c">❌</span></td></tr></tbody></table>

:x: Alice and Charlie will never match:

* no beacons have < 200 ms latency for both players,
* Alice lives in North America - Illinois,
* Charlie lives in Asia - Japan.

<table><thead><tr><th width="180">Beacon City</th><th width="80">Match</th><th width="132">abs(A - B) [ms]</th><th width="164">Alice [ms]</th><th width="164">Charlie [ms]</th></tr></thead><tbody><tr><td><del>Chicago</del></td><td>n/a</td><td>n/a</td><td>12.3</td><td><a data-footnote-ref href="#user-content-fn-9"><del>215.6</del></a> <span data-gb-custom-inline data-tag="emoji" data-code="274c">❌</span></td></tr><tr><td><del>Los Angeles</del></td><td>n/a</td><td>n/a</td><td>145.6</td><td><a data-footnote-ref href="#user-content-fn-9"><del>238.3</del></a> <span data-gb-custom-inline data-tag="emoji" data-code="274c">❌</span></td></tr><tr><td><del>Tokyo</del></td><td>n/a</td><td>n/a</td><td><a data-footnote-ref href="#user-content-fn-9"><del>233.2</del></a> <span data-gb-custom-inline data-tag="emoji" data-code="274c">❌</span></td><td>24.2</td></tr></tbody></table>

</details>

{% hint style="warning" %}
Rule `latencies`  is **optional and may only be defined once in your initial configuration** rules.
{% endhint %}

Some players with high ping to all beacons due to ISP[^10] issues or slow connection (e.g. wireless/mobile) may cause lags and degrade game experience for others. To mitigate this issue:

* Gradually expand allowed latency maximum and difference (see [Advanced Example Config](https://docs.edgegap.com/learn/matchmaking/..#advanced-example)),
  * players with high ping may have to wait longer than usual to find a match.
* Alternatively, allow players to override measurement with manual region selection, only sending fake ping values for the player-selected regions only (e.g. 25ms for fast match),
  * this may negatively impact player experience of the players' teammates and opponents.

{% hint style="info" %}
**High beacon ping doesn’t always result in high server ping**. Deployments are available in more locations than beacons. Beacons are orchestrated in real time to prioritize global coverage and reliability.
{% endhint %}

{% hint style="success" %}
See [](https://docs.edgegap.com/learn/matchmaking "mention") for **automated ping measurement using our SDKs**.
{% endhint %}

{% hint style="danger" %}
Beacons are automatically rescaled in real time - adding/removing/replacing existing beacons. Your clients and backend should account for this and **reload list of beacons before each matchmaking round**.
{% endhint %}

**`intersection`** matches players with one or more overlapping string values, case sensitively.

<details>

<summary>Rule Example: <code>selected_map</code></summary>

`selected_map` rule above with `"overlap": 1`  will match:

:white\_check\_mark: Alice + Bob + Charlie may match, or Alice + Bob + Dave may match,

:x: Alice + Bob + Charlie + Dave will never match.

<figure><img src="https://3027732442-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2FcQSUAnRkZKVyuGjFWSYL%2Fimage.png?alt=media&#x26;token=bf1a4e28-230a-4c9a-9ef6-a0dea4dbecdb" alt=""><figcaption></figcaption></figure>

</details>

#### Rule Expansion

Optionally, **`expansions`**  modify a rule’s attributes after a period of time spent in queue to relax  limitations and expand the pool of players which can be matched, **resulting in faster matches**.

<details>

<summary>Example Scenario: Expansions</summary>

[Initially, we require 1 team composed of exactly 4 players (possibly split in groups)](https://docs.edgegap.com/learn/matchmaking/..#advanced-example) with:

* maximum of 125 ms latency against the same (any one) beacon,
* latency difference of 125 ms or less between lowest/highest value for the same beacon,
* skill rating difference of 50 points or less between lowest and highest ranking player,
* the exact same (case sensitive) selected game mode,
* at least one matching map selection (case sensitive) amongst players,
* at least one matching [backfill group size](#backfill-match) value amongst players.

In the example above, we **expand the search by modifying attributes** after:

<table data-view="cards"><thead><tr><th></th><th></th></tr></thead><tbody><tr><td>30 seconds:</td><td><ul><li>4 players</li><li><strong>150 skill rating range</strong></li><li><strong>max 250 ms latency</strong></li></ul></td></tr><tr><td>60 seconds:</td><td><ul><li>4 players</li><li><strong>200 skill rating range</strong></li><li>max 250ms latency</li></ul></td></tr><tr><td>3 minutes (180s):</td><td><ul><li><strong>1-4 players</strong></li><li>200 skill rating range</li><li><strong>any latency</strong></li></ul></td></tr></tbody></table>

</details>

<details>

<summary>Fine-Tuning Expansions</summary>

Predicting player preferences is similar to shooting at a moving target. Start with a less restrictive rule set at release and optimize afterwards in iterations with [#analytics](#analytics "mention").

These questions may help frame your thinking process:

* How long is my play session?
  * 5 min play session means each player rejoins queue every 5 min, which will indirectly reduce queue time due to more players queueing at any given time.
* What is my [peak CCU](#user-content-fn-11)[^11] and my [low tide CCU](#user-content-fn-12)[^12]?
  * If there's high variance (more than 60%) between low/high, you may need a separate profile for low tide to wait longer in each expansion, to accumulate more players.
* What is my players' geographic distribution?
  * Even spread across multiple time zones means the peak and low tide have lower variance, but doesn't improve match speed since players in different regions shouldn't match if your [#ping-optimization](#ping-optimization "mention") is configured correctly (would result in high ping).
* What is my skill rating distribution (per region)?
  * Skill distribution typically follows [Bell curve](https://www.simplypsychology.org/normal-distribution.html) (natural distribution), so with each standard deviation from average, you find less players further away from average. Players with average values will be matched fast, in first expansion, but extremes are a problem.
  * We recommend to increase the expanded difference amount with each expansion, e.g. 25 -> 50 -> 100, so you account for having less players on the curve extremes.
  * If you have any challenger tier (pro players) we recommend a separate profile with custom skill setup, since the sample is smaller and often doesn't follow the macro trend across the entire player base. (leaning towards extremes, inverted bell curve)
* How can I improve matchmaking speed and match fill rate with small player base?
  * Learn as much about your players and their preferences as possible!
  * Consider removing some rules or relaxing restrictions initially.
  * Relax team size or team count over time - partial match is better than no match.
  * Increase duration between expansions to accumulate more players.
  * Contact us for more tips and tricks, specifically for your game design.

</details>

{% hint style="info" %}
Expansions of any rule’s attribute will **overwrite previous values** of that attribute.
{% endhint %}

## 📌 Injected Variables

Your server might need to know details about it’s players. Player attributes, resolved match values, and other values are injected to your deployment alongside the usual [#injected-variables](https://docs.edgegap.com/orchestration/application-and-versions#injected-variables "mention").

Preview unformatted **🏁 Advanced Example Variables:**

```
MM_MATCH_PROFILE=advanced-example
MM_EXPANSION=initial
MM_TICKET_IDS=["cusfn10msflc73beiik0","cusfn18msflc73beiil0"]
MM_TICKET_cusfn10msflc73beiik0={"id":"cusfn10msflc73beiik0","created_at":"2025-02-21T22:17:42.3886970Z","player_ip":"174.93.233.25","group_id":"b2080c27-19c9-4fb0-8fe7-4bf1e5d285d1","team_id":"cusfn1gmsflc73beiim0","attributes":{"beacons":{"Chicago":12.3,"LosAngeles":145.6,"Tokyo":233.2},"elo_rating":1337,"selected_game_mode":"quickplay","selected_map":["DustII","Airport","BankVault"],"backfill_group_size":["new","1"]}}
MM_TICKET_cusfn18msflc73beiil0={"id":"cusfn18msflc73beiil0","created_at":"2025-02-21T22:17:42.2548390Z","player_ip":"174.93.233.23","group_id":"015d4dc8-6c79-4b5c-bbc6-f309b9787c8f","team_id":"cusfn1gmsflc73beiim0","attributes":{"beacons":{"Chicago":87.3,"LosAngeles":32.4,"Tokyo":253.2},"elo_rating":1339,"selected_game_mode":"quickplay","selected_map":["Island","Airport"],"backfill_group_size":["new","1"]}}
MM_GROUPS={"b2080c27-19c9-4fb0-8fe7-4bf1e5d285d1":["cusfn10msflc73beiik0"],"015d4dc8-6c79-4b5c-bbc6-f309b9787c8f":["cusfn18msflc73beiil0"]}
MM_TEAMS={"cusfn1gmsflc73beiim0":["b2080c27-19c9-4fb0-8fe7-4bf1e5d285d1","015d4dc8-6c79-4b5c-bbc6-f309b9787c8f"]}
MM_MATCH_ID=advanced-example_initial-2025-02-21T22:17:43.3886970Z
MM_INTERSECTION={"selected_map":["Airport"],"backfill_group_size":["new","1"]}
MM_EQUALITY={"selected_game_mode":"quickplay"}
```

{% hint style="info" %}
Environment variables are **stored as stringified JSONs**, parse them using our SDK or a custom method.
{% endhint %}

{% hint style="success" %}
**Servers can map player connections to groups and attributes** after player sends their ticket ID to server.
{% endhint %}

## 🧵 Player Tracing

If your players experience any issues, tracing their path to server logs can be helpful. Each Matchmaker **deployment** **will be tagged with assigned player ticket IDs** so you can easily [#filter-deployments](https://docs.edgegap.com/orchestration/deployments#filter-deployments "mention") and find [#container-logs](https://docs.edgegap.com/orchestration/deployments#container-logs "mention") to help you troubleshoot.

{% hint style="success" %}
**Display ticket IDs and deployment IDs in client match history UI** to trace players when troubleshooting.
{% endhint %}

{% hint style="info" %}
See [#connection-quality](https://docs.edgegap.com/orchestration/deployments#connection-quality "mention") to learn about deployment troubleshooting.
{% endhint %}

## 👀 Analytics

Gain insights into your matchmaker load and performance, no code or configuration required.

🌟 [**Upgrade Matchmaker to Enterprise Tier**](https://app.edgegap.com/matchmaker-management-v2/matchmakers/list) **to unlock matchmaking metrics and insights:**

<figure><img src="https://3027732442-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2Fhb8NmB4ELuG7ayGLTeHs%2Fimage.png?alt=media&#x26;token=e3e0371e-c33f-48c8-bd15-5c11448dc633" alt=""><figcaption></figcaption></figure>

<figure><img src="https://3027732442-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2Fl0zTNccJASUTkJfTYxss%2Fimage.png?alt=media&#x26;token=0d061320-9524-4b12-83e6-ea9112ef1409" alt=""><figcaption></figcaption></figure>

## ☁️ Hosting Cluster

Matchmaker is conveniently hosted and managed 24/7 around the clock by Edgegap.

Choose a hosting option best suited for your goal:

* **Free Cluster (shared)** to test all features and explore synergies with your design,
  * shuts down after 3 hours automatically, requiring restart to continue testing.
* **Private Cluster** **(dedicated)** to ensure a stable environment for your production needs,
  * pick your region and get 24/7 support for live games to release with confidence.

#### Private Cluster Tiers

We currently offer [3 private cluster tiers](https://edgegap.com/resources/pricing#managed-infrastructure) to cater to everybody’s needs:

<table><thead><tr><th width="160">Tier</th><th align="right">Hobbyist Tier</th><th align="right">Studio Tier</th><th align="right">Enterprise Tier</th></tr></thead><tbody><tr><td>Best Suited For</td><td align="right">enthusiasts,<br>solo developers</td><td align="right">commercial releases</td><td align="right">high-traffic launches</td></tr><tr><td>Resources</td><td align="right">1 vCPU + 2GB RAM</td><td align="right">6 vCPU + 12GB RAM</td><td align="right">18 vCPU + 48GB RAM</td></tr><tr><td>Redundancy</td><td align="right">1x virtual node</td><td align="right">3x virtual nodes</td><td align="right">3x virtual nodes</td></tr><tr><td>Rate Limit (req/s)</td><td align="right">200</td><td align="right">750</td><td align="right">2,000</td></tr><tr><td>Price, hourly</td><td align="right">$0.0312</td><td align="right"> $0.146</td><td align="right">$0.548</td></tr><tr><td><strong>Price, 30 days</strong><br>(nonstop usage)</td><td align="right"><strong>$22.464</strong></td><td align="right"><strong>$105.12</strong></td><td align="right"><strong>$394.56</strong></td></tr></tbody></table>

Upgrade to a private cluster with one click. Changing Private Cluster Tiers after launch, without any player downtime, is also possible with [#rolling-updates-and-ab-tests](#rolling-updates-and-ab-tests "mention"). Managed clusters provide high-availability service hosting maintained by Edgegap with 24/7 live support for publicly released games.

Resource requirements for your instance will depend on factors:

* **number of players** - more players result in more tickets and API requests,
* **number of requests per player** - faster retries increase service load and consume resources,
* **configuration complexity** - intersection rules and expansions are particularly demanding,
* **average match duration** - shorter sessions make players rejoin matchmaking more often,
* **expiration and removal periods** - stale tickets stockpile over time and consume resources,
* **client retry fallback logic** - retrying with jittered backoff helps spread traffic burst peaks.

{% hint style="warning" %}
**Prepare for success and optimize after launch, so you don’t block your players on release day.** Use [#matchmaking-sdk](https://docs.edgegap.com/unity/developer-tools#matchmaking-sdk "mention") or **implement exponential jittered backoff** to recover from high load.
{% endhint %}

{% hint style="info" %}
Our clusters use cloud machines featuring AMD/Intel CPUs with clock speed 2.4 - 3.2 GHz.
{% endhint %}

### Rate Limits

To protect your cluster from exceeding it's burst capacity and crashing, we limit the number of requests per second based on our internal load tests using [#advanced-example](https://docs.edgegap.com/learn/matchmaking/..#advanced-example "mention") configuration.

<table><thead><tr><th>API endpoint</th><th width="130">Free Tier</th><th width="130">Hobbyist Tier</th><th width="130">Studio Tier</th><th width="130">Enterprise Tier</th></tr></thead><tbody><tr><td><strong>Overall Limit</strong></td><td><strong>100</strong></td><td><strong>200</strong></td><td><strong>750</strong></td><td><strong>2,000</strong></td></tr><tr><td>Create Deployment</td><td>5</td><td>10</td><td>30</td><td>30</td></tr><tr><td>List Beacons</td><td>10</td><td>20</td><td>75</td><td>200</td></tr><tr><td>Create Group<br>+ Create Ticket<br>+ Create Group Ticket</td><td>10</td><td>20</td><td>75</td><td>200</td></tr><tr><td>Read Membership<br>+ Read Group<br>+ Read Ticket</td><td>10</td><td>120</td><td>450</td><td>1,300</td></tr><tr><td>Create Backfill</td><td>5</td><td>10</td><td>37</td><td>100</td></tr></tbody></table>

Rate limits are expressed in **combined requests per second to the specified set of API endpoints**.

If you game clients do not retry requests upon receiving response `429 Too Many Requests`  **your deployments may be missing players** who stop reading their assignments due to high load.

#### Load Testing

Matchmaking and assignments require CPU and memory usage, requiring a hosting cost with each private matchmaker. See resources and prices associated with each tier on [our pricing page](https://edgegap.com/resources/pricing#matchmaker).

{% hint style="success" %}
**Always use** [**private clusters**](#private-cluster-tiers) **for stress testing.** Free matchmakers are strictly limited for dev testing only.
{% endhint %}

When designing your load test, **please consider realistic player patterns**:

| Realistic Scenario                                                                            | Unrealistic Traffic Pattern                                                              |
| --------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------- |
| ✅ Players join matchmaking gradually, increasing req/s over several hours.                    | ❌ All players coordinate and create their tickets in the exact same second.              |
| ✅ Players wait an increasing amount of time between their retries (e.g. 1s-5s-10s-10s).       | ❌ All players retry immediately upon receiving `429 Too Many Requests`  response.        |
| ✅ Most players will receive their assignments  within a short time (10-60s) and stop polling. | ❌ All players continue polling for a set amount of time even after receiving assignment. |
| ✅ Most players finish their game (taking time) before restarting matchmaking anew.            | ❌ All players restart matchmaking anew immediately after receiving their assignment.     |
| ✅ Peak traffic is sustained for 6-8 hours a day, after which some time zones drop off.        | ❌ Peak traffic is sustained 24 hours a day, with all players playing night and day.      |

If a matchmaker is experiencing high load:

* if CPU is throttling, matchmaking could be slowed down,
* if matchmaker runs out of memory, it will restart without losing ticket information, hoping that clients will implement exponential backoff and the burst is spread over longer period of time.

## ⏩ Rolling Updates <a href="#rolling-updates-and-ab-tests" id="rolling-updates-and-ab-tests"></a>

Keeping track of compatibility between server and client versions can get complicated. Follow our tips for reliable releases, updates, and preventing downtime or compatibility issues.

**Your Matchmaker URL and Auth token will always remain the same after restarting.**

{% hint style="danger" %}
**Create separate matchmakers for dev & production** environments to experiment safely.
{% endhint %}

#### ⚠️ **Before Going Live**

We recommend creating multiple copies of your matchmaker ahead of time: `green`, `blue` and `orange`. You can rotate which matchmaker is in use as you release updates ([blue/green strategy](https://en.wikipedia.org/wiki/Blue%E2%80%93green_deployment)).

**Choose different regions for each instance to prevent downtime** during localized outages.

<figure><img src="https://3027732442-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2Flzy4elHYDPBMpjSMG1HS%2Fimage.png?alt=media&#x26;token=7da795fc-ae6c-490f-b65c-5f8dda635503" alt=""><figcaption><p>Blue/Green DevOps Environment Example</p></figcaption></figure>

#### **🔃 Client + Server Update**

**Prerequisites:** This section assumes you’ve completed [#before-going-live](#before-going-live "mention").

In order to **release game client + server updates**, you may:

1. Prepare new server app version `v1.2.0-rc` on Edgegap:
   1. push a new image tag to your container registry `t1.2.0`,
   2. create new app version `v1.2.0-rc`,
2. Perform any dev tests by [deploying your new app version](https://app.edgegap.com/deployment-management/deployments/list) `v1.2.0-rc`:
   1. connect your game engine’s Editor to the provided URL + external port,
3. Update unused matchmaker `blue` to link to your new image tag `t1.2.0`,
   1. enable caching for new app version `v1.2.0-rc` , enabling cache for this version will ensure the image is also cached for version `v-blue`  since they reference the same tag,
   2. wait for caching indicator in version `v1.2.0-rc`  to reach :green\_circle: green,
4. Update your new game client `c2` to use the new version `v-blue` when creating tickets:
   1. update your base URL and Authorization token in game client,
5. Perform QA tests and final verifications of your new game client `c2`:
   1. if you find and resolve any issues, repeat process from the beginning,
   2. wait 3-7 days to propagate matchmaker DNS changes to ISPs globally, after the matchmaker has been stopped (quick restart doesn't require DNS updates or waiting period),
6. Release your new game client update `c2` on game distribution platforms,
7. Allow time for new game client `c2` to distribute to player devices (typically up to 3-7 days):
   1. monitor outdated game clients `c1`  using deployment [#analytics](https://docs.edgegap.com/orchestration/deployments#analytics "mention"),
8. Clean up unused resources in your Edgegap account:
   1. delete image tag `t1.0.0` to free up Container Registry capacity,
   2. delete image tag `t1.1.0` to free up Container Registry capacity,
   3. turn off your `green`  matchmaker to pause billing until your next update.

{% hint style="success" %}
**For your next update**, increase version numbers and swap `green` and `blue` keywords in the guide.
{% endhint %}

#### **⚡ Server Hotfix**

**Prerequisites:** This section assumes you’ve completed [#before-going-live](#before-going-live "mention").

To **release a server patch without requiring a game client update**, you may:

1. Prepare new server app version `v1.2.0-rc` on Edgegap:
   1. push a new image tag to your container registry `t1.2.0`,
   2. create new app version `v1.2.0-rc`,
2. Perform tests and verifications by [deploying your new app version](https://app.edgegap.com/deployment-management/deployments/list) `v1.2.0-rc`:
   1. connect your game engine’s Editor to the provided URL + external port,
   2. if you find and resolve any issues, repeat process from the beginning,
   3. enable caching for new app version `v1.2.0-rc` , enabling cache for this version will ensure the image is also cached for version `v-green`  later since they will reference the same tag,
   4. wait for caching indicator in version `v1.2.0-rc`  to reach :green\_circle: green,
3. Update version `v-green`  to link to your new image tag `t1.2.0`,
   1. new matches will automatically initiate assignment with the updated tag `t1.2.0`,
   2. monitor outdated game clients `c1`  using deployment [#analytics](https://docs.edgegap.com/orchestration/deployments#analytics "mention"),
4. Clean up of unused resources in your Edgegap account:
   1. delete image tag `t1.1.0` to free up Container Registry capacity.

## 📗 API <a href="#matchmaking-api" id="matchmaking-api"></a>

Clients and servers may call API directly or with game engine SDKs, see also [](https://docs.edgegap.com/learn/matchmaking "mention").

{% hint style="info" %}
Unity/Android - consider [using raw string interpolation](https://www.c-sharpcorner.com/article/convert-string-to-json-in-c-sharp/) to prevent code stripping of hardcoded JSONs.
{% endhint %}

{% hint style="success" %}
**Swagger Web UI**: deploying your service will generate an openAPI specification and a convenient web UI. Open the URL in your browser to view and test all API endpoints, and to review payload examples.
{% endhint %}

{% tabs fullWidth="false" %}
{% tab title="🍀 Simple Example" %}
{% file src="<https://3027732442-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2FqofgtLfdhstOFoJr1BzV%2Fmm-conf-simple-example.json?alt=media&token=7dc25895-aef3-4174-9f40-e45af77a28d6>" %}
{% endtab %}

{% tab title="🏁 Advanced Example" %}
{% file src="<https://3027732442-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2FxSkXEzgG9AUPrXbsFsTU%2Fmm-conf-advanced-example.json?alt=media&token=4bcc1c0b-5887-457f-8a50-d89c0b20714e>" %}
{% endtab %}

{% tab title="🎾 Custom Lobby" %}
{% file src="<https://3027732442-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2Fts2LDr07atVf70MREw7j%2Fmm-conf-custom-lobby.json?alt=media&token=0215a52a-3fc1-47e8-beb9-6e90a4c49f6d>" %}
{% endtab %}

{% tab title="🥛 Backfill Showcase" %}
{% file src="<https://3027732442-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2FJEbYPVDhVI8UNCIcyFxQ%2Fmm-conf-backfill-example.json?alt=media&token=64733825-a3de-4d91-96fd-0f2f5e8be0cc>" %}
{% endtab %}

{% tab title="⚔️ Competitive Games" %}
{% file src="<https://3027732442-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2FVUNHRCiqRhf7axG6KQAD%2Fmm-conf-competitive-example.json?alt=media&token=7e49eb87-f07e-4969-b141-dbb8edea37fe>" %}
{% endtab %}

{% tab title="🤝 Cooperative Games" %}
{% file src="<https://3027732442-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2F6pWfNV1QOvpWbYQtbxc6%2Fmm-conf-cooperative-example.json?alt=media&token=b5c9f44b-cdd2-4968-8445-3f74d56b61c8>" %}
{% endtab %}

{% tab title="🎈 Social Games" %}
{% file src="<https://3027732442-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2FkVZMSRCd7JTXwOK2MqoW%2Fmm-conf-social-example.json?alt=media&token=ef26e619-5b31-4395-8e35-7607cb21bd35>" %}
{% endtab %}
{% endtabs %}

Import API specification to [Scalar API Web Client](https://client.scalar.com/workspace/default/request/default) or [Swagger Editor](https://editor.swagger.io/) to inspect details.

### Server to Server <a href="#server-to-server-api" id="server-to-server-api"></a>

Add enhanced or customized controls over matchmaking flow - implement a custom proxy using our [managed-clusters](https://docs.edgegap.com/learn/advanced-features/managed-clusters "mention") or any cloud FaaS[^13] compute platform, to achieve any of:

* attach sensitive player attributes - such as cheater flags, skill ratings, or similar,
* provide team and match context in-game - list my teammates and opponents during loading,
* restrict specific edge cases - e.g. allow only 1 group per player at any time,
* add caching or API rate limiting - reduce number of requests and load on matchmaker,
* customize lobby-group integration - create asymmetric/role-based lobbies before matchmaking.

{% hint style="success" %}
**Include parameter `player_ip`  with member's public IP address** to ensure lowest possible player latency and take advantage of [#id-1.-server-score-strategy-best-practice](https://docs.edgegap.com/orchestration/deployments#id-1.-server-score-strategy-best-practice "mention").
{% endhint %}

{% hint style="info" %}
Game clients may use [ipify.org](http://ipify.org/) free service to find their public IPs. VPNs may mask public IP address.
{% endhint %}

<figure><img src="https://3027732442-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2FzLfA3fEBgwaziGtp2yMO%2Fimage.png?alt=media&#x26;token=3d551e74-4a60-47a6-9d79-a506f961663d" alt=""><figcaption><p>Server to Server Matchmaking Activity Diagram</p></figcaption></figure>

#### Cross-Origin Resource Sharing (CORS)

For webGL games hosted on third party distribution platforms (e.g. [itch.io](http://itch.io/)), sending any requests to Matchmaker from game client may result in [Cross-Origin Resource Sharing](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS) policy violations. Most modern web browsers send a [pre-flight request](https://developer.mozilla.org/en-US/docs/Glossary/Preflight_request) to verify that a backend service (the Matchmaker) understands and accepts communication from your game client.

Failing pre-flight check (default for security reasons) can result in [one of several possible CORS-related errors](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS/Errors/CORSMissingAllowOrigin), most commonly `CORS header 'Access-Control-Allow-Origin' missing` .

To resolve this error, add **`allowed_cors_origin`** parameter to your configuration to either:

* whitelist your exact client hosting domains:

<details>

<summary>🍀 Simple Example (Specific Domains Example)</summary>

<pre class="language-json"><code class="lang-json">{
  "version": "3.2.0",
  "allowed_cors_origins": [
    "https://dev.my-game-server.com",
    "https://prod.my-game-server.com"
  ],
  "profiles": {
      <a data-footnote-ref href="#user-content-fn-14">...</a>
  }
}
</code></pre>

</details>

* or whitelist a wildcard domain (including all subdomains):

<details>

<summary>🍀 Simple Example (Wildcard Domain Example)</summary>

<pre class="language-json"><code class="lang-json">{
  "version": "3.2.0",
  "allowed_cors_origins": ["https://*.my-game-server.com"],
  "profiles": {
      <a data-footnote-ref href="#user-content-fn-14">...</a>
  }
}
</code></pre>

</details>

{% hint style="info" %}
**No credentials are required for Matchmaker pre-flight requests**, if domains are configured correctly.
{% endhint %}

## 🚨 Troubleshooting

**Your success is our priority.** If you'd like to send custom requests, ask for missing critical features, or express any thoughts, [please reach out in our Community Discord](https://discord.gg/MmJf8fWjnt).

<details>

<summary><code>The application configuration is not valid for profile XYZ.</code></summary>

* We couldn’t find your [application-and-versions](https://docs.edgegap.com/learn/orchestration/application-and-versions "mention"), please verify `application`  values.

</details>

<details>

<summary><code>Docker image for '2024.01.30-16.23.00-UTC' is not cached.</code></summary>

[**🌟 Upgrade to Pay as You Go tier**](https://app.edgegap.com/user-settings?tab=memberships) **to unlock** [**instant deployments with Caching**](https://docs.edgegap.com/orchestration/deployments#id-1.-start-a-deployment)**.**

* 4GB+ uncached images may take longer to deploy, resulting in [#id-4.-deployment-error](https://docs.edgegap.com/orchestration/deployments#id-4.-deployment-error "mention"). Consider optimizing your server image size ([Unreal Engine](https://docs.edgegap.com/unreal-engine#optimize-server-build-size) / [Unity](https://docs.edgegap.com/unity#optimize-server-build-size)).
* You may proceed anyway, though we recommend testing your deployment time.

</details>

<details>

<summary>Why am I getting errors when trying to create a new matchmaker?</summary>

* Please read the error, it’s possible you’ve misspelled an identifier, rule, or an operator. - Use [JSONLint](https://jsonlint.com/) to validate your JSON formatting, you may have missed a comma or a bracket. - Reach out over [our Community Discord](https://discord.gg/MmJf8fWjnt) for help, we’ll be happy to assist. 🙏

</details>

<details>

<summary>Why did my matchmaker turned off automatically after 3 hours?</summary>

* Matchmakers in Free Tier are intended for initial tests and are automatically turned off after 3 hours. To continue testing you may [restart your matchmaker](https://app.edgegap.com/matchmaker-management-v2/matchmakers/list).
* Consider upgrading to paid tier for unliminted runtime.

</details>

<details>

<summary>Why can’t I start a second deployment on my account?</summary>

* You may only run 1 concurrent deployment in Free Tier.
* Please consider upgrading to paid tier for unlimited deployments.

</details>

<details>

<summary>Why am I getting assignment/deployment at random times, disregarding <code>player_count</code>?</summary>

* You or another team member may have created tickets during a previous testing session which were not assigned. Please [restart your matchmaker](https://app.edgegap.com/matchmaker-management-v2/matchmakers/list).

</details>

<details>

<summary>My ticket is stuck in <code>SEARCHING</code> .</summary>

* Please verify you’ve created enough matching tickets adhering to your configuration.

</details>

<details>

<summary>My ticket is stuck switching between <code>MATCH_FOUND</code> and <code>TEAM_FOUND</code> repeatedly.</summary>

* Free Tier accounts are limited to 1 deployment at a time.
* Please consider upgrading or stop your current deployment to start a new one.

</details>

<details>

<summary>My ticket goes straight to <code>CANCELLED</code>.</summary>

* Your ticket reached it’s expiration. Create a new ticket or increase the expiration period in your configuration for testing purposes.

</details>

<details>

<summary>I receive <code>HTTP 404 Not Found</code> when checking on my ticket.</summary>

* Your ticket was removed either by a DELETE request, or by reaching it’s removal period (starts after ticket is expired, defined in your configuration). Recreate a new ticket or increase the expiration/removal periods in your configuration for testing purposes.

</details>

<details>

<summary>My matchmaker shows an error, what should I do?</summary>

* If this is a development or a testing instance, try restarting your matchmaker first. - Please report any issues through [our Community Discord](https://discord.gg/MmJf8fWjnt).
* In case this issue is impacting a live game, create an [urgent support request](https://edgegap.atlassian.net/servicedesk/customer/portal/3).

</details>

## 🔖 Changelog

#### Semantic Versioning

Our matchmaker uses official [Semantic Versioning](https://semver.org/) guidelines. Each configuration JSON is tied to a specific version of the service. Service version dictates which rules and settings are available in your configuration and API. **Once a version is released, it will never change**.

Your configuration file will be validated depending on matchmaker version used, make sure your rules are matching the matchmaker version’s capabilities.

{% hint style="info" %}
**The latest version of matchmaker is `3.2.1`**. All examples on this page are up to date. Keep an eye out for end of support notices for your matchmaker version. See also [#rolling-updates-and-ab-tests](#rolling-updates-and-ab-tests "mention").
{% endhint %}

#### 3.2.1 (Nov 24, 2025)

{% hint style="success" %}
**This is the latest matchmaker service version, recommended for production use.**
{% endhint %}

{% hint style="warning" %}
**To upgrade your matchmaker version - Stop, Edit, Restart.** Quick Restart won't apply version changes.
{% endhint %}

🩹 **Bugfixes:**

* Minor deployment bugfixes, resolved several errors when starting your matchmaker.

#### 3.2.0 (Oct 31, 2025)

🩹 **Bugfixes:**

* Various smaller specification fixes and documentation consistency updates.
* Various stability and self-healing fixes across matchmaker infrastructure.

**✨ Improvements and new features:**

* **Introducing** [#group-up](#group-up "mention") **feature** - managing groups is now easy and doesn't require 3rd party!
  * No more sharing complex ticket attributes amongst group members, you only need Group ID.
  * Start matching as a group once all of your players mark themselves as ready.
  * Validate group member attributes against the group leader upon joining, preventing unmatchable groups (attributes of group players wouldn't match under profile's rules).
  * Validate group size and decline new memberships once max team size is reached.
  * Read our updated documentation with the new user flow, SDK updates coming soon!
* Tickets (memberships) now include your match ID - track players and add UI elements to share your team or opponent teams nicknames, skill rating, or other properties stored in third parties.
* Major [#rate-limits](#rate-limits "mention") overhaul based on internal stress testing, better handling of short bursts.
* Improved match fill rate due to delaying partial matches size until end of expansion.
  * If maximum team size reached, match immediately.
  * Otherwise match at the end of current expansion, if minimum team size reached.
* Set expiration and removal periods per profile and optimize for best player experience.

{% hint style="warning" %}
To update your Configuration, increase version, and copy expiration and removal fields to each profile.
{% endhint %}

#### 3.1.0 (June 10, 2025)

🩹 **Bugfixes:**

* Matchmakers now correctly validate tickets with multiple profiles including different rules.

**✨ Improvements and new features:**

* More optimizations to maximize match fill rate with [player\_count rule](#matchmaking-rules). Tickets will now wait until end of expansion (or expiration) if only partial match is possible (>min and \<max team size).
  * Full matches (max team size reached) are made immediately (no change).
* Upgrade to Enterprise [#hosting-cluster](#hosting-cluster "mention") to unlock matchmaking [#analytics](#analytics "mention")! Gain insights into matchmaker load and performance, no code or configuration required. Metrics at launch include:
  * total tickets, backfills, assignments, and deployments made over custom period of time,
  * per minute rates for the above metrics over custom period of time,
  * totals and time series insights into expired tickets, expanded matches, match fill rate,
  * API usage metrics, and more.
* Improved [#matchmaking-rules](#matchmaking-rules "mention") documentation with better examples and visuals.

#### 3.0.0 (May 20, 2025)

**⚠️ Breaking changes:**

* Use [min/max team size to fill teams efficiently](#matchmaking-rules) (replaces player count expansions):
  * in your configuration `player_count` rule, replace `team_size` with `min_team_size` and `max_team_size` to achieve "best effort" matching attempting to maximize match fill rate,
  * to require a specific number of players per team, set both min and max to the same value,
  * backfills bypass `player_count` rule and always match with 1 ticket (unchanged).
* Tickets, group tickets, and backfills with all latencies above the highest `max_latency` in a given profile will be immediately rejected with `400 Bad Request` response to ticket create request, instead of expiring:
  * only applies if [latency rule](#matchmaking-rules) is configured,
  * to bypass this behavior, create an expansion with `max_latency: 99999` (any value higher than your client latency measurement timeout).
* [Injected environment variables](#injected-environment-variables) containing ticket data now include field `id` (ticket ID) so they can be reused more easily when creating [#backfills](#backfills "mention").

🩹 **Bugfixes:**

* [#backfill](#backfill "mention") now uses configured deletion and expiration period (like tickets and group tickets).
* [#backfill](#backfill "mention") now correctly matches using configured [`intersection` rules](#matchmaking-rules).
* Fixed [openAPI specification](#matchmaking-api) for POST [#backfills](#backfills "mention") request (requires `public_ip`) and GET /tickets response (`team_id` is optional), including examples.

**✨ Improvements and new features:**

* Up to 3x more potential matches are considered now, producing more optimal groups and maximizing match fill rate.
* Up to 200% faster matching speed due to concurrency optimizations.
* Up to 40% increased match fill rate due to optimization of expansions algorithm.
* Improved service stability and increased speed of quick restarts.

{% hint style="info" %}
Benchmarks were produced with chaos-generated data using [Advanced Example configuration](#configuration).
{% endhint %}

#### 2.1.0 (Feb 24, 2025)

**⚠️ Breaking changes:**

* Separated game profile and expansion stage information in the [#injected-environment-variables](#injected-environment-variables "mention"):
  * `MM_MATCH_PROFILE` will now only include the profile name as it appears in the configuration.
  * Introduced `MM_EXPANSION_STAGE` which will contain the expansion stage as a string (e.g. "initial", "15", "30").
* Ticket assignments now include the group ID when [#endpoint-tickets](#endpoint-tickets "mention"). Group ID is also included as an [#injected-environment-variables](#injected-environment-variables "mention"), as a mapping of group ID to a list of the group's player IDs.
* Ticket assignments now include the team ID when [#endpoint-tickets](#endpoint-tickets "mention"). The team ID is also included in every ticket data [#injected-environment-variables](#injected-environment-variables "mention").
* [#endpoint-tickets](#endpoint-tickets "mention") now returns `409 Conflict` HTTP code instead of `204 No Content` to indicate the ticket can't be deleted since the deployment is starting. To replace leavers, use a [#backfill](#backfill "mention") issued by the server after a pre-specified timeout period.
* [#endpoint-backfills](#endpoint-backfills "mention") request body parameter `attributes.deployment_request_id` has been moved to `attributes.assignment.request_id`.
* [#endpoint-backfills](#endpoint-backfills "mention") request body now requires full assignment details as part of `attributes` parameter in addition to the `request_id`.

🩹 **Bugfixes:**

* Resolved intersection rule values are now [#injected-environment-variables](#injected-environment-variables "mention") in the `MM_INTERSECTION` environment variable.
* Quick restart feature now reliably regenerates API endpoints and openAPI specification when configuration is changed.
* Fixed several bugs during matchmaker (re)start causing prolonged startup time or getting matchmaker stuck.

**✨ Improvements and new features:**

* Increased rate limits and scalability of all API endpoints, across all matchmaker tiers.
* When assigning a player to a [#backfill](#backfill "mention"), the new player's ticket ID will be added as a tag to the Backfill's [deployments](https://docs.edgegap.com/learn/orchestration/deployments "mention").
* Added swagger UI authentication feature to test API directly in web UI without needing postman.
* Improved openAPI examples to reflect realistic requests and responses more closely.
* Added new [#inspect-api](#inspect-api "mention") meant for development and debugging purposes.
  * Allows listing all current player tickets in a paginated list.
  * Allows listing all current matches in a paginated list.

#### 1.0.0 (Dec 9, 2024)

* [#backfill](#backfill "mention"): Upon (popular) request, we’re adding backfill with automated ticket assignment, which allows you to reuse server seats when players leave the session.
  * Ideal for filling empty player seats after a match has begun, or for replacing players that have left during a match.
* [#join-as-group](#join-as-group "mention"): We’re adding the ability to join as a group to the already available ability to fill multiple teams with players.
  * Ideal for joining up in a matchmaking queue with a group of friends or coming from a common lobby.
* [#matchmaking-sdk](https://docs.edgegap.com/unity/developer-tools#matchmaking-sdk "mention") and [#edgegap-integration-kit-by-betide-studio](https://docs.edgegap.com/unreal-engine/developer-tools#edgegap-integration-kit-by-betide-studio "mention") matchmaking SDKs:
  * To make integration easier, we’re now offering Software Development Kits for the most popular game engines.
* Fixed a bug where the [#latencies-attributes](#latencies-attributes "mention") was not applied correctly.
* Tickets will now be automatically canceled after a [#matchmaking-process](#matchmaking-process "mention") if they haven't been assigned to a deployment.
* You can now [#endpoint-tickets](#endpoint-tickets "mention") to enhance the flow of your matchmaking process.
* Deployments made by the matchmaker are now tagged with ticket IDs.
* You can now edit your configuration while the matchmaker is running. This triggers a quick reload of your configuration without requiring a full on/off cycle for your matchmaker. Note: This feature is not recommended for production environments, as it deletes all current tickets and temporarily makes the API unresponsive.
* Fixed [#injected-environment-variables](#injected-environment-variables "mention") to use the correct primitive types instead of arrays.
* Fixed [#injected-environment-variables](#injected-environment-variables "mention") JSON values, which previously contained escaped characters.

#### 0.2.3 (Oct 8, 2024)

{% hint style="info" %}
This version is no longer supported, please use a newer version for your matchmaker.
{% endhint %}

* Fixed a bug where certain headers were not accepted by the matchmaker when requests were made from a WebGL application (CORS policies).

#### 0.2.2 (Oct 3, 2024)

{% hint style="info" %}
This version is no longer supported, please use a newer version for your matchmaker.
{% endhint %}

* Fixed issue with TLS/SSL certificate validation preventing matchmaker from launching.

#### 0.2.1 (Sep 30, 2024)

{% hint style="info" %}
This version is no longer supported, please use a newer version for your matchmaker.
{% endhint %}

* Fixed a bug causing the beacons endpoint to return a 500 error.

#### 0.2.0 (Sep 25, 2024)

{% hint style="info" %}
This version is no longer supported, please use a newer version for your matchmaker.
{% endhint %}

* Basic authentication is now mandatory for all endpoints.
* Added the ability to configure the number of retries on server assignment failure.
* Team-based matchmaking is now the default for all matchmaking configurations.
* Both application and version are now required fields in all profiles.
* Introduced a new endpoint to monitor the matchmaker's status.
* Updated the format of the tickets environment variable in the deployment.
* Added a configuration option to allow hosts to communicate with the matchmaker.
* The debug API is now only available when explicitly enabled in the configuration (it is currently disabled for rework).
* The `game_profile` key in the GET ticket response has been replaced by `profile`.

[^1]: example value

[^2]: game clients join a Lobby to retrieve matchmaking Group ID and join the Group

[^3]: Fully Qualified Domain Name

[^4]: e.g. for 3 free slots = \["3", "2", "1"]

[^5]: replace "2" with the number of actual group members

[^6]: replace with your own application name

[^7]: replace with your own application version

[^8]: maximum difference exceeded

[^9]: maximum latency exceeded

[^10]: Internet Service Provider

[^11]: highest concurrent users on a given day

[^12]: concurrent users during off-periods

[^13]: [Function as a Service](https://www.ibm.com/think/topics/faas)

[^14]: see other examples


# Server Browser

**Welcome to Edgegap Server Browser OPEN BETA.** We hope you enjoy the opportunity to preview our new service, and help shape it's future through roundtable discussions in our Discord.

Server Browser is a managed service for [#match-bound](https://docs.edgegap.com/orchestration/deployments#match-bound "mention") and [Persistent](https://docs.edgegap.com/learn/orchestration/persistence) servers:

* **help players search and join suitable servers** based on capacity, latency, or game parameters;
* **pre-warm new servers** to serve global audiences at scale and prevent frustrating queues;
* **streamline server operations** including updates, restarts, persistence, meshing, and more.

{% hint style="success" %}
Looking to match players based on strict rules, without allowing server choice? Consider [matchmaking](https://docs.edgegap.com/learn/matchmaking "mention").
{% endhint %}

<figure><img src="https://3027732442-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2FwKrq9tLaamRoM6vSLXZu%2Fimage.png?alt=media&#x26;token=83756c6f-d413-4ac1-988e-b90e7fa7a0a6" alt=""><figcaption></figcaption></figure>

## ✔️ Preparation

**Testing this service is entirely free, no credit card required.**

Free Tier allows up to 3 hours of runtime on our shared test cluster, after each restart.

This tutorial assumes you have already:

* [understood Edgegap’s deployment model](https://docs.edgegap.com/orchestration/deployments#id-1.-just-in-time-deployment-dedicated-servers),
* published your server application on Edgegap ([unreal-engine](https://docs.edgegap.com/unreal-engine "mention"), [unity](https://docs.edgegap.com/unity "mention")),
* successfully connected from a game client to your server on Edgegap.

### Flow and Hierarchy

<figure><img src="https://3027732442-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2Fnwlt2Ot2ahlyLvI7kdGx%2Fimage.png?alt=media&#x26;token=14b5a6c8-48c8-4f23-a50a-0783acab14e3" alt=""><figcaption><p>Server Browser: Flow and Hierarchy</p></figcaption></figure>

Server Browser offers two main features:

**▶️ Start Browsing** with Game Clients to:

* Discover and find suitable server instances, view slots, and reserve available capacity.
* Reserve seats in an instance slot, retrieve connection details, and connect to servers.
* Authenticate player connections from Deployments using [Federated Identity](#user-content-fn-1)[^1].
* Update instance slots' available capacity and/or metadata to modify discovery criteria.

**🚀 Automated Scaling** (optional) with Scaling Policies to:

* Monitor available server instances, slots, capacity - per region and/or other criteria.
* Create Deployments to increase capacity with prewarming or just-in-time scaling.
* Automate ops with special policies for demos, updates, testing, QA, tournaments, and more.

{% hint style="info" %}
After release, **your server browser will need to run 24/7** to ensure players across the world can join servers.
{% endhint %}

## ▶️ Start Browsing

Learn about server/player lifecycle and their responsibilities to ensure efficient server use.

### Authenticate

All requests must send an `Authorization`  HTTP header with your secret **Auth Token:**

<pre><code>Authorization: <a data-footnote-ref href="#user-content-fn-2">xxxxxxxx-e458-4592-b607-c2c28afd8b62</a>
</code></pre>

{% hint style="warning" %}
**Keep your tokens secret and safe! Edgegap staff will never ask you for your tokens.**
{% endhint %}

Server Browser automatically generates two types of tokens:

* **Server Token** - required for [Server API](#server-lifecycle) methods, can be [injected as app version variable](https://docs.edgegap.com/orchestration/application-and-versions#injected-variables).
  * Grants access to all API methods, and is handy for testing, devops, or custom orchestration.
* **Client Token** - required for [Monitor API and Seat Reservation API](#player-lifecycle) used by Game Clients.
  * We recommend storing this token in a third party secret store to make token rotation easier.

### Discover Instance

**New** [deployments](https://docs.edgegap.com/learn/orchestration/deployments "mention") **must create a new Instance with at least one Slot when initialized.**

{% hint style="info" %}
See [#configuration](#configuration "mention") to learn about Scaling Policies and start deployments automatically.
{% endhint %}

**Optional custom metadata parameters** for player filtering, sorting, and browsing.

Examples:

* slot information - team capacity and team-specific metadata (e.g. team name),
* name and tags - customizable, unique, human-readable and searchable labels;
* connection details - URL, IP, external ports, or other parameters;
* compatibility data - server version or supported client versions;
* latency qualifiers - city and region identifiers, and assigned [ping-beacons](https://docs.edgegap.com/learn/orchestration/ping-beacons "mention") details;
* game parameters - level/scene/map, game mode, difficulty, mods used;
* any other custom parameters to help players filter and find a suitable server.

{% hint style="info" %}
Metadata parameters above are just examples, you can define any parameters including the above. All  metadata parameters are optional, and some instances may not need to define all parameters.
{% endhint %}

Metadata supports string keys and values containing string, number, boolean, or array of strings.

{% hint style="success" %}
To serialize nested objects try encoding their accessor path in the key as `"object.child.property"`.
{% endhint %}

Servers may **update instance or slot metadata anytime** to modify their discoverability criteria.

**Server Instances must periodically send a keep-alive heartbeat** to verify their ongoing availability and prevent players from joining crashed or offline servers. Missing heartbeat for the configured expiration period will automatically delete instance and any pending seat reservations.

{% hint style="info" %}
See [persistence](https://docs.edgegap.com/learn/orchestration/persistence "mention") for managing persistent world state and [#active-caching](https://docs.edgegap.com/orchestration/application-and-versions#active-caching "mention") for faster deployments.
{% endhint %}

### Search and Browse

Players may list server instances and [paginate through results](#pagination) to find a server they'd like to join. To display ping (latency) data, read each instance's [ping-beacons](https://docs.edgegap.com/learn/orchestration/ping-beacons "mention") details and [measure latency](https://docs.edgegap.com/orchestration/ping-beacons#measuring-round-trip-time).

Instances and slots may be filtered by joinable seats or [indexed metadata parameters](#configuration).

<table><thead><tr><th width="170">Parameter</th><th width="135">Operators</th><th>Example Filter (based on Simple Example)</th></tr></thead><tbody><tr><td><code>"joinable_seats"</code></td><td><p><a data-footnote-ref href="#user-content-fn-3"><code>eq</code></a>  or <a data-footnote-ref href="#user-content-fn-5"><code>ne</code></a> or </p><p><a data-footnote-ref href="#user-content-fn-7"><code>lt</code></a>  or <a data-footnote-ref href="#user-content-fn-8"><code>le</code></a> or </p><p><a data-footnote-ref href="#user-content-fn-9"><code>gt</code></a>  or <a data-footnote-ref href="#user-content-fn-10"><code>ge</code></a></p></td><td><pre><code>?filter=<a data-footnote-ref href="#user-content-fn-4">joinable_seats gt 0</a>
&#x26;orderby=<a data-footnote-ref href="#user-content-fn-6">joinable_seats desc</a>
</code></pre></td></tr><tr><td><code>"string"</code><br>(metadata)</td><td><p><a data-footnote-ref href="#user-content-fn-3"><code>eq</code></a>  or <a data-footnote-ref href="#user-content-fn-5"><code>ne</code></a> or </p><p><a data-footnote-ref href="#user-content-fn-7"><code>lt</code></a>  or <a data-footnote-ref href="#user-content-fn-8"><code>le</code></a> or </p><p><a data-footnote-ref href="#user-content-fn-9"><code>gt</code></a>  or <a data-footnote-ref href="#user-content-fn-10"><code>ge</code></a>  or<br><code>contains</code></p></td><td><pre><code>?filter=metadata.custom_name contains 'my game'
and metadata.server_version le '1.1.0'
and metadata.server_version ge '1.0.0'
&#x26;orderby=metadata.custom_name asc
</code></pre></td></tr><tr><td><p><code>"int"</code> , or <code>"float"</code></p><p>(metadata)</p></td><td><p><a data-footnote-ref href="#user-content-fn-3"><code>eq</code></a>  or <a data-footnote-ref href="#user-content-fn-5"><code>ne</code></a> or </p><p><a data-footnote-ref href="#user-content-fn-7"><code>lt</code></a>  or <a data-footnote-ref href="#user-content-fn-8"><code>le</code></a> or </p><p><a data-footnote-ref href="#user-content-fn-9"><code>gt</code></a>  or <a data-footnote-ref href="#user-content-fn-10"><code>ge</code></a>  </p></td><td><pre><code>?filter=metadata.xp_multiplier gt 1.0
&#x26;orderby=metadata.xp_multiplier desc
</code></pre></td></tr><tr><td><code>"bool"</code><br>(metadata)</td><td><a data-footnote-ref href="#user-content-fn-3"><code>eq</code></a>  or <a data-footnote-ref href="#user-content-fn-5"><code>ne</code></a></td><td><pre><code>?filter=metadata.allows_new_connections eq true
</code></pre></td></tr></tbody></table>

{% hint style="success" %}
Filter by regions and/or cities to narrow down selection before measuring latency to servers.
{% endhint %}

{% hint style="info" %}
Learn about cursor-based [#pagination](#pagination "mention") to let users fetch more results.
{% endhint %}

### Reserve Seats

Before joining a server, a seat reservation is required to ensure that the instance offers sufficient available capacity. Reservations can include a group of players or a solo individual.

**Reservations exceeding slot's joinable seat capacity will be automatically rejected** ([409 Conflict](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Status/409)). Joinable seats are any available seats which have not been reserved by other players yet.

Federated Identity: Players must provide a unique third party player ID in their reservation. Sending the same ID once they [#connect-to-server](#connect-to-server "mention") will allow the server to verify their identity.

Once a reservation is made successfully ([200 OK](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Status/200)) players should attempt connecting immediately. Pending **reservations will expire after 30 seconds unless they are confirmed** by your server.

{% hint style="info" %}
Server may forcefully change any slot's capacity, add, delete, or update any slots. **All reservations for a given slot will be removed if any pending reservations exceed new available slot capacity.**
{% endhint %}

### Connect to Server

Once a player found a suitable instance, they can **retrieve required connection details from metadata** (URL, IP, [External Port](https://docs.edgegap.com/orchestration/application-and-versions#port-mapping)). As soon as the seat reservation is made, **players may proceed to connect to your deployment's game server and pass their player ID**.

{% tabs %}
{% tab title="Unreal Engine" %}
To **connect from PIE (Editor)** during development and testing, press the tilde key `~`  and type `open {URL}:{port}` and wait for your editor to load the map.

{% hint style="success" %}
In case of failed connections or dark screen consult our [troubleshooting guide](https://docs.edgegap.com/unreal-engine#troubleshooting-and-faq-1).
{% endhint %}
{% endtab %}

{% tab title="Unity" %}
To **connect your Unity Editor** or **game client** to your cloud deployment, input:

* **Deployment** **URL** pointing to the server's IP, usually in `NetworkManager`  component.
* **External port** mapping to the [server's internal listen port](https://docs.edgegap.com/learn/advanced-features/application-and-versions#port-mapping), usually in a Transport component.

{% hint style="success" %}
In case of connection timeout or other issues consult our [troubleshooting guide](https://docs.edgegap.com/unity#troubleshooting-and-faq-4).
{% endhint %}
{% endtab %}
{% endtabs %}

To authenticate new connections, **your server must send a bulk reservation confirmation** request with all new players' IDs, receiving information in confirmation response:

* assignment of accepted player reservations to their preferred slot,
* assignment of expired player reservations to their preferred slot,
* a list of unknown player IDs.

Your **server may decide how to handle each group of players** and whether to allow or kick/ban expired or rejected users. Each of the **instance's slots must be updated immediately with the new available seat count** to ensure new reservations won't exceed capacity.

### Abandon Server

When players leave, the server must update their assigned slot to reflect new available seat capacity.

{% hint style="success" %}
If your game design allows a reconnection period, your server may wait before releasing seats.
{% endhint %}

We recommend stopping servers with no players to optimize your hosting cost. Waiting a few minutes before doing so can reduce the amount of restarts during short periods of idling.

Read about [#recovery-objectives](https://docs.edgegap.com/orchestration/persistence#recovery-objectives "mention") to prevent frustrating persistent server rollbacks.

## ⚙️ Configuration <a href="#configuration" id="configuration"></a>

Server Browser API is generated from a JSON configuration specified when you create a new (or quick-restart) Server Browser. You may specify server and slot expiration, and custom metadata:

<pre class="language-json" data-title="🍀 Simple Example v0.0.5" data-expandable="true"><code class="lang-json">{
	"version": "0.0.5",
	"server_instances": {
		"expiration_period": "30m",
		"<a data-footnote-ref href="#user-content-fn-11">indices</a>": {
			"third_party_id": "string",
			"level": "string",
			"mode": "string",
			"difficulty": "string",
			"seed": "string",
			"avg_player_rank": "int",
			"max_player_count": "int",
			"is_ranked": "bool",
			"app_version": "string",
			"DEPLOYMENT_LOCATION.city": "string",
			"DEPLOYMENT_TAGS": "string",
			"IN_PRIVATE_FLEET": "bool",
			"HOST_BASE_CLOCK_FREQUENCY": "int",
			"DEPLOYMENT_VCPU_UNITS": "int",
			"DEPLOYMENT_MEMORY_MB": "int",
			"PORT_GAMEPORT_EXTERNAL": "string",
			"BEACON_ENABLED": "bool",
			"BEACON_PUBLIC_IP": "string",
			"BEACON_PORT_UDP_EXTERNAL": "string",
			"BEACON_PORT_TCP_EXTERNAL": "string",
			"MM_MATCH_ID": "string",
			"MM_INTERSECTION": "string",
			"MM_EQUALITY": "string"
		}
	},
	"server_instance_slots": {
		"<a data-footnote-ref href="#user-content-fn-11">indices</a>": {
			"third_party_id": "string",
			"name": "string",
			"max_player_count": "int",
			"avg_player_rank": "int",
			"avg_player_latency": "int",
			"player_ids": "string"
		}
	},
	"seat_reservations": {
		"expiration_period": "5m"
	},
	"scaling_policies": {
		"monitoring_interval": "10s",
		"deployment_registration_period": "1m"
	}
}
</code></pre>

{% hint style="info" %}
For best performance, avoid specifying indices for metadata not used for filtering or sorting. Non-indexed params can be still set and read with server instance or slot details API methods, see [#api](#api "mention").
{% endhint %}

## ☁️ Hosting Cluster

Server Browser is conveniently hosted and managed 24/7 around the clock by Edgegap.

Choose a hosting option best suited for your goal:

* **Free Cluster (shared)** to test all features and explore synergies with your design,
  * shuts down after 3 hours automatically, requiring restart to continue testing.
* **Private Cluster** **(dedicated)** to ensure a stable environment for your production needs,
  * pick your region and get 24/7 support for live games to release with confidence.

### Private Cluster Tiers

We currently offer [3 private cluster tiers](https://edgegap.com/resources/pricing#managed-infrastructure) to cater to everybody’s needs:

<table><thead><tr><th width="160">Tier</th><th align="right">Hobbyist Tier</th><th align="right">Studio Tier</th><th align="right">Enterprise Tier</th></tr></thead><tbody><tr><td>Best Suited For</td><td align="right">enthusiasts,<br>solo developers</td><td align="right">commercial releases</td><td align="right">high-traffic launches</td></tr><tr><td>Resources</td><td align="right">1 vCPU + 2GB RAM</td><td align="right">6 vCPU + 12GB RAM</td><td align="right">18 vCPU + 48GB RAM</td></tr><tr><td>Redundancy</td><td align="right">1x virtual node</td><td align="right">3x virtual nodes</td><td align="right">3x virtual nodes</td></tr><tr><td>Rate Limit (req/s)</td><td align="right">200</td><td align="right">750</td><td align="right">2,000</td></tr><tr><td>Price, hourly</td><td align="right">$0.0312</td><td align="right"> $0.146</td><td align="right">$0.548</td></tr><tr><td><strong>Price, 30 days</strong><br>(nonstop usage)</td><td align="right"><strong>$22.464</strong></td><td align="right"><strong>$105.12</strong></td><td align="right"><strong>$394.56</strong></td></tr></tbody></table>

Upgrade to a private cluster with one click to benefit from highly available hosting maintained by Edgegap team with 24/7 live support for publicly released games.

Resource requirements for your instance will depend on factors:

* **number of players** - more players result in more API requests,
* **number of requests per player** - faster retries increase service load and consume resources,
* **number of servers** - more servers result in more data stored and more API requests,
* **client retry fallback logic** - retrying with jittered backoff helps spread traffic burst peaks,
* **average match duration** - shorter sessions require more frequent server browser interaction.

{% hint style="info" %}
Our clusters use cloud machines featuring AMD/Intel CPUs with clock speed 2.4 - 3.2 GHz.
{% endhint %}

## 📗 API

Game Clients and Dedicated Servers send API requests throughout their lifecycle to Server Browser.

{% hint style="info" %}
Unity/Android - consider [using raw string interpolation](https://www.c-sharpcorner.com/article/convert-string-to-json-in-c-sharp/) to prevent code stripping of hardcoded JSONs.
{% endhint %}

{% hint style="success" %}
**Swagger Web UI**: deploying your service will generate an openAPI specification and a convenient web UI. Open the URL in your browser to view and test all API endpoints, and to review payload examples.
{% endhint %}

{% file src="<https://3027732442-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2F0auyzkkQfLfNRgzKbWMn%2Fedgegap-server-browser-005.yaml?alt=media&token=84669896-e7b9-4415-8d66-131badb3fff5>" %}

Import API specification to [Scalar API Web Client](https://client.scalar.com/workspace/default/request/default) or [Swagger Editor](https://editor.swagger.io/) to inspect details.

### Pagination

**Server Browser provides cursor pagination to fetch filtered data incrementally in a specific order.** This approach requires sending a cursor (starting point) and a page size (number of response items) whenever fetching more results, as opposed to the traditional limit-offset pagination.

{% hint style="info" %}
Combined with our proprietary database indexing system developed for game server metadata, cursor pagination provides a fast, consistent, and flexible user experience for filtering highly dynamic data.
{% endhint %}

Our goal is for users to find a suitable server on the first page. For best experience, we recommend showing cached results for previous pages, and only refreshing results when the user clicks Search.

## 🔖 Changelog

#### Semantic Versioning

Our matchmaker uses official [Semantic Versioning](https://semver.org/) guidelines. Each configuration JSON is tied to a specific version of the service. Service version dictates which rules and settings are available in your configuration and API. **Once a version is released, it will never change**.

{% hint style="info" %}
**The latest version of server browser is `0.0.4`** . Keep an eye out for updates and announcements.
{% endhint %}

#### 0.0.4 (Jan 05, 2026)

* Entering OPEN BETA, introducing [filtering and sorting for server instances and slots](#search-and-browse)!

#### 0.0.3 (Nov 28, 2025)

* Initial release of Server Browser service launched in CLOSED BETA.
* List Servers, Manage Capacity, and Get Connection Details.
* Support for match sessions with Cloud Deployments and always online with Private Fleets.

[^1]: third party player identifiers

[^2]: example value

[^3]: equals

[^4]: finds instances with available seats

[^5]: not equals

[^6]: show more filled instances first

[^7]: lower than

[^8]: lower than or equal

[^9]: greater than

[^10]: greater than or equal

[^11]: indices contain your custom metadata parameters used for filtering or sorting


# Advanced Features

Here, you will learn how to get more out of your Edgegap account. Understanding some server concepts in-depth can make your development process less prone to human error, more cost effective, and help customize to your specific needs.

{% hint style="success" %}
Before you send us your questions please use the search bar in this documentation and on our [Community Discord](https://discord.gg/NgCnkHbsGp). Posting your questions, suggestions, bug reports, or otherwise participating in community support will be rewarded with experience points!
{% endhint %}


# Container Registry

Now that you know how to use our platform, you need to containerize your game server. You will need a place to store your container images to be accessible when deploying your game servers.

That is why we created the Edgegap Container Registry. It is a privately managed container repository that works much like standard public container registries, but with the added benefit of increased security, vulnerability scans and other goodies! With high availability and dashboard integration, you will spend less time learning new tools, and your servers will always be ready to go.

### Getting your credentials

To push images, you will first need to authenticate to our registry, and for that, you need credentials. Find the `Container Registry` tab in the `Service` section to request your credentials in the sidebar. From there, you can request access to our registry.

<figure><img src="https://3027732442-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2Fgit-blob-323308a355e5937e7bcd4dfdbf75cd0d4517ac86%2Frequest-access.png?alt=media" alt=""><figcaption></figcaption></figure>

In the box at the bottom of the screen, you will find everything you need to connect to the registry and push your container images.

<figure><img src="https://3027732442-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2Fgit-blob-ed6f68d538b2ea4944d14989c82351b09dc3914c%2Fregistry-project-info.png?alt=media" alt=""><figcaption></figcaption></figure>

| Field    | Description                                                                                    |
| -------- | ---------------------------------------------------------------------------------------------- |
| URL      | The URL of our container registry. You will need to use it when logging in and pushing images. |
| Project  | The name of your assigned project. You must include it in your image repository path.          |
| Username | The username to use when logging in to the registry.                                           |
| Token    | The password to use when logging in to the registry.                                           |

You can now login to the repository using your tool of choice:

#### Linux

```bash
# enter your password when prompted
docker login -u '<REPOSITORY_USERNAME>' registry.edgegap.com
```

#### cmd

```bash
# enter your password when prompted
docker login -u <REPOSITORY_USERNAME> registry.edgegap.com
```

#### Powershell

```bash
# enter your password when prompted
docker login -u '<REPOSITORY_USERNAME>' registry.edgegap.com
```

### Docker login Warning

```
WARNING! Your password will be stored unencrypted in /home/user/.docker/config.json.
```

You can configure the credentials store by following [this setup](https://docs.docker.com/engine/reference/commandline/login/#credentials-store). Remember that this warning is normal behaviour from Docker.

It's **important** that you understand that your robot username, and the token for your private repository are encoded in base64 in your machine at this path `$HOME/.docker/config.json`. Anybody who has access to this file can easily decrypt your robot account token with a base64 decoder. Ensure that the environment `docker login registry.edgegap.com` you use is safe and that the access permissions to this file are restricted.

To remove your credentials from this file, you can easily use `docker logout registry.edgegap.com` each time you push and pull your private images.

### Pushing an image to the registry

If you need help containerizing your project, see [our documentation on this topic](https://docs.edgegap.com/docs/tools-and-integrations/container/docker) to get you started.

First, you need to add a tag to your image corresponding to the registry. Then, since you are logged in to the registry, all you need to do is push your image to the URL and project found on the page:

```bash
docker image tag <IMAGE_NAME>:<TAG> registry.edgegap.com/<PROJECT_NAME>/<IMAGE_NAME>:<TAG>
docker push registry.edgegap.com/<PROJECT_NAME>/<IMAGE_NAME>:<TAG>
```

You may push as many images as your storage permits and separate them in different repositories as you see fit. However, you should read the "App templates" section before pushing too many images!

You will then find your repositories on the same page upon refreshing.

### Tagging the same build artifact multiple times (pushing an image duplicate)

If you happen to push the same build artifact twice, if the tag value is the same no change will be made.

If you happen to push the same build artifact twice, with two different tag values, no additional storage space will be consumed and our registry will simply create the new tag pointing to the same build artifact.

### Managing your images

You may see your repositories by going to the same page after you have pushed at least one image.

By clicking on one of those repositories, you can see the images it contains, grouped by artifact. If you tagged the same image with two different tags and pushed those to the registry, you will see them as the same artifact.

<figure><img src="https://3027732442-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2Fgit-blob-0a4a754f4b880aa351d7a77ff94cad5335a59831%2Fartifact-list.png?alt=media" alt=""><figcaption></figcaption></figure>

<figure><img src="https://3027732442-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2Fgit-blob-7afcf8e2f1ef701a0b2dc7aa8d54b56529f7c6eb%2Fartifact-list-2.png?alt=media" alt=""><figcaption></figcaption></figure>

The images tagged `1.0.1` and `1.0.2` in the picture above have the same artifact. The image tagged `1.0.3`, however, has a different artifact.

{% hint style="warning" %}
If you delete an artifact, you will also delete its associated tags. The confirmation dialogue will list all the tags that this action would delete to ensure you do not accidentally delete needed resources.
{% endhint %}

### Delete build artifacts via API

If the dashboard UI is too slow for you, or you need an automated continuous integration pipeline that would delete your outdated build artifacts automatically to keep your registry usage within limits, consider using our Container Registry API. Our [Container Registry API](https://docs.edgegap.com/docs/api) allows listing all tags for a given app (image), as well as deleting individual tags. Since each image artifact (build) may have multiple tags associated at the same time (such as `v1.1.0`, `dev`, `latest`, or more), you will need to delete all tags associated with a specific artifact in order to free up space in your Edgegap Container Registry.

### Requesting more storage

When your request for access to the registry has been approved, you will be given a certain amount of storage space in the registry.

You may request additional space by clicking on the "Request more storage" button next to the space usage indicator.

<figure><img src="https://3027732442-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2Fgit-blob-81bdfd593994140a1a5a5f915b5e1242b32ef8fb%2Frequest-more-storage.png?alt=media" alt=""><figcaption></figcaption></figure>

When a staff member has approved your request, you will have more space to push your images.

### Next steps

Learn how to containerize your application with our guide: [Getting started with Docker](https://docs.edgegap.com/docs/tools-and-integrations/container/docker).


# Managed Clusters

Learn about Managed Clusters and get started quickly with custom backend solutions.

## ✔️ Introduction

Managed Clusters make hosting self-managed game services and game backend easy and fast. You prepare the service image and we provide a high-availability, resilient cloud environment to run them:

* player authentication,
* data storage - accounts, progression, inventory, rewards, ...
* social services - chat, clans, leaderboards, tournaments, ...
* custom matchmaking - using [#advanced-matchmaker](#advanced-matchmaker "mention"), [#nakama-by-heroic-labs](#nakama-by-heroic-labs "mention"), ...
* serverless compute - managed [functions as a service](https://github.com/openfaas/faas) (alt. cloudscript, lambda), ...

{% hint style="success" %}
See [matchmaking](https://docs.edgegap.com/learn/matchmaking "mention") and [server-browser](https://docs.edgegap.com/learn/server-browser "mention") to get started with game client integration.
{% endhint %}

Private clusters ensure your services have **dedicated compute to serve your players 24/7**.

We currently offer [3 private cluster tiers](https://edgegap.com/resources/pricing#managed-infrastructure) to cater to everybody’s needs:

<table><thead><tr><th width="160">Tier</th><th align="right">Hobbyist Tier</th><th align="right">Studio Tier</th><th align="right">Enterprise Tier</th></tr></thead><tbody><tr><td>Best Suited For</td><td align="right">enthusiasts,<br>solo developers</td><td align="right">commercial releases</td><td align="right">high-traffic launches</td></tr><tr><td>Resources</td><td align="right">1 vCPU + 2GB RAM</td><td align="right">6 vCPU + 12GB RAM</td><td align="right">18 vCPU + 48GB RAM</td></tr><tr><td>Redundancy</td><td align="right">1x virtual node</td><td align="right">3x virtual nodes</td><td align="right">3x virtual nodes</td></tr><tr><td>Rate Limit (req/s)</td><td align="right">200</td><td align="right">750</td><td align="right">2,000</td></tr><tr><td>Price, hourly</td><td align="right">$0.0312</td><td align="right"> $0.146</td><td align="right">$0.548</td></tr><tr><td><strong>Price, 30 days</strong><br>(nonstop usage)</td><td align="right"><strong>$22.464</strong></td><td align="right"><strong>$105.12</strong></td><td align="right"><strong>$394.56</strong></td></tr></tbody></table>

{% hint style="info" %}
Our cluster machines use AMD/Intel CPUs with clock speed 2.4 - 3.2 GHz. Reach out on [Community Discord](https://discord.gg/MmJf8fWjnt) to coordinate load tests and to ensure your server has sufficient resources available.
{% endhint %}

## 🛠️ Developer Tools

If you see an opportunity for improvement, please let us know in our [Community Discord](https://discord.gg/NgCnkHbsGp).

We hope you will enjoy a smooth experience. 🚀

### Docker

To help make your server reliable, we use [Docker](https://www.docker.com/) - virtualization software to ensuring that all of your server code dependencies down to the operating system level are going to be always exactly the same, no matter how or where the server is launched.

{% hint style="info" %}
We recommend watching ["Never install locally" (video)](https://www.youtube.com/watch?v=J0NuOlA2xDc\&ab_channel=Coderized). **You DON'T need to use Dockerhub with Docker**.  Docker ≠ Dockerhub. Think of Docker as a programming engine and Dockerhub as it’s App Store.
{% endhint %}

### Kubernetes (K8s)

[Kubernetes](https://kubernetes.io/docs/concepts/overview/), also known as K8s, is an open source system for automating deployment, scaling, and management of containerized applications (Docker Images). It groups containers that make up an application into logical units for easy management and discovery.

Edgegap Managed Clusters provide a Kubernetes API for administration purposes.

### K8s Lens

With over 1 million users, [K8s Lens](https://k8slens.dev/) is the most popular Kubernetes IDE in the world. Connect to clusters, explore, gain insights, learn and take an action when needed. Lens provides all the information from your workloads and resources in real-time, always in the right context.

Edgegap Cluster Kubernetes API can be used through Lens or other Kubernetes IDEs.

### Helm Package Manager

[Helm](https://helm.sh/) is the best way to find, share, and use software built for Kubernetes. Helm helps you manage Kubernetes applications - Helm Charts help you define, install, and upgrade even the most complex Kubernetes application. Charts are easy to create, version, share, and publish - so start using Helm and stop the copy-and-paste.

[Installing Helm CLI](https://helm.sh/docs/intro/install/) provides developers with a simple interface to manage their cluster packages.

## 🚀 Getting Started

☑️ [Registered for your free Edgegap account](https://app.edgegap.com/auth/register) and upgrade to pay as you go tier to unlock Clusters.

☑️ Navigate to [Managed Clusters](https://app.edgegap.com/cluster-management/clusters/list) page.

☑️ Click on **Create Cluster** first, then input:

* **Label** for your cluster to find it later easily,
* **Cluster Size -** see [#introduction](#introduction "mention").

{% hint style="danger" %}
**We strongly recommend creating separate clusters for your dev & production environments.**
{% endhint %}

☑️ Review estimated cost and click **Create Cluster** to start your new cluster.

☑️ Once the cluster is ready, **click Kubeconfig to download your configuration and credentials** for connecting and administrating your new cluster.

☑️ [Move your kubeconfig file](https://kubernetes.io/docs/concepts/configuration/organize-cluster-access-kubeconfig/) for `kubectl` to find it.

☑️ Lens users: [import your kubeconfig file](https://docs.k8slens.dev/getting-started/add-cluster/#specify-kubeconfig-files).

☑️ Test your cluster connection with command `kubectl get nodes` :

```bash
kubectl get nodes
NAME                            STATUS   ROLES    AGE    VERSION
lke334087-533013-294dcfe70000   Ready    <none>   10m   v1.31.0
lke334087-533013-4e69edc10000   Ready    <none>   10m   v1.31.0
lke334087-533013-50bf39880000   Ready    <none>   10m   v1.31.0
```

🙌 Congratulations, you’ve completed Managed Cluster setup! You may now install your services.

## 📦 Nakama by Heroic Labs

{% hint style="success" %}
See [#getting-started](#getting-started "mention") before setting up your services on Managed Clusters.
{% endhint %}

{% hint style="info" %}
Integrate Edgegap with [Nakama plugin](https://github.com/edgegap/nakama-edgegap) + [Unity plugin](https://github.com/edgegap/edgegap-server-nakama-plugin-unity)! [Reach out for other platforms/features.](https://discord.gg/NgCnkHbsGp)
{% endhint %}

Follow these steps to host your own [Nakama Game Backend](https://heroiclabs.com/docs/nakama/getting-started/) on Managed Clusters:

☑️ Install a **Certificate Manager** to support usage of HTTPS requests from game clients:

```bash
helm repo add jetstack https://charts.jetstack.io --force-update;
helm upgrade --install cert-manager jetstack/cert-manager \
  --namespace cert-manager --create-namespace \
  --version v1.16.1 --set crds.enabled=true;
```

☑️ Lens: verify installation in Services / Network section, `cert-manager` should be running.

☑️ Write a **Cluster Issuer** file, remember to replace `<YOUR_EMAIL>` below:

<pre class="language-yaml"><code class="lang-yaml">apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: letsencrypt-staging
  namespace: cert-manager
spec:
  acme:
    server: https://acme-staging-v02.api.letsencrypt.org/directory
    email: <a data-footnote-ref href="#user-content-fn-1">&#x3C;YOUR_EMAIL></a>
    privateKeySecretRef:
      name: <a data-footnote-ref href="#user-content-fn-2">letsencrypt-staging</a>
    solvers:
    - http01:
        ingress:
          class: nginx
          
</code></pre>

{% hint style="danger" %}
Use `letsencrypt-prod` for your production cluster `privateKeySecretRef`.
{% endhint %}

☑️ Create a **Cluster Issuer** in command line:

```bash
kubectl create -f <FILE_PATH>/issuer.yaml
```

☑️ Lens: verify installation in Custom Resources section / `cert-manager.io` - cluster issuer created.

☑️ Install the **nginx Ingress** for receiving client requests and passing them to services in cluster:

```
helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
helm upgrade --install ingress-nginx ingress-nginx/ingress-nginx \
  --namespace ingress-nginx --create-namespace
```

☑️ Lens: verify installation in Services / Network section, `nginx` should be running.

☑️ Create a **DNS record type A** in your DNS provider (e.g. [Cloudflare](https://developers.cloudflare.com/dns/get-started/)), note the URL for later. Your **external IP for the DNS record** can be found in Lens under Services / `ingress-nginx-controller` .

☑️ Verify your DNS is set up correctly by performing a lookup [using DNSchecker](https://dnschecker.org/ns-lookup.php).

☑️ Create file named `values.yaml` with contents (use your own values):

<pre class="language-yaml"><code class="lang-yaml">isProductionEnvironment: true

# The external hostname for the Nakama server - DNS record from last step
externalHostName: <a data-footnote-ref href="#user-content-fn-3">&#x3C;DNS_A_RECORD_URL></a>

nakama:
  # The version of Nakama to deploy.
  # See https://hub.docker.com/r/heroiclabs/nakama/tags for available versions.
  version: 3.26.0
  # Username and password for the Nakama console
  username: <a data-footnote-ref href="#user-content-fn-4">&#x3C;USERNAME></a>
  password: <a data-footnote-ref href="#user-content-fn-5">&#x3C;PASSWORD></a>
</code></pre>

{% hint style="danger" %}
**Replace \<VALUES> above with your own values** in the file above.
{% endhint %}

☑️ Deploy Nakama helm chart:

```bash
helm upgrade --install \
  --namespace nakama --create-namespace -f <FILE_PATH>/values.yaml \
  --version 1.0.0 <RELEASE_NAME> oci://registry-1.docker.io/edgegap/heroiclabs-nakama
```

☑️ Lens: verify installation in Workloads / Deployments section, `nakama` should be running.

✅ **Connect to your Nakama Console** with URL and credentials from `values.yaml` file.

🙌 Congratulations, you’ve completed self-hosted Nakama Game Backend setup!

### Service Updates

Follow these steps to update your service hosted in the Managed Cluster:

☑️ Update your `value.yaml` file with new files.

☑️ Update your helm chart using this command:

```bash
helm upgrade --reuse-values \
  --namespace nakama -f <FILE_PATH>/values.yaml \
  --version 1.0.0 <RELEASE_NAME> oci://registry-1.docker.io/edgegap/heroiclabs-nakama
```

☑️ Reload your changes by closing the updated pods, causing the new helm chart to be used after we automatically restart the pods.

{% hint style="warning" %}
This **update will cause a short downtime** while the pods restart.
{% endhint %}

🙌 Congratulations, you’ve completed Nakama Cluster update!

## 👷 Advanced Matchmaker

{% hint style="success" %}
See [#getting-started](#getting-started "mention") before setting up your services on Managed Clusters.
{% endhint %}

Follow these steps to host your [OpenMatch](https://open-match.dev/site/) on a Managed Cluster.

☑️ Install a **Certificate Manager** to support usage of HTTPS requests from game clients:

```bash
helm repo add jetstack https://charts.jetstack.io --force-update;
helm upgrade --install cert-manager jetstack/cert-manager \
  --namespace cert-manager --create-namespace \
  --version v1.16.1 --set crds.enabled=true;
```

☑️ Lens: verify installation in Services / Network section, `cert-manager` should be running.

☑️ Write a **Cluster Issuer** file, remember to replace `<YOUR_EMAIL>` below:

<pre class="language-yaml"><code class="lang-yaml">apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: letsencrypt-staging
  namespace: cert-manager
spec:
  acme:
    server: https://acme-staging-v02.api.letsencrypt.org/directory
    email: <a data-footnote-ref href="#user-content-fn-1">&#x3C;YOUR_EMAIL></a>
    privateKeySecretRef:
      name: <a data-footnote-ref href="#user-content-fn-2">letsencrypt-staging</a>
    solvers:
    - http01:
        ingress:
          class: nginx
          
</code></pre>

{% hint style="danger" %}
Use `letsencrypt-prod` for your production cluster `privateKeySecretRef`.
{% endhint %}

☑️ Create a **Cluster Issuer** in command line:

```bash
kubectl create -f <FILE_PATH>/issuer.yaml
```

☑️ Lens: verify installation in Custom Resources section / `cert-manager.io` - cluster issuer created.

☑️ Install the **nginx Ingress** for receiving client requests and passing them to services in cluster:

```
helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
helm upgrade --install ingress-nginx ingress-nginx/ingress-nginx \
  --namespace ingress-nginx --create-namespace
```

☑️ Lens: verify installation in Services / Network section, `nginx` should be running.

☑️ Create a DNS record type A in your DNS provider (e.g. [Cloudflare](https://developers.cloudflare.com/dns/get-started/)), note the URL for later. Your **external IP for the DNS record** can be found in Lens under Services / `ingress-nginx-controller` .

☑️ Verify your DNS is set up correctly by performing a lookup [using DNSchecker](https://dnschecker.org/ns-lookup.php).

☑️ Create file named `values.yaml` with contents (use your own values):

```yaml
isProductionEnvironment: false

director:
  credential:
    registry: <YOUR_DIRECTOR_REGISTRY>
    username: <YOUR_DIRECTOR_REGISTRY_USERNAME>
    password: <YOUR_DIRECTOR_REGISTRY_PASSWORD>
  image: <DIRECTOR_IMAGE>
  env: {
    "KEY": "VALUE"
  }

mmf:
  credential:
    registry: <MATCHMAKER_FUNCTION_REGISTRY>
    username: <MATCHMAKER_FUNCTION_REGISTRY_USERNAME>
    password: <MATCHMAKER_FUNCTION_REGISTRY_PASSWORD>
  image: <MATCHMAKER_FUNCTION_IMAGE>
  env: {
    "KEY": "VALUE"
  }

frontend:
  credential:
    registry: <FRONTEND_REGISTRY>
    username: <FRONTEND_REGISTRY_USERNAME>
    password: <FRONTEND_REGISTRY_PASSWORD>
  externalHostName: <YOUR_CLOUDFLARE_HOST_NAME> # e.g. exemple.test.com
  image: <FRONTEND_IMAGE>
  env: {
    "KEY": "VALUE"
  }

# Global configurations that are visible to all subcharts
global:
  kubernetes:
    resources:
      requests:
        memory: 100Mi
        cpu: 100m
      limits:
        memory: 100Mi
        cpu: 100m
```

{% hint style="danger" %}
**Replace \<VALUES> above with your own values** in the file above.
{% endhint %}

☑️ Add **Edgegap repository** to your list of repositories:

```bash
helm repo add edgegap-public https://registry.edgegap.com/chartrepo/edgegap-public
```

☑️ Deploy advanced matchmaker helm chart:

```bash
helm upgrade --install \
  --namespace matchmaker --create-namespace -f <FILE_PATH>/values.yaml \
  --version 1.0.1 <RELEASE_NAME> edgegap-public/open-match-edgegap
```

🙌 Congratulations, you’ve completed Advanced Matchmaker setup!

### Service Updates

Follow these steps to update your service hosted in the Managed Cluster:

☑️ Update your `value.yaml` file with new files.

☑️ Update your helm chart using this command:

```bash
helm upgrade --reuse-values \
  --namespace matchmaker -f <FILE_PATH>/values.yaml \
  --version 1.0.1 <RELEASE_NAME> edgegap-public/open-match-edgegap
```

☑️ Reload your changes by closing the updated pods (director, mmf, frontend), causing the new helm chart to be used after we automatically restart the pods.

{% hint style="warning" %}
This **update will cause a short downtime** while the pods restart.
{% endhint %}

🙌 Congratulations, you’ve completed Advanced Matchmaker update!

### Continuous Deployment

Automate updating your services by adding this shell script to your deployment pipeline:

```bash
#!/bin/bash

RELEASE_NAME="<RELEASE_NAME>"
NAMESPACE="matchmaker"  # Change this if you changed the namespace.

helm upgrade --reuse-values -f <FILE_PATH>/value.yaml --namespace $NAMESPACE --version 1.0.1 $RELEASE_NAME edgegap-public/open-match-edgegap

echo "Installing redis-tools"
apt-get update
apt-get install -y redis-tools

DIRECTOR_DEPLOYMENT_NAME="$RELEASE_NAME-director"
MMF_DEPLOYMENT_NAME="$RELEASE_NAME-mmf"
CUSTOM_FRONTEND_DEPLOYMENT_NAME="$RELEASE_NAME-custom-frontend"
REDIS_HOST="$RELEASE_NAME-redis-master"

declare -A replicas

# For each deployment (director, mmf, custom-frontend) stop the pods
for deployment in $DIRECTOR_DEPLOYMENT_NAME $MMF_DEPLOYMENT_NAME $CUSTOM_FRONTEND_DEPLOYMENT_NAME
do
  echo "Stopping pods for deployment: $deployment"
  replicas[$deployment]=$(kubectl get deployment $deployment -o=jsonpath='{.spec.replicas}' --namespace $NAMESPACE)
  kubectl scale deployment/$deployment --replicas=0 --namespace $NAMESPACE
done

# Wait until the pods are terminated
for deployment in $DIRECTOR_DEPLOYMENT_NAME $MMF_DEPLOYMENT_NAME $CUSTOM_FRONTEND_DEPLOYMENT_NAME
do

  echo "Waiting for pods to be terminated for deployment: $deployment"
  kubectl wait --for=delete pod -l app=$deployment --timeout=60s --namespace $NAMESPACE

  # Check if the wait command was successful. If not, exit the script
  if [ $? -ne 0 ]; then
    echo "Failed to wait for pods to be terminated for deployment: $deployment"
    exit 1
  fi
done

# Clean up redis database
echo "Cleaning up redis database"
redis-cli -h $REDIS_HOST flushall

# For each deployment (director, mmf, custom-frontend) rescale the pods to their original count
for deployment in $DIRECTOR_DEPLOYMENT_NAME $MMF_DEPLOYMENT_NAME $CUSTOM_FRONTEND_DEPLOYMENT_NAME
do
  echo "Rescaling pods to ${replicas[$deployment]} for deployment: $deployment"
  kubectl scale deployment/$deployment --replicas=${replicas[$deployment]} --namespace $NAMESPACE
done
```

{% hint style="warning" %}
This **update will cause a short downtime** while the pods restart.
{% endhint %}

### Letsencrypt Certificate Validation (C#)

For some clients, the recommended Letsencrypt certificate validation may fail with error:

```bash
Curl error 60: Cert verify failed. Certificate has expired. UnityTls error code: 7
```

{% hint style="success" %}
Updating your operating system may resolve issues with outdated root certificate authority.
{% endhint %}

As a last resort, game clients may implement a custom certificate handler function:

````csharp
```csharp
public class CustomCertificateHandler : CertificateHandler
{
  private readonly string EXPECTED_CERT = "-----BEGIN CERTIFICATE-----<key>-----END CERTIFICATE-----\r\n";
  protected override bool ValidateCertificate(byte[] certificateData)
  {
    X509Certificate2 certificate = new X509Certificate2(certificateData);
    X509Certificate2 expectedCert = new X509Certificate2(Encoding.ASCII.GetBytes(EXPECTED_CERT));

    using (SHA256 sha256 = SHA256.Create())
    {
      Debug.Log("certificate.Thumbprint: " + certificate.Thumbprint);
      Debug.Log("expectedCert.Thumbprint: " + expectedCert.Thumbprint);

      return certificate.Thumbprint == expectedCert.Thumbprint;
    }
  }
}
```
````

Usage:

```csharp
UnityWebRequest request = UnityWebRequest.Get(...);
request.certificateHandler = new BypassCertificateHandler();
request.SendWebRequest();
request.certificateHandler.Dispose();
```

We recommend storing the `EXPECTED_CERT` value in your own file storage, and retrieving it on runtime, so you can update it without releasing a game client update.

## 🟢 Operations and Observability

### Cluster Tier Changes

Prepare for success and optimize after launch, so you don’t block your players on release day.

{% hint style="warning" %}
&#x20;Changing cluster size requires stopping your cluster. See [blue/green deployment](https://circleci.com/blog/canary-vs-blue-green-downtime/) for zero downtime updates.
{% endhint %}

### Support and Future Updates

**Your success is our priority.** If you'd like to send custom requests, ask for missing critical features , or express any thoughts, [please reach out in our Community Discord](https://discord.gg/MmJf8fWjnt).

[^1]: replace with your email

[^2]: use letsencrypt-prod for production

[^3]: DNS record from last step

[^4]: choose your own admin username

[^5]: choose a secure password for admin


# Relays (P2P)

{% hint style="warning" %}
This section of the documentation is a work in progress and is subject to change.

Don't hesitate to ask questions or make requests via our [Discord](https://discord.com/invite/NgCnkHbsGp) channel. We are here to assist you!
{% endhint %}

The Edgegap Distributed Relays benefit from our distributed cloud network, which includes hundreds of locations. This ensures that your players are always playing on the best available relay, thanks to our patented real-time telemetry decision technology.

Implementing relays can indeed be a complex task, which is why we have developed a solution that takes care of the technical aspects so you don't have to. Our solution simplifies the process of setting up and managing relays, allowing you to focus on integrating them seamlessly into your game or application without the need for extensive technical expertise.

***

### Why Do I Need a Relay in a P2P Game

A Relay server can be a valuable tool for P2P game developers. In P2P games, players connect directly to each other without the need for a central server. However, this approach can present some challenges, such as:

#### **Firewall restrictions**

Firewalls can block P2P connections between devices, making it difficult for players to connect to each other.

#### **Strict NAT**

A Strict NAT can have a significant impact on a player's ability to participate in peer-to-peer (P2P) games. P2P games rely on direct connections between players' devices to facilitate communication and gameplay, but a Strict NAT can limit or even block these connections. This can result in increased latency, dropped connections, and difficulty joining or hosting games.

<figure><img src="https://3027732442-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2Fgit-blob-1ff4b2b8740e5c4f621e070e7524b20cb26a52b4%2FTraditional_P2P.png?alt=media" alt=""><figcaption></figcaption></figure>

A Relay server can help overcome these challenges by acting as an intermediary between players. When a player wants to connect to another player, their connection is first routed through the Relay server. This allows the Relay server to handle NAT traversal and firewall restrictions, making it easier for players to connect to each other.

Relay servers can also help improve the overall performance of P2P games by reducing the load on player devices. By handling some of the network traffic between players, the Relay server can help reduce latency and improve the overall gameplay experience.

In summary, a Relay server can be a valuable tool for P2P game developers, helping to overcome NAT traversal and firewall restrictions, and improving the overall performance of the game.

***

### Server vs Client in P2P

In a peer-to-peer (P2P) setup for a multiplayer game, one player must act as the game server since there is no dedicated server to manage the game for all players. This player, referred to as the "server," is responsible for managing the game world and synchronizing all information between players. The remaining players (Client" alt="">

will connect to the server directly.

***

### Getting Started

#### **Implement Some Sort of Lobby/Matchmaker**

You will need to implement some form of lobby or matchmaker to create relay sessions for your players. Don't worry, initially you won't need a fully functional matchmaker, but rather something that can automate your API requests without exposing your token in the game client. Consider using [#nakama-by-heroic-labs](https://docs.edgegap.com/advanced-features/managed-clusters#nakama-by-heroic-labs "mention") on Edgegap clusters.

#### **Integration with the Edgegap API**

Once you have completed the previous step, you will need to primarily perform two straightforward actions using the Edgegap API: creating relay sessions and deleting relay sessions. Your lobby/matchmaker should be responsible for implementing these actions, which will authorize or unauthorize your players from accessing a relay. [More information in this section](https://docs.edgegap.com/learn/distributed-relay/relay-edgegap-api).

#### **Integration with Existing Transport Layer**

After authorizing your players on a relay, you will still need to implement the communication between your game client and the relay, which is known as the transport layer.

To make your life easier, we are working to do many implementations for different netcode, language and framework. If you want to integrate one of our actual implementation, simply follow the tutorial corresponding your stack.

* [Unity with Mirror Netcode](https://docs.edgegap.com/docs/sample-projects/unity-netcodes/mirror-on-edgegap)
* Unreal Networking - Coming soon
* [Unity Netcode for GameObjects](https://docs.edgegap.com/docs/sample-projects/unity-netcodes/unity-netcode-on-edgegap)
* [Fishnet Networking](https://docs.edgegap.com/docs/sample-projects/unity-netcodes/fishnet-on-edgegap)

#### **(Alternatively) Implementing Your Own Transport Layer**

If you are interested in implementing your own transport layer for a specific netcode, you can find detailed information and guidance by following this guide:

[Relay Implementation Manual](https://github.com/edgegap/distributed-relay-examples#relay-implementation-manual)

If you have any question on the implementation or want to know the roadmap on our current integration feel free to reach us!


# Game Integration

### Why do I need a Matchmaker and/or Lobby?

A Lobby Service ([#nakama-by-heroic-labs](https://docs.edgegap.com/advanced-features/managed-clusters#nakama-by-heroic-labs "mention")) system plays a crucial role in online multiplayer games for various technical reasons.

**Player management**

A lobby or matchmaker system helps manage players by grouping them into appropriate matches based on various criteria such as skill level, geographical location, or game preferences. This ensures a balanced and enjoyable gaming experience for all players involved.

**Backend**

You do not want your player to communicate directly with your backend and you want to offer a centralized point for them to access. Imagine you have an API token that start a VM in a certain provider, you do not want the Token hardcoded in the Game Client, accessible to any players!

**Security**

Using a centralized lobby or matchmaker system helps maintain control over the game's security. By filtering and validating player connections, a matchmaker can prevent unauthorized access, protect user data, and mitigate potential cheating or hacking attempts.

**Game session management**

A lobby or matchmaker system manages game sessions by creating, updating, and terminating them as needed. This ensures that players can join or leave games seamlessly, and the game instances can be efficiently managed by the system.

<figure><img src="https://3027732442-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2Fgit-blob-b5db2255168c7ceca08fdbeca00c51f7e967a045%2FLobby.png?alt=media" alt=""><figcaption></figcaption></figure>

### You Don't Need One Right Away! (Development mode)

During the development phase, you might not need a fully-fledged lobby or matchmaker system for several technical reasons:

**Simplified testing environment**

In the initial stages of development, you might focus on implementing and testing the core game mechanics and networking features. By avoiding the complexity of a lobby or matchmaker system, you can more easily test and debug your game with a smaller group of players, often within your development team.

**Faster iteration**

Without a lobby or matchmaker, you can make quick changes to your game code and test new features or fixes without worrying about the impact on the matchmaking process. This allows for a more agile development approach, enabling your team to iterate and refine the game mechanics more rapidly.

**Resource allocation**

Developing a full-scale lobby or matchmaker system requires considerable time and resources. By delaying the implementation of these components, you can allocate your resources more efficiently, focusing on the core gameplay and networking features first.

**Scalability concerns**

In the early stages of development, you likely won't have a large number of players to manage. As a result, a basic system for connecting players or even manual connections for testing purposes may be sufficient. However, as your game grows and attracts more players, a lobby or matchmaker system will become increasingly necessary to manage player connections and ensure a smooth gameplay experience.

It's crucial to design your game architecture to accommodate a lobby or matchmaker system in the future. This forward-thinking approach will make it easier to integrate these components when you're ready to test your game with a larger group of players, ensuring a smoother transition and a more polished final product.

### Interacting with Edgegap’s API

Edgegap offer a simple API to interact with the Relay Sessions to authorize your players to connect to the closest relay for low latency.

<figure><img src="https://3027732442-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2Fgit-blob-d9e302f8f6c3d299760dd8ad5416a5d47965cb1b%2FDistributed_Relay_P2P.png?alt=media" alt=""><figcaption></figcaption></figure>

To interact with the API, you'll need to provide an `Authorization Header Token` in your requests.

{% hint style="info" %}
You can acquire a token by registering for an account and generating a relay profile. [**Register here**](https://app.edgegap.com/auth/register)

Please note that you need a token exclusively designated for the relays. If you already have a standard API token, it will not work.
{% endhint %}

This is accessible from the sidebar on the dashboard.

<figure><img src="https://3027732442-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2Fgit-blob-52bbb7251013ce023d5ceb59e7a078c1755312cb%2Fcreatetoken.png?alt=media" alt=""><figcaption></figcaption></figure>

Once you have the token, include it in the request headers for all API calls. Don't forget to prefix your API key with `token`.

{% hint style="success" %}
If you are not familiar with working with an API, you can refer to [this section](#interacting-with-api-curl-or-postman) to assist you in getting started.
{% endhint %}

### Creating a Relay Session

To use Distributed Relay, you need to create a relay session. This is done by sending a `POST` request to the `/v1/relays/sessions` endpoint with a JSON payload. Sessions can be created manually, with a matchmaker, with a lobby, or with your own custom service.

This will dynamically select the best available relay for your players in real-time and create authorization for accessing the relay. However, we recommend pre-filtering your matchmaking to group players within the same region to avoid extreme distances between them.

{% hint style="info" %}
This step will not directly connect your players to the relay; you will need to handle that in a later stage of the process. This step only provides you with a relay to establish a connection with.
{% endhint %}

Example Request:

```bash
POST - /v1/relays/sessions
```

The payload should contain an array of user objects, where each object contains the IP address of a user. You can also include a `webhook_url`, which is the URL that will receive notifications related to the session.

Example Payload:

```json
{
  "users": [
    {
      "ip": "1.1.1.1"
    },
    {
      "ip": "2.2.2.2"
    }
  ],
  "webhook_url": "https://webhook.example.com/notify"
}
```

{% hint style="info" %}
Where `"users"` is an array of user objects containing the `"ip"` of each user in the session, and `"webhook_url"` is an optional URL to receive session updates.

After sending the `POST` request, you will receive a JSON response containing the `session_id`, which is needed to retrieve session information later.
{% endhint %}

Example Response:

```json
{
  "session_id": "3960c873aafd-S",
  "authorization_token": null,
  "status": "Initializing",
  "ready": false,
  "linked": false,
  "error": null,
  "session_users": [],
  "relay": null,
  "webhook_url": "https://webhook.example.com/notify"
}
```

### Getting Information about the Relay Session

To retrieve session information, send a `GET` request to the `/v1/relays/sessions/{session_id}` endpoint with the `session_id` obtained from the `POST` request.

Example Request:

```bash
GET - /v1/relays/sessions/3960c873aafd-S
```

The response will contain information about the session, including the session status, users information, and relay information.

The expected response will contain session information like this:

```json
{
  "session_id": "3960c873aafd-S",
  "authorization_token": 1031196689,
  "status": "Linked",
  "ready": true,
  "linked": true,
  "error": null,
  "session_users": [
    {
      "ip_address": "2.2.2.2",
      "latitude": 48.8602294921875,
      "longitude": 2.34106993675232,
      "authorization_token": 3499933322
    },
    {
      "ip_address": "1.1.1.1",
      "latitude": -37.7036018371582,
      "longitude": 145.180633544922,
      "authorization_token": 4261594560
    }
  ],
  "relay": {
    "ip": "178.79.131.238",
    "host": "cc84b011777b.pr.edgegap.net",
    "ports": {
      "server": {
        "port": 31527,
        "protocol": "UDP",
        "link": "cc84b011777b.pr.edgegap.net:31527"
      },
      "client": {
        "port": 32089,
        "protocol": "UDP",
        "link": "cc84b011777b.pr.edgegap.net:32089"
      }
    }
  },
  "webhook_url": "https://webhook.example.com/notify"
}
```

Getting the Authorization to the closest relay can take a small amount of time, so when the field `ready` is `true` you can extract JSON data to use it.

[More details here](https://docs.edgegap.com/docs/api)

{% hint style="success" %}
Alternatively, you can use the \`webhook\_url\` parameter when creating a relay session to be notified when the session has either succeeded in being assigned to a relay or has failed to do so.
{% endhint %}

### Terminating a Relay Session

When you decide to end your connection to the relay, you can easily terminate a relay session. You need to send a `DELETE` request to the following endpoint:

```bash
DELETE - /v1/relays/sessions/{session_id}
```

{% hint style="info" %}
Replace `{session_id}` with the actual session ID you want to terminate.
{% endhint %}

A response with status 204 no content means the session has been successfully deleted. The players will lose access to the relay and you will no longer be charged for that session.

{% hint style="warning" %}
It's important to terminate sessions properly in order to avoid leaving any unused resources allocated, which can impact performance and incur unnecessary costs.
{% endhint %}

***

### C# Example

This is a C# that your Lobby or Matchmaker could do to create a Relay Session and extract the Data that you would need to return to your game client.

{% hint style="info" %}
This example uses C# version > 7.0
{% endhint %}

```csharp
using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Net.Http.Json;
using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;

namespace LobbyNamespace
{
    public class EdgegapAPI
    {
        private readonly HttpClient _httpClient;

        public EdgegapAPI(string apiToken)
        {
            _httpClient = new HttpClient();
            _httpClient.DefaultRequestHeaders.Add("Authorization", $"Token {apiToken}");
        }

        public async Task<RelaySessionAuthorization> CreateRelaySession(List<string> ips)
        {
            var jsonBody = new
            {
                users = ips.ConvertAll(ip => new { ip })
            };

            var postResponse = await _httpClient.PostAsJsonAsync("https://api.edgegap.com/v1/relays/sessions", jsonBody);
            var postJsonData = await postResponse.Content.ReadFromJsonAsync<Dictionary<string, object>>();

            if (!postJsonData.ContainsKey("session_id"))
            {
                throw new Exception("Failed to create relay session");
            }

            var sessionId = postJsonData["session_id"].ToString();

            var retries = 5;
            while (retries > 0)
            {
                var getResponse = await _httpClient.GetAsync($"https://api.edgegap.com/v1/relays/sessions/{sessionId}");
                var getJsonData = await getResponse.Content.ReadFromJsonAsync<Dictionary<string, object>>();
                var ready = (JsonElement)getJsonData["ready"];

                if (ready.ValueKind == JsonValueKind.True)
                {
                    var usersData = (JsonElement)getJsonData["session_users"];
                    var userAuthorizationTokens = new Dictionary<string, UInt32>();
                    foreach (var user in usersData.EnumerateArray())
                    {
                        var ipAddress = user.GetProperty("ip_address").GetString();
                        var userAuthorizationToken = user.GetProperty("authorization_token").GetUInt32();
                        userAuthorizationTokens[ipAddress] = userAuthorizationToken;
                    }

                    var relayData = (JsonElement)getJsonData["relay"];
                    var relayAddress = relayData.GetProperty("host").GetString();
                    var relayServerPort = relayData.GetProperty("ports").GetProperty("server").GetProperty("port").GetInt32();
                    var relayClientPort = relayData.GetProperty("ports").GetProperty("client").GetProperty("port").GetInt32();

                    return new RelaySessionAuthorization
                    {
                        SessionAuthorizationToken = sessionId,
                        UserAuthorizationTokens = userAuthorizationTokens,
                        RelayAddress = relayAddress,
                        RelayServerPort = relayServerPort,
                        RelayClientPort = relayClientPort
                    };
                }

                retries--;
                await Task.Delay(2000); // wait for 2 second before retrying
            }

            throw new Exception("Failed to get a ready relay session");
        }
    }

    public class RelaySessionAuthorization
    {
        public string? SessionAuthorizationToken { get; set; }
        public Dictionary<string, UInt32>? UserAuthorizationTokens { get; set; }
        public string? RelayAddress { get; set; }
        public int RelayServerPort { get; set; }
        public int RelayClientPort { get; set; }
    }
}
```

You will need to return this information to the corresponding Player.

The Player acting as the Server will need the `RelayServerPort` and all the other will need the `RelayClientPort`

```csharp
using System.Text.Json;
using LobbyNamespace;

class Program
{
    static async Task Main(string[] args)
    {
        // Replace YOUR_API_TOKEN with your actual API token
        var apiToken = "YOUR_API_TOKEN";

        // 1.1.1.1 is your player acting as a server
        // 2.2.2.2 is your player acting as a client
        var ips = new List<string> { "1.1.1.1", "2.2.2.2" };

        var edgegapAPI = new EdgegapAPI(apiToken);
        var relaySessionAuthorization = await edgegapAPI.CreateRelaySession(ips);

        // Generate JSON body for server (1.1.1.1)
        var serverJsonBody = new
        {
            relay_address = relaySessionAuthorization.RelayAddress,
            port = relaySessionAuthorization.RelayServerPort,
            session_authorization_token = relaySessionAuthorization.SessionAuthorizationToken,
            user_authorization_token = relaySessionAuthorization.UserAuthorizationTokens["1.1.1.1"]
        };
        var serverJson = JsonSerializer.Serialize(serverJsonBody);
        Console.WriteLine($"JSON body for server (1.1.1.1):\n{serverJson}");

        // Generate JSON body for client (2.2.2.2)
        var clientJsonBody = new
        {
            relay_address = relaySessionAuthorization.RelayAddress,
            port = relaySessionAuthorization.RelayClientPort,
            session_authorization_token = relaySessionAuthorization.SessionAuthorizationToken,
            user_authorization_token = relaySessionAuthorization.UserAuthorizationTokens["2.2.2.2"]
        };
        var clientJson = JsonSerializer.Serialize(clientJsonBody);
        Console.WriteLine($"JSON body for client (2.2.2.2):\n{clientJson}");
    }
}
```

### Interacting with API (cURL or POSTMAN)

While developing your game, you'll need to interact with the API to create, manage, and delete relay sessions. You can use tools like cURL or POSTMAN to send HTTP requests to the API.

cURL is a command-line tool that allows you to make HTTP requests and interact with APIs directly from the terminal. POSTMAN is a popular graphical user interface (GUI) application that simplifies API testing by providing a user-friendly interface to create, send, and analyze HTTP requests.

Here's an example of how to create a relay session using cURL:

```bash
curl -X POST -H "Content-Type: application/json" -H "Authorization: Token API_TOKEN" -d '{
  "users": [
    {
      "ip": "1.1.1.1"
    },
    {
      "ip": "2.2.2.2"
    }
  ],
  "webhook_url": "https://webhook.example.com/notify"
}' "https://api.edgegap.com/v1/relays/sessions"
```

{% hint style="info" %}
Remember to replace `API_TOKEN` with your actual relay API Token.
{% endhint %}

The API will return you a response that contain data also. You will need to parse this response and extract the data you need.


# Transport Samples

After managing your players with either a matchmaker or lobbies then creating a relay session for them using the Edgegap API, you will need to connect your players to the relay once it is ready. Edgegap offers a specific transport to do just that, and this guide will show you how to implement it in your project. The transport is available [here on our GitHub](https://github.com/edgegap/distributed-relay-examples/tree/main).

With Unity, there currently is a version of the transport for the following netcodes:

* Mirror;
* Fishnet;
* Unity Netcode for GameObjects (NGO).

### Adding the transport

After downloading the right transport for your netcode, you need to include it in your project. First, add it to your project files in the following location:

* **Mirror** : add the `Edgegap` folder under `Assets/Mirror/Transports`;
* **Fishnet** : add the `Edgegap KcpTransport` folder under `Assets/Fishnet/Plugins`;
* **NGO** : add the `EdgegapRelay` and `kcp2k` folders under `Assets/Edgegap`.

Then, add the `EdgegapKcpTransport` script to your `NetworkManager` gameObject, make sure to drag that new component in the `Transport` property of the gameObject as well.

{% hint style="info" %}
If the option is present, make sure to disable `Relay GUI` in the `EdgegapKcpTransport` component of the `NetworkManager`. Otherwise, it will interfere when attempting to connect to the relay.

This option is namely present in the Mirror and NGO versions of the transport.
{% endhint %}

### Connecting to the relay

After matchmaking and creating the relay session, use the Edgegap API to determine when the relay is ready to accept connections. Once it is, use the data provided in the API response to set the values of the transport. You will need the following values in the appropriate fields:

* the relay's `IP` address is used as the `transport's relay address`;
* the `session authorization token` is used as the `transport's session ID`;
* the `user's authorization token` is used as the `transport's user ID`.

#### Server/Host Connection

* the relay's `server port` value is used as the `transport's relay port` .

#### Client Connection

* the relay's `client port` value is used as the `transport's relay port` .

{% hint style="info" %}
Each player will have their own unique authorization token, but the session token will remain the same for each player in the session.
{% endhint %}

### Using Mirror

```cs
// `data` is the deserialized API response converted to JSON
// `_EdgegapTransport` is the EdgegapKcpTransport

// Convert uint? to uint
uint sessionAuthorizationToken = data.authorization_token ?? 0;

//TODO find which session user matches the player, `i` being its place in the list
uint userAuthorizationToken = data.session_users?[i].authorization_token ?? 0;

_EdgegapTransport.ChangeValue(
    data.relay.ip,
    data.relay.ports.client.port,
    data.relay.ports.server.port,
    data.session_id,
    sessionAuthorizationToken,
    userAuthorizationToken
);

// then `NetworkManager.Singleton.StartHost();` if host player
// OR `NetworkManager.Singleton.StartClient();` if client 
```

### Using Fishnet

```cs
// `data` is the deserialized API response converted to JSON
// `_transport` is the EdgegapKcpTransport

// Convert uint? to uint
uint sessionAuthorizationToken = data.authorization_token ?? 0;

//TODO find which session user matches the player, `i` being its place in the list
uint userAuthorizationToken = data.session_users?[i].authorization_token ?? 0;

Relay relay = data.relay;
string address = relay.ip;
ushort serverPort = relay.ports.server.port;
ushort clientPort = relay.ports.client.port;

var relayData = new EdgegapRelayData(
    address,
    serverPort,
    clientPort,
    userAuthorizationToken,
    sessionAuthorizationToken
);
_transport.SetEdgegapRelayData(relayData);

// then `_transport.StartConnection(true);` if host
// OR `_transport.StartConnection(false);` if client
```

### Using NGO

```cs
// `data` is the deserialized API response converted to JSON
// `_EdgegapTransport` is the EdgegapKcpTransport

// Convert uint? to uint
uint sessionAuthorizationToken = data.authorization_token ?? 0;

//TODO find which session user matches the player, `i` being its place in the list
uint userAuthorizationToken = data.session_users?[i].authorization_token ?? 0;

_EdgegapTransport.relayAddress = data.relay.ip;
_EdgegapTransport.relayGameClientPort = data.relay.ports.client.port;
_EdgegapTransport.relayGameServerPort = data.relay.ports.server.port;
_EdgegapTransport.sessionId = sessionAuthorizationToken;
_EdgegapTransport.userId = userAuthorizationToken;

// then `NetworkManager.Singleton.StartHost();` if host player
// OR `NetworkManager.Singleton.StartClient();` if client 
```

### Using ApiResponse

```cs
public class ApiResponse
{
    public string session_id { get; set; }
    public uint? authorization_token { get; set; }
    public string status { get; set; }
    public bool ready { get; set; }
    public bool linked { get; set; }
    public object? error { get; set; }
    public List<SessionUser>? session_users { get; set; }
    public Relay relay { get; set; }
    public object? webhook_url { get; set; }
}
```

Once the values are properly set, use the transport to connect each player to the relay. After a short moment, you will be able to play the game!

### Sample projects

The following projects are simple examples that use the Edgegap relay transport.

For them to work properly, open a command prompt terminal and download the project via the `git clone [URL]` command. Open the project folder in the editor via the Unity Hub, then change the `RelayProfileToken` value in the `HelloWorldManager` component of the `NetworkManager` gameObject to your own relay profile token.

* [Mirror sample](https://github.com/edgegap/unity-mirror-relay-sample)
* [Fishnet sample](https://github.com/edgegap/unity-fishnet-relay-sample)
* [NGO sample](https://github.com/edgegap/unity-ngo-relay-sample)

{% hint style="info" %}
Use your custom [Relay Profile token](https://app.edgegap.com/relay-management/dashboard) in `HelloWorldManager.cs` or `EdgegapRelayService.cs`.
{% endhint %}


# API Reference

Get access to management functions for your Edgegap resources using HTTP requests.

<a href="https://raw.githubusercontent.com/edgegap/openapi-specification/refs/heads/main/edgegap-v2-openapi.yaml" class="button primary" data-icon="square-down">Download openapi \[v2]</a> <a href="https://api.edgegap.com/swagger.json" class="button secondary" data-icon="square-down">Download openapi \[v1]</a>&#x20;

{% hint style="info" %}
If you need help, [please reach out to us over Discord](https://discord.gg/MmJf8fWjnt). For live games support see our [ticketing system](https://edgegap.atlassian.net/servicedesk/customer/portal/3).
{% endhint %}

### Authentication Token

Generate (and view) your secret tokens for Edgegap API in [Dashboard - User Settings / Tokens](https://app.edgegap.com/user-settings?tab=tokens).

Add your secret token with each API request as an HTTP header (include the word `token`):

`Authorization: token xxxxxxxx-e458-4592-b607-c2c28afd8b62`

{% hint style="danger" %}
**Do not integrate Edgegap API endpoints in game client, as your API token provides unlimited access to your account. See** [Broken link](https://docs.edgegap.com/docs/broken-reference "mention") **for secure client-facing API endpoints and functions.**
{% endhint %}

{% hint style="success" %}
In case your secret tokens are compromised, delete them, and update organization member passwords.
{% endhint %}

### Response Pagination

In case a response would contain too many items, we return a subset of data with pagination info:

<pre class="language-json"><code class="lang-json">{
  "count": 100,
  "data": ["foo-0", "[...]", "bar-9"],
  "<a data-footnote-ref href="#user-content-fn-1">pagination</a>": {
    "number": 1,
    "next_page_number": 2,
    "previous_page_number": null
    "paginator": {
      "num_pages": 10
    },
    "has_next": true,
    "has_previous": false
  }
}
</code></pre>

For paginated response, use parameters `page` and `limit`  to retrieve more results:

* second page: `https://api.edgegap.com/v1/apps?`**`page=2`**
* more results: `https://api.edgegap.com/v1/apps?`**`limit=20`**
* combined: `https://api.edgegap.com/v1/apps?`**`page=2&limit=20`**

### Rate Limiting

To ensure platform stability and prevent surprise invoices, we rate limit your organization's API usage:

* [deployments](https://docs.edgegap.com/learn/orchestration/deployments "mention") at 40 requests per second,
* [#context-and-status](https://docs.edgegap.com/learn/orchestration/deployments#context-and-status "mention") at 20 requests per second.

{% hint style="info" %}
[Contact us](mailto:info@edgegap.com) to **plan releases, run load tests, estimate launch traffic, and prepare for success.**
{% endhint %}

[^1]: contains pagination information


# Dedicated Servers

## ⚡ Deployments

## \[v2] Deploy

> \<strong>\[Rate Limit: 40/seconds]\</strong> Initiate a new deployment. A deployment is a containerized server instance of an application version running on the Edgegap platform.

```json
{"openapi":"3.0.1","info":{"title":"Edgegap v2 API","version":"2026.02.20"},"servers":[{"url":"https://api.edgegap.com/v2","description":"Edgegap V2"}],"security":[{"api-token":[]}],"components":{"securitySchemes":{"api-token":{"type":"apiKey","in":"header","name":"Authorization"}},"schemas":{"DeploymentCreate":{"required":["application","users","version"],"properties":{"application":{"type":"string","description":"Name of the application that will be deployed"},"version":{"type":"string","description":"Name of the version within the application that will be deployed"},"require_cached_locations":{"type":"boolean","default":false,"description":"Deploy faster by limiting placement to locations with cached image.","nullable":true},"users":{"type":"array","description":"List of users. These users will be used to select the locations for the deployment","minItems":1,"items":{"$ref":"#/components/schemas/User"}},"environment_variables":{"type":"array","description":"List of environment variables to inject into the deployment","items":{"$ref":"#/components/schemas/DeploymentEnvironmentVariable"}},"tags":{"type":"array","description":"List of tags to associate with the deployment","items":{"type":"string"}},"webhook_on_ready":{"description":"Webhook to call when the deployment is ready","allOf":[{"$ref":"#/components/schemas/BasicWebhook"}]},"webhook_on_error":{"description":"Webhook to call when the deployment is in error","allOf":[{"$ref":"#/components/schemas/BasicWebhook"}]},"webhook_on_terminated":{"description":"Webhook to call when the deployment is terminated","allOf":[{"$ref":"#/components/schemas/BasicWebhook"}]}},"type":"object"},"User":{"required":["user_data","user_type"],"properties":{"user_type":{"type":"string","description":"Type of user (e.g., ip_address or geo_coordinates)"},"user_data":{"type":"object","description":"Dynamic user data depending on user_type","properties":{}}},"type":"object"},"DeploymentEnvironmentVariable":{"required":["is_hidden","key","value"],"properties":{"key":{"type":"string","description":"Environment variable key"},"value":{"type":"string","description":"Environment variable value"},"is_hidden":{"type":"boolean","description":"An hidden environment variable is not shown in the UI"}},"type":"object"},"BasicWebhook":{"required":["url"],"properties":{"url":{"type":"string","description":"Webhook URL"}},"type":"object"}}},"paths":{"/deployments":{"post":{"summary":"[v2] Deploy","deprecated":false,"description":"<strong>[Rate Limit: 40/seconds]</strong> Initiate a new deployment. A deployment is a containerized server instance of an application version running on the Edgegap platform.","operationId":"deployment-create","tags":[],"parameters":[],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeploymentCreate"}}}},"responses":{"202":{"description":"Deployment Request Accepted","content":{"application/json":{"schema":{"title":"","type":"object","properties":{"request_id":{"type":"string","description":"Request ID. Unique identifier of the deployment request"}},"required":["request_id"]}}},"headers":{}},"400":{"description":"Client Side Request Error","content":{"application/json":{"schema":{"title":"","type":"object","properties":{"message":{"type":"string","description":"Error message"},"details":{"type":"object","description":"Additional error details","properties":{}}},"required":["message"]}}},"headers":{}},"401":{"description":"Unauthorized - Missing Token","content":{"application/json":{"schema":{"title":"","type":"object","properties":{"message":{"type":"string","description":"Error message"},"details":{"type":"object","description":"Additional error details","properties":{}}},"required":["message"]}}},"headers":{}},"422":{"description":"Couldn't Allocate Server","content":{"application/json":{"schema":{"title":"","type":"object","properties":{"request_id":{"type":"string","description":"Request ID. Unique identifier of the deployment request"},"message":{"type":"string","description":"Error message"}},"required":["request_id","message"]}}},"headers":{}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"title":"","type":"object","properties":{"message":{"type":"string","description":"Error message"},"details":{"type":"object","description":"Additional error details","properties":{}}},"required":["message"]}}},"headers":{}}}}}}}
```

{% openapi src="<https://api.edgegap.com/swagger.json>" path="/v1/status/{request\_id}" method="get" %}
<https://api.edgegap.com/swagger.json>
{% endopenapi %}

{% openapi src="<https://api.edgegap.com/swagger.json>" path="/v1/stop/{request\_id}" method="delete" %}
<https://api.edgegap.com/swagger.json>
{% endopenapi %}

{% openapi src="<https://api.edgegap.com/swagger.json>" path="/v1/self/stop/{request\_id}/{access\_point\_id}" method="delete" %}
<https://api.edgegap.com/swagger.json>
{% endopenapi %}

{% openapi src="<https://api.edgegap.com/swagger.json>" path="/v1/deployments/bulk-stop" method="post" %}
<https://api.edgegap.com/swagger.json>
{% endopenapi %}

{% openapi src="<https://api.edgegap.com/swagger.json>" path="/v1/deployments" method="get" %}
<https://api.edgegap.com/swagger.json>
{% endopenapi %}

{% openapi src="<https://api.edgegap.com/swagger.json>" path="/v1/locations" method="get" %}
<https://api.edgegap.com/swagger.json>
{% endopenapi %}

{% openapi src="<https://api.edgegap.com/swagger.json>" path="/v1/deployment/{request\_id}/container-logs" method="get" %}
<https://api.edgegap.com/swagger.json>
{% endopenapi %}

{% openapi src="<https://api.edgegap.com/swagger.json>" path="/v1/metrics/deployment/{request\_id}" method="get" %}
<https://api.edgegap.com/swagger.json>
{% endopenapi %}

### Legacy \[v1]

{% hint style="warning" %}
Legacy v1/deploy API endpoint is **outdated, and has been replaced by v2 API** - see [#deployments](#deployments "mention").
{% endhint %}

## Create a Deployment request.

> \[Rate Limit: 40/second] Create a new deployment. A deployment is a containerized instance of an application version running on the Edgegap platform.

```json
{"openapi":"3.1.1","info":{"title":"Edgegap V1","version":"0.0.0"},"tags":[{"name":"Deployments","description":"Deployments Control API - Please refer to <a href='https://docs.edgegap.com/docs/deployment' target='_blank'>this documentation</a> to get started with deployments."}],"servers":[{"url":"https://api.edgegap.com"}],"security":[{"apiKey":[]}],"components":{"securitySchemes":{"apiKey":{"type":"apiKey","in":"header","name":"authorization","description":"To access Edgegap API, generate (and view) your secret tokens in Dashboard - User Settings / Tokens. Add your secret token with each API request as an HTTP header (include the word token): `Authorization: token xxxxxxxx-e458-4592-b607-c2c28afd8b62`"}},"schemas":{"Request":{"required":["request_app","request_dns","request_id","request_user_count","request_version"],"properties":{"request_id":{"type":"string","description":"The identifier of the deployment request. This is used to track the deployment."},"request_dns":{"type":"string","description":"This is the FQDN that allow to connect to your Deployment. It will not resolve until the deployment is ready."},"request_app":{"type":"string","description":"The application that has been deployed."},"filters":{"type":"array","description":"List of filters applied to choose the location of the deployment.","items":{"$ref":"#/components/schemas/DeploymentFilterModel"}},"request_version":{"type":"string","description":"The version of the application that has been deployed."},"request_user_count":{"type":"integer","description":"This is the number of IP you have provided in the deployment request."},"tags":{"type":"array","description":"List of tags that have been injected in the deployment request. This field will only be present if tags were provided in the request.","items":{"type":"string"}},"container_log_storage":{"description":"Endpoint storage configuration that will be used to store the container logs when the deployment will be deleted. This field will only be present if container log storage was provided in the request.","$ref":"#/components/schemas/ContainerLogStorageModel"},"location":{"description":"The desired location centroid of the deployment. This field will only be present if a location was provided in the request.","$ref":"#/components/schemas/LocationModel"},"ap_sort_strategy":{"type":"string","description":"(DEPRECATED) - Will only be present if the request was made with the ap_sort_strategy field.","enum":["basic","weighted"]}},"type":"object"},"DeploymentFilterModel":{"required":["field","filter_type","values"],"properties":{"field":{"type":"string","description":"The deployment's field to filter on. See https://docs.edgegap.com/learn/advanced-features/deployments#filter-deployments for more details."},"values":{"type":"array","description":"The values to filter on.","items":{"type":"string"}},"filter_type":{"type":"string","description":"The type of filter.","enum":["any","all","not"]}},"type":"object"},"ContainerLogStorageModel":{"required":["enabled"],"properties":{"enabled":{"type":"boolean","description":"If true, the container logs will be stored in the provided endpoint storage at the end of the request. If false, the container logs will not be stored, even if set up in the app version."},"endpoint_storage":{"type":"string","description":"The name of the endpoint storage to be used. It must be the same as the one set on the dashboard when created. If container log storage is enabled without this parameter, we will try to take the app version endpoint storage. If there is no endpoint storage in your app version, the container logs will not be stored. If we don't find any endpointstorage associated with this name, the container logs will not be stored."}},"type":"object"},"LocationModel":{"required":["latitude","longitude"],"properties":{"latitude":{"type":"number","description":"Desired Latitude"},"longitude":{"type":"number","description":"Desired Longitude"}},"type":"object"},"Error":{"required":["message"],"properties":{"message":{"type":"string","description":"A message depending of the request termination"}},"type":"object"},"DeployModel":{"required":["app_name"],"properties":{"app_name":{"type":"string","description":"The application you want to deploy a version of."},"version_name":{"type":"string","description":"The application version you want to deploy a container, if not present, the last version created is automatically chosen."},"is_public_app":{"type":"boolean","description":"(DEPRECATED) - No longer used and you don't need to set it.","default":false},"ip_list":{"type":"array","description":"This parameter is not optional, but mutually exclusive with the geo_ip_list parameter. One of them is required. List of IP representing your users. These will be used to determine the best location for your deployment.","items":{"type":"string"}},"geo_ip_list":{"type":"array","description":"This parameter is not optional, but mutually exclusive with the ip_list parameter. One of them is required. List of IP of your user with their location (latitude, longitude). We will use the coordinates instead of the IPs to determine the best location for your deployment.","items":{"$ref":"#/components/schemas/GeoIpListModel"}},"telemetry_profile_uuid_list":{"type":"array","description":"(DEPRECATED)","items":{"type":"string"}},"env_vars":{"type":"array","description":"List of environment variables to set in your deployment instance. These variables will be available in your container.","items":{"$ref":"#/components/schemas/DeployEnvModel"}},"skip_telemetry":{"type":"boolean","description":"If true, the deployment will skip the telemetry measurement. This result in a faster time to deploy.","default":true},"location":{"description":"Specify the centroid of the deployment instead of letting the system choose the best location. The system will do a best effort to deploy the container in the closest location to the specified coordinates.","$ref":"#/components/schemas/LocationModel"},"webhook_url":{"type":"string","description":"A URL to send a POST request when the deployment is ready. The request will contain the deployment status. The content of the request is the same as the `v1/status/{request_id}` endpoint."},"tags":{"type":"array","description":"List of tags associated with the deployment. These tags will be shown in the dashboard.","items":{"type":"string"}},"container_log_storage":{"description":"Configuration for the container log storage. This will override the app version default configuration if set.","$ref":"#/components/schemas/ContainerLogStorageModel"},"filters":{"type":"array","description":"List of filters to apply to the deployment. The deployment will be deployed in a location that match the filters.","items":{"$ref":"#/components/schemas/DeploymentFilterModel"}},"ap_sort_strategy":{"type":"string","description":"(DEPRECATED) - No longer used and you don't need to set it.","enum":["basic","weighted"]},"command":{"type":["string","null"],"description":"Allows to override the container command for this deployment. This is an advanced feature and should be used with caution.If set to null, the default command of the container will be used."},"arguments":{"type":["string","null"],"description":"Allows to override the container arguments for this deployment. This is an advanced feature and should be used with caution.If set to null, the default arguments of the container will be used."}},"type":"object"},"GeoIpListModel":{"required":["ip","latitude","longitude"],"properties":{"ip":{"type":"string","description":"IP address"},"latitude":{"type":"number","description":"Latitude of the IP/User"},"longitude":{"type":"number","description":"Longitude of the IP/User"}},"type":"object"},"DeployEnvModel":{"required":["key","value"],"properties":{"key":{"type":"string","description":"Key of the environment variable. This key will be used to access the value in your container."},"value":{"type":"string","description":"Value of the environment variable. This value will be set in your container. Max 4096 characters."},"is_hidden":{"type":"boolean","description":"If true, the environment variable will be encrypted and only decrypted in the container."}},"type":"object"}}},"paths":{"/v1/deploy":{"post":{"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Request"}}}},"400":{"description":"Bad Request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Conflict","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Unprocessable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"summary":"Create a Deployment request.","description":"[Rate Limit: 40/second] Create a new deployment. A deployment is a containerized instance of an application version running on the Edgegap platform.","operationId":"deploy","tags":["Deployments"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeployModel"}}},"required":true}}}}}
```

## 🗺️ Private Fleets

## Deploy to Fleet

> \<strong>\[Rate Limit: 40/seconds]\</strong> Initiate a new private fleet deployment. A deployment is a containerized server instance of an application version running on the Edgegap platform.

```json
{"openapi":"3.0.1","info":{"title":"Edgegap v2 API","version":"2026.02.20"},"servers":[{"url":"https://api.edgegap.com/v2","description":"Edgegap V2"}],"security":[{"api-token":[]}],"components":{"securitySchemes":{"api-token":{"type":"apiKey","in":"header","name":"Authorization"}},"schemas":{"PrivateFleetDeploymentCreate":{"type":"object","properties":{"application":{"type":"string","description":"Name of the application that will be deployed"},"version":{"type":"string","description":"Name of the version within the application that will be deployed"},"require_cached_locations":{"type":"boolean","default":false,"description":"Deploy faster by limiting placement to locations with cached image.","nullable":true},"private_host_ids":{"type":"array","items":{"type":"string"},"description":"Preferred and prioritized Private Host IDs to try before overflowing to cloud.","minItems":1,"uniqueItems":true},"users":{"type":"array","description":"List of users. These users will be used to select the locations for the deployment","minItems":1,"items":{"$ref":"#/components/schemas/User"}},"environment_variables":{"type":"array","description":"List of environment variables to inject into the deployment","items":{"$ref":"#/components/schemas/DeploymentEnvironmentVariable"}},"tags":{"type":"array","description":"List of tags to associate with the deployment","items":{"type":"string"}},"webhook_on_ready":{"description":"Webhook to call when the deployment is ready","allOf":[{"$ref":"#/components/schemas/BasicWebhook"}]},"webhook_on_error":{"description":"Webhook to call when the deployment is in error","allOf":[{"$ref":"#/components/schemas/BasicWebhook"}]},"webhook_on_terminated":{"description":"Webhook to call when the deployment is terminated","allOf":[{"$ref":"#/components/schemas/BasicWebhook"}]}},"required":["application","users","version","private_host_ids"]},"User":{"required":["user_data","user_type"],"properties":{"user_type":{"type":"string","description":"Type of user (e.g., ip_address or geo_coordinates)"},"user_data":{"type":"object","description":"Dynamic user data depending on user_type","properties":{}}},"type":"object"},"DeploymentEnvironmentVariable":{"required":["is_hidden","key","value"],"properties":{"key":{"type":"string","description":"Environment variable key"},"value":{"type":"string","description":"Environment variable value"},"is_hidden":{"type":"boolean","description":"An hidden environment variable is not shown in the UI"}},"type":"object"},"BasicWebhook":{"required":["url"],"properties":{"url":{"type":"string","description":"Webhook URL"}},"type":"object"},"Error":{"required":["message"],"properties":{"message":{"type":"string","description":"Error message"},"details":{"type":"object","description":"Additional error details","properties":{}}},"type":"object"},"ParameterError422":{"required":["message","request_id"],"properties":{"request_id":{"type":"string","description":"Request ID. Unique identifier of the deployment request"},"message":{"type":"string","description":"Error message"}},"type":"object"}}},"paths":{"/private-fleets/deployments":{"post":{"summary":"Deploy to Fleet","deprecated":false,"description":"<strong>[Rate Limit: 40/seconds]</strong> Initiate a new private fleet deployment. A deployment is a containerized server instance of an application version running on the Edgegap platform.","operationId":"private-fleets-deployment-create","tags":[],"parameters":[],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PrivateFleetDeploymentCreate"}}}},"responses":{"202":{"description":"","content":{"application/json":{"schema":{"title":"","type":"object","properties":{"request_id":{"type":"string","description":"Request ID. Unique identifier of the deployment request"}},"required":["request_id"]}}},"headers":{}},"400":{"description":"Invalid Application or Application Version. No deployment has been created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{}},"401":{"description":"Unauthorized. No deployment has been created.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{}},"422":{"description":"Could not allocate an Edge Server for the deployment. A deployment has been created. Deployment is in error state. You can delete it manually or it will be deleted automatically by our system after some some times","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ParameterError422"}}},"headers":{}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{}}}}}}}
```

## List Private Fleet Hosts

> \<strong>\[Rate Limit: 10/seconds]\</strong> List all hosts in a private fleet.

```json
{"openapi":"3.0.1","info":{"title":"Edgegap v2 API","version":"2026.02.20"},"servers":[{"url":"https://api.edgegap.com/v2","description":"Edgegap V2"}],"security":[{"api-token":[]}],"components":{"securitySchemes":{"api-token":{"type":"apiKey","in":"header","name":"Authorization"}}},"paths":{"/private-fleets/{fleet-name}/hosts":{"get":{"summary":"List Private Fleet Hosts","deprecated":false,"description":"<strong>[Rate Limit: 10/seconds]</strong> List all hosts in a private fleet.","operationId":"private-fleet-hosts-list","tags":[],"parameters":[{"name":"fleet-name","in":"path","description":"Name of your private fleet.","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"host_id":{"type":"string","description":"Unique private fleet host identifier, used to deploy on this host."},"status":{"type":"string","description":"Lifecycle stage of the host, only ACTIVE hosts accept deployments.","enum":["PENDING","ACTIVE"]},"ip_address":{"type":"string","description":"Public IP address of the host.","nullable":true},"latitude":{"type":"number","description":"Approximate geographic latitude of the host.","nullable":true},"longitude":{"type":"number","description":"Approximate geographic longitude of the host.","nullable":true},"city":{"type":"string","description":"City in which the host is located.","nullable":true},"country":{"type":"string","description":"Country in which the host is located.","nullable":true},"continent":{"type":"string","description":"Continent in which the host is located.","nullable":true},"allocated_cpu_units":{"type":"integer","description":"Total virtual CPU units currently in use for deployments, beacons, and orchestration.","nullable":true},"allocated_memory_mb":{"type":"integer","description":"Total memory in MB currently in use for deployments, beacons, and orchestration."},"allocatable_cpu_units":{"type":"integer","description":"Total available virtual CPU units for deployments.","nullable":true},"allocatable_memory_mb":{"type":"integer","description":"Total available memory in MB for deployments.","nullable":true},"beacon":{"type":"object","properties":{"tcp_port":{"type":"integer","description":"External beacon TCP port used to perform TCP ping."},"udp_port":{"type":"integer","description":"External beacon UDP port used to perform UDP ping."},"ip_address":{"type":"string","description":"Public IP address used to perform ping measurement."}},"required":["tcp_port","udp_port","ip_address"],"description":"Assigned beacon information, if enabled for this fleet.","nullable":true},"created_at":{"type":"string","description":"Timestamp of creation in UTC, ISO 8601 format."},"updated_at":{"type":"string","description":"Timestamp of last update in UTC, ISO 8601 format."},"centroid":{"type":"object","properties":{"label":{"type":"string","description":"Human readable label."},"latitude":{"type":"number","description":"Approximate geographic latitude of the centroid."},"longitude":{"type":"number","description":"Approximate geographic longitude of the centroid."},"radius_km":{"type":"integer","description":"Approximate geographic radius used to pick primary and fallback locations."},"desired_host_count":{"type":"integer","description":"Requested amount of hosts to be started under this centroid."}},"required":["label","latitude","longitude","radius_km","desired_host_count"],"description":"Centroid information used to orchestrate placement of the host."},"delete_schedule":{"type":"object","properties":{"uuid":{"type":"string","description":"Unique identifier of deletion schedule."},"scheduled_at":{"type":"string","description":"Timestamp of scheduled deletion in UTC, ISO 8601 format."}},"description":"If defined, specified when the host will be deleted.","required":["uuid","scheduled_at"],"nullable":true},"fleet_host_specifications":{"type":"object","properties":{"cpu_units":{"type":"integer","description":"Host specification vCPU units selected during fleet creation."},"memory_mb":{"type":"integer","description":"Host specification memory MB selected during fleet creation."},"base_clock_speed_mhz":{"type":"integer","description":"Host specification base CPU clock frequency selected during fleet creation."}},"required":["cpu_units","memory_mb","base_clock_speed_mhz"]}},"description":"List of private fleet hosts.","required":["host_id","status","allocated_cpu_units","allocated_memory_mb","created_at","updated_at","centroid","fleet_host_specifications"]}}},"required":["data"]}}},"headers":{}},"400":{"description":"","content":{"application/json":{"schema":{"title":"","type":"object","properties":{"message":{"type":"string","description":"Error message"},"details":{"type":"object","description":"Additional error details","properties":{}}},"required":["message"]}}},"headers":{}},"401":{"description":"","content":{"application/json":{"schema":{"title":"","type":"object","properties":{"message":{"type":"string","description":"Error message"},"details":{"type":"object","description":"Additional error details","properties":{}}},"required":["message"]}}},"headers":{}},"500":{"description":"","content":{"application/json":{"schema":{"title":"","type":"object","properties":{"message":{"type":"string","description":"Error message"},"details":{"type":"object","description":"Additional error details","properties":{}}},"required":["message"]}}},"headers":{}}}}}}}
```

## &#x20;🔖 Tags

{% openapi src="<https://api.edgegap.com/swagger.json>" path="/v1/deployments/{request\_id}/tags" method="get" %}
<https://api.edgegap.com/swagger.json>
{% endopenapi %}

{% openapi src="<https://api.edgegap.com/swagger.json>" path="/v1/deployments/{request\_id}/tags/{tag\_name}" method="get" %}
<https://api.edgegap.com/swagger.json>
{% endopenapi %}

{% openapi src="<https://api.edgegap.com/swagger.json>" path="/v1/deployments/{request\_id}/tags" method="post" %}
<https://api.edgegap.com/swagger.json>
{% endopenapi %}

{% openapi src="<https://api.edgegap.com/swagger.json>" path="/v1/deployments/{request\_id}/tags/{tag\_name}" method="delete" %}
<https://api.edgegap.com/swagger.json>
{% endopenapi %}

{% openapi src="<https://api.edgegap.com/swagger.json>" path="/v1/deployments/{request\_id}/tags/{tag\_name}" method="patch" %}
<https://api.edgegap.com/swagger.json>
{% endopenapi %}


# Versioning

## 📦 Applications

{% openapi src="<https://api.edgegap.com/swagger.json>" path="/v1/app" method="post" %}
<https://api.edgegap.com/swagger.json>
{% endopenapi %}

{% openapi src="<https://api.edgegap.com/swagger.json>" path="/v1/app/{app\_name}" method="patch" %}
<https://api.edgegap.com/swagger.json>
{% endopenapi %}

{% openapi src="<https://api.edgegap.com/swagger.json>" path="/v1/app/{app\_name}" method="get" %}
<https://api.edgegap.com/swagger.json>
{% endopenapi %}

{% openapi src="<https://api.edgegap.com/swagger.json>" path="/v1/app/{app\_name}" method="delete" %}
<https://api.edgegap.com/swagger.json>
{% endopenapi %}

{% openapi src="<https://api.edgegap.com/swagger.json>" path="/v1/app/{app\_name}/version" method="post" %}
<https://api.edgegap.com/swagger.json>
{% endopenapi %}

{% openapi src="<https://api.edgegap.com/swagger.json>" path="/v1/app/{app\_name}/version/{version\_name}" method="delete" %}
<https://api.edgegap.com/swagger.json>
{% endopenapi %}

{% openapi src="<https://api.edgegap.com/swagger.json>" path="/v1/app/{app\_name}/version/{version\_name}" method="get" %}
<https://api.edgegap.com/swagger.json>
{% endopenapi %}

{% openapi src="<https://api.edgegap.com/swagger.json>" path="/v1/app/{app\_name}/version/{version\_name}" method="patch" %}
<https://api.edgegap.com/swagger.json>
{% endopenapi %}

{% openapi src="<https://api.edgegap.com/swagger.json>" path="/v1/app/{app\_name}/versions" method="get" %}
<https://api.edgegap.com/swagger.json>
{% endopenapi %}

{% openapi src="<https://api.edgegap.com/swagger.json>" path="/v1/apps" method="get" %}
<https://api.edgegap.com/swagger.json>
{% endopenapi %}

## 💾 Container Registry

{% openapi src="<https://api.edgegap.com/swagger.json>" path="/v1/container-registry/images/{image\_name}/tags" method="get" %}
<https://api.edgegap.com/swagger.json>
{% endopenapi %}

{% openapi src="<https://api.edgegap.com/swagger.json>" path="/v1/container-registry/images/{image\_name}/tags/{tag\_name}" method="delete" %}
<https://api.edgegap.com/swagger.json>
{% endopenapi %}

## Create a New Pull Profile

> Create a pull profile. Pull profile will upload data from an endpoint storage to a deployment container on boot. You must link the application version to the pull profile first.

```json
{"openapi":"3.1.1","info":{"title":"Edgegap V1","version":"0.0.0"},"tags":[{"name":"Endpoint Storage","description":"Endpoint Storage Control API - Please refer to <a href='https://docs.edgegap.com/docs/deployment/endpoint-storage' target='_blank'>this documentation</a> to get started with storage."}],"servers":[{"url":"https://api.edgegap.com"}],"security":[{"apiKey":[]}],"components":{"securitySchemes":{"apiKey":{"type":"apiKey","in":"header","name":"authorization","description":"To access Edgegap API, generate (and view) your secret tokens in Dashboard - User Settings / Tokens. Add your secret token with each API request as an HTTP header (include the word token): `Authorization: token xxxxxxxx-e458-4592-b607-c2c28afd8b62`"}},"schemas":{"PullProfilePostResponse":{"required":["destination","name","source","source_type"],"properties":{"name":{"type":"string","description":"Name of the pull profile"},"source":{"type":"string","description":"Source in the S3 bucket to fetch from"},"source_type":{"type":"string","description":"If the source is a File or a Directory","enum":["File","Folder"]},"destination":{"type":"string","description":"Destination path where your source will be uploaded in your container. Make sure to avoid protected destinations, such as `/etc/`, as this will prevent the files from being copied to your deployment, and will make your deployment fail. Make sure a normal user can write to the destination folder."},"create_time":{"type":"string","description":"UTC time of pull profile creation"},"last_updated":{"type":"string","description":"UTC time of pull profile last update"}},"type":"object"},"Error":{"required":["message"],"properties":{"message":{"type":"string","description":"A message depending of the request termination"}},"type":"object"},"PullProfilePostPayload":{"required":["destination","name","source","source_type"],"properties":{"name":{"type":"string","description":"Name of the pull profile"},"source":{"type":"string","description":"Source in the S3 bucket to fetch from"},"source_type":{"type":"string","description":"If the source is a File or a Directory","enum":["File","Folder"]},"destination":{"type":"string","description":"Destination path where your source will be uploaded in your container. Make sure to avoid protected destinations, such as `/etc/`, as this will prevent the files from being copied to your deployment, and will make your deployment fail. Make sure a normal user can write to the destination folder."}},"type":"object"}}},"paths":{"/v1/storage/endpoint/{endpoint_name}/pull-profile":{"post":{"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PullProfilePostResponse"}}}},"400":{"description":"Bad Request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"summary":"Create a New Pull Profile","description":"Create a pull profile. Pull profile will upload data from an endpoint storage to a deployment container on boot. You must link the application version to the pull profile first.","operationId":"pull-profile-create","tags":["Endpoint Storage"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PullProfilePostPayload"}}},"required":true}}}}}
```

## Get a Pull Profile

> Retrieve a pull profile and its specifications.

```json
{"openapi":"3.1.1","info":{"title":"Edgegap V1","version":"0.0.0"},"tags":[{"name":"Endpoint Storage","description":"Endpoint Storage Control API - Please refer to <a href='https://docs.edgegap.com/docs/deployment/endpoint-storage' target='_blank'>this documentation</a> to get started with storage."}],"servers":[{"url":"https://api.edgegap.com"}],"security":[{"apiKey":[]}],"components":{"securitySchemes":{"apiKey":{"type":"apiKey","in":"header","name":"authorization","description":"To access Edgegap API, generate (and view) your secret tokens in Dashboard - User Settings / Tokens. Add your secret token with each API request as an HTTP header (include the word token): `Authorization: token xxxxxxxx-e458-4592-b607-c2c28afd8b62`"}},"schemas":{"PullProfileGetResponse":{"required":["destination","name","source","source_type"],"properties":{"name":{"type":"string","description":"Name of the pull profile"},"source":{"type":"string","description":"Source in the S3 bucket to fetch from"},"source_type":{"type":"string","description":"If the source is a File or a Directory","enum":["File","Folder"]},"destination":{"type":"string","description":"Destination path where your source will be uploaded in your container. Make sure to avoid protected destinations, such as `/etc/`, as this will prevent the files from being copied to your deployment, and will make your deployment fail. Make sure a normal user can write to the destination folder."},"create_time":{"type":"string","description":"UTC time of pull profile creation"},"last_updated":{"type":"string","description":"UTC time of pull profile last update"}},"type":"object"},"Error":{"required":["message"],"properties":{"message":{"type":"string","description":"A message depending of the request termination"}},"type":"object"}}},"paths":{"/v1/storage/endpoint/{endpoint_name}/pull-profile/{pull_profile_name}":{"get":{"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PullProfileGetResponse"}}}},"400":{"description":"Bad Request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"summary":"Get a Pull Profile","description":"Retrieve a pull profile and its specifications.","operationId":"pull-profile-get","tags":["Endpoint Storage"]}}}}
```

## Update a Pull Profile

> Update a pull profile with new specifications.

```json
{"openapi":"3.1.1","info":{"title":"Edgegap V1","version":"0.0.0"},"tags":[{"name":"Endpoint Storage","description":"Endpoint Storage Control API - Please refer to <a href='https://docs.edgegap.com/docs/deployment/endpoint-storage' target='_blank'>this documentation</a> to get started with storage."}],"servers":[{"url":"https://api.edgegap.com"}],"security":[{"apiKey":[]}],"components":{"securitySchemes":{"apiKey":{"type":"apiKey","in":"header","name":"authorization","description":"To access Edgegap API, generate (and view) your secret tokens in Dashboard - User Settings / Tokens. Add your secret token with each API request as an HTTP header (include the word token): `Authorization: token xxxxxxxx-e458-4592-b607-c2c28afd8b62`"}},"schemas":{"PulloProfilePatchResponse":{"properties":{"name":{"type":"string","description":"Name of the pull profile"},"source":{"type":"string","description":"Source in the S3 bucket to fetch from"},"source_type":{"type":"string","description":"If the source is a File or a Directory","enum":["File","Folder"]},"destination":{"type":"string","description":"Destination path where your source will be uploaded in your container. Make sure to avoid protected destinations, such as `/etc/`, as this will prevent the files from being copied to your deployment, and will make your deployment fail. Make sure a normal user can write to the destination folder."},"create_time":{"type":"string","description":"UTC time of pull profile creation"},"last_updated":{"type":"string","description":"UTC time of pull profile last update"}},"type":"object"},"Error":{"required":["message"],"properties":{"message":{"type":"string","description":"A message depending of the request termination"}},"type":"object"},"PullProfilePatchPayload":{"properties":{"name":{"type":"string","description":"Name of the pull profile"},"source":{"type":"string","description":"Source in the S3 bucket to fetch from"},"source_type":{"type":"string","description":"If the source is a File or a Directory","enum":["File","Folder"]},"destination":{"type":"string","description":"Destination path where your source will be uploaded in your container. Make sure to avoid protected destinations, such as `/etc/`, as this will prevent the files from being copied to your deployment, and will make your deployment fail. Make sure a normal user can write to the destination folder."}},"type":"object"}}},"paths":{"/v1/storage/endpoint/{endpoint_name}/pull-profile/{pull_profile_name}":{"patch":{"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PulloProfilePatchResponse"}}}},"400":{"description":"Bad Request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"summary":"Update a Pull Profile","description":"Update a pull profile with new specifications.","operationId":"pull-profile-update","tags":["Endpoint Storage"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PullProfilePatchPayload"}}},"required":true}}}}}
```

## Delete a Pull Profile

> Delete a pull profile. All the application versions linked won't receive the data upload anymore. It will not delete your endpoint storage.

```json
{"openapi":"3.1.1","info":{"title":"Edgegap V1","version":"0.0.0"},"tags":[{"name":"Endpoint Storage","description":"Endpoint Storage Control API - Please refer to <a href='https://docs.edgegap.com/docs/deployment/endpoint-storage' target='_blank'>this documentation</a> to get started with storage."}],"servers":[{"url":"https://api.edgegap.com"}],"security":[{"apiKey":[]}],"components":{"securitySchemes":{"apiKey":{"type":"apiKey","in":"header","name":"authorization","description":"To access Edgegap API, generate (and view) your secret tokens in Dashboard - User Settings / Tokens. Add your secret token with each API request as an HTTP header (include the word token): `Authorization: token xxxxxxxx-e458-4592-b607-c2c28afd8b62`"}},"schemas":{"Error":{"required":["message"],"properties":{"message":{"type":"string","description":"A message depending of the request termination"}},"type":"object"}}},"paths":{"/v1/storage/endpoint/{endpoint_name}/pull-profile/{pull_profile_name}":{"delete":{"responses":{"204":{"description":"No Content"},"400":{"description":"Bad Request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"summary":"Delete a Pull Profile","description":"Delete a pull profile. All the application versions linked won't receive the data upload anymore. It will not delete your endpoint storage.","operationId":"pull-profile-delete","tags":["Endpoint Storage"]}}}}
```

## List All Pull Profile of an Endpoint Storage

> List all pull profiles of an endpoint storage.

```json
{"openapi":"3.1.1","info":{"title":"Edgegap V1","version":"0.0.0"},"tags":[{"name":"Endpoint Storage","description":"Endpoint Storage Control API - Please refer to <a href='https://docs.edgegap.com/docs/deployment/endpoint-storage' target='_blank'>this documentation</a> to get started with storage."}],"servers":[{"url":"https://api.edgegap.com"}],"security":[{"apiKey":[]}],"components":{"securitySchemes":{"apiKey":{"type":"apiKey","in":"header","name":"authorization","description":"To access Edgegap API, generate (and view) your secret tokens in Dashboard - User Settings / Tokens. Add your secret token with each API request as an HTTP header (include the word token): `Authorization: token xxxxxxxx-e458-4592-b607-c2c28afd8b62`"}},"schemas":{"PullProfilesListResponse":{"properties":{"pull_profiles":{"type":"array","items":{"$ref":"#/components/schemas/PullProfileGetResponse"}},"pagination":{"description":"Pagination Object","$ref":"#/components/schemas/Pagination"}},"type":"object"},"PullProfileGetResponse":{"required":["destination","name","source","source_type"],"properties":{"name":{"type":"string","description":"Name of the pull profile"},"source":{"type":"string","description":"Source in the S3 bucket to fetch from"},"source_type":{"type":"string","description":"If the source is a File or a Directory","enum":["File","Folder"]},"destination":{"type":"string","description":"Destination path where your source will be uploaded in your container. Make sure to avoid protected destinations, such as `/etc/`, as this will prevent the files from being copied to your deployment, and will make your deployment fail. Make sure a normal user can write to the destination folder."},"create_time":{"type":"string","description":"UTC time of pull profile creation"},"last_updated":{"type":"string","description":"UTC time of pull profile last update"}},"type":"object"},"Pagination":{"properties":{"number":{"type":"integer","description":"Current page number"},"next_page_number":{"type":"integer","description":"Next page number"},"previous_page_number":{"type":"integer","description":"Previous page number"},"paginator":{"$ref":"#/components/schemas/Paginator"},"has_next":{"type":"boolean","description":"If there is a next page"},"has_previous":{"type":"boolean","description":"If there is a previous page"}},"type":"object"},"Paginator":{"properties":{"num_pages":{"type":"integer","description":"Total pages count"}},"type":"object"},"Error":{"required":["message"],"properties":{"message":{"type":"string","description":"A message depending of the request termination"}},"type":"object"}}},"paths":{"/v1/storage/endpoint/{endpoint_name}/pull-profiles":{"get":{"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PullProfilesListResponse"}}}},"400":{"description":"Bad Request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"summary":"List All Pull Profile of an Endpoint Storage","description":"List all pull profiles of an endpoint storage.","operationId":"pull-profile-list","parameters":[{"schema":{"type":"integer","default":1},"name":"page","in":"query","description":"Page number for pagination"},{"schema":{"type":"integer","default":10},"name":"limit","in":"query","description":"Limit of pull profiles for each page"}],"tags":["Endpoint Storage"]}}}}
```

## Link a Pull Profile to an Application Version

> Link a pull profile to an app version. Without a link, the pull profile by itself will do nothing.

```json
{"openapi":"3.1.1","info":{"title":"Edgegap V1","version":"0.0.0"},"tags":[{"name":"Endpoint Storage","description":"Endpoint Storage Control API - Please refer to <a href='https://docs.edgegap.com/docs/deployment/endpoint-storage' target='_blank'>this documentation</a> to get started with storage."}],"servers":[{"url":"https://api.edgegap.com"}],"security":[{"apiKey":[]}],"components":{"securitySchemes":{"apiKey":{"type":"apiKey","in":"header","name":"authorization","description":"To access Edgegap API, generate (and view) your secret tokens in Dashboard - User Settings / Tokens. Add your secret token with each API request as an HTTP header (include the word token): `Authorization: token xxxxxxxx-e458-4592-b607-c2c28afd8b62`"}},"schemas":{"PullProfileAppVersionLinkResponse":{"required":["app","app_version","endpoint","pull_profile"],"properties":{"app":{"type":"string","description":"Name of the linked app of the linked version"},"app_version":{"type":"string","description":"Name of the linked app version."},"endpoint":{"type":"string","description":"Name of the endpoint storage"},"pull_profile":{"type":"string","description":"Name of the pull profile the app version is linked to."},"create_time":{"type":"string","description":"UTC time of link creation"},"last_updated":{"type":"string","description":"UTC time of link last update"}},"type":"object"},"Error":{"required":["message"],"properties":{"message":{"type":"string","description":"A message depending of the request termination"}},"type":"object"}}},"paths":{"/v1/storage/endpoint/{endpoint_name}/pull-profile/{pull_profile_name}/app/{app_name}/version/{version_name}":{"put":{"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PullProfileAppVersionLinkResponse"}}}},"400":{"description":"Bad Request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"summary":"Link a Pull Profile to an Application Version","description":"Link a pull profile to an app version. Without a link, the pull profile by itself will do nothing.","operationId":"pull-profile-link-app-version","tags":["Endpoint Storage"]}}}}
```

## Unlink a Pull Profile From an Application Version

> Unlink a pull profile from an app version. It will not delete the pull profile.

```json
{"openapi":"3.1.1","info":{"title":"Edgegap V1","version":"0.0.0"},"tags":[{"name":"Endpoint Storage","description":"Endpoint Storage Control API - Please refer to <a href='https://docs.edgegap.com/docs/deployment/endpoint-storage' target='_blank'>this documentation</a> to get started with storage."}],"servers":[{"url":"https://api.edgegap.com"}],"security":[{"apiKey":[]}],"components":{"securitySchemes":{"apiKey":{"type":"apiKey","in":"header","name":"authorization","description":"To access Edgegap API, generate (and view) your secret tokens in Dashboard - User Settings / Tokens. Add your secret token with each API request as an HTTP header (include the word token): `Authorization: token xxxxxxxx-e458-4592-b607-c2c28afd8b62`"}},"schemas":{"Error":{"required":["message"],"properties":{"message":{"type":"string","description":"A message depending of the request termination"}},"type":"object"}}},"paths":{"/v1/storage/endpoint/{endpoint_name}/pull-profile/{pull_profile_name}/app/{app_name}/version/{version_name}":{"delete":{"responses":{"204":{"description":"Success"},"400":{"description":"Bad Request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"summary":"Unlink a Pull Profile From an Application Version","description":"Unlink a pull profile from an app version. It will not delete the pull profile.","operationId":"pull-profile-unlink-app-version","tags":["Endpoint Storage"]}}}}
```

## 🗒️ Log Storage

{% openapi src="<https://api.edgegap.com/swagger.json>" path="/v1/storage/endpoint" method="post" %}
<https://api.edgegap.com/swagger.json>
{% endopenapi %}

{% openapi src="<https://api.edgegap.com/swagger.json>" path="/v1/storage/endpoint/{endpoint\_name}" method="delete" %}
<https://api.edgegap.com/swagger.json>
{% endopenapi %}

{% openapi src="<https://api.edgegap.com/swagger.json>" path="/v1/storage/endpoints" method="get" %}
<https://api.edgegap.com/swagger.json>
{% endopenapi %}

{% openapi src="<https://api.edgegap.com/swagger.json>" path="/v1/storage/endpoint/{endpoint\_name}" method="get" %}
<https://api.edgegap.com/swagger.json>
{% endopenapi %}

{% openapi src="<https://api.edgegap.com/swagger.json>" path="/v1/storage/endpoint/{endpoint\_name}" method="patch" %}
<https://api.edgegap.com/swagger.json>
{% endopenapi %}


# Integration

## ⭐ Matchmaking

Each matchmaker manages their own private API, separate from your organization's Edgegap API.

{% tabs fullWidth="false" %}
{% tab title="🍀 Simple Example" %}
{% file src="<https://3027732442-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2FqofgtLfdhstOFoJr1BzV%2Fmm-conf-simple-example.json?alt=media&token=7dc25895-aef3-4174-9f40-e45af77a28d6>" %}
{% endtab %}

{% tab title="🏁 Advanced Example" %}
{% file src="<https://3027732442-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2FxSkXEzgG9AUPrXbsFsTU%2Fmm-conf-advanced-example.json?alt=media&token=4bcc1c0b-5887-457f-8a50-d89c0b20714e>" %}
{% endtab %}

{% tab title="🎾 Custom Lobby" %}
{% file src="<https://3027732442-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2Fts2LDr07atVf70MREw7j%2Fmm-conf-custom-lobby.json?alt=media&token=0215a52a-3fc1-47e8-beb9-6e90a4c49f6d>" %}
{% endtab %}

{% tab title="🥛 Backfill Showcase" %}
{% file src="<https://3027732442-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2FJEbYPVDhVI8UNCIcyFxQ%2Fmm-conf-backfill-example.json?alt=media&token=64733825-a3de-4d91-96fd-0f2f5e8be0cc>" %}
{% endtab %}

{% tab title="⚔️ Competitive Games" %}
{% file src="<https://3027732442-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2FVUNHRCiqRhf7axG6KQAD%2Fmm-conf-competitive-example.json?alt=media&token=7e49eb87-f07e-4969-b141-dbb8edea37fe>" %}
{% endtab %}

{% tab title="🤝 Cooperative Games" %}
{% file src="<https://3027732442-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2F6pWfNV1QOvpWbYQtbxc6%2Fmm-conf-cooperative-example.json?alt=media&token=b5c9f44b-cdd2-4968-8445-3f74d56b61c8>" %}
{% endtab %}

{% tab title="🎈 Social Games" %}
{% file src="<https://3027732442-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2FkVZMSRCd7JTXwOK2MqoW%2Fmm-conf-social-example.json?alt=media&token=ef26e619-5b31-4395-8e35-7607cb21bd35>" %}
{% endtab %}
{% endtabs %}

Import API specification to [Scalar API Web Client](https://client.scalar.com/workspace/default/request/default) or [Swagger Editor](https://editor.swagger.io/) to inspect details.

{% hint style="success" %}
**Swagger Web UI**: deploying your service will generate an openAPI specification and a convenient web UI. Open the URL in your browser to view and test all API endpoints, and to review payload examples.
{% endhint %}

## 🧭 Server Browser

Each matchmaker manages their own private API, separate from your organization's Edgegap API.

{% file src="broken-reference" %}

{% hint style="success" %}
**Swagger Web UI**: deploying your service will generate an openAPI specification and a convenient web UI. Open the URL in your browser to view and test all API endpoints, and to review payload examples.
{% endhint %}

## 🗼 Beacons

{% openapi src="<https://api.edgegap.com/swagger.json>" path="/v1/locations/beacons" method="get" %}
<https://api.edgegap.com/swagger.json>
{% endopenapi %}


# Relays

## 📫 Relays

{% openapi src="<https://api.edgegap.com/swagger.json>" path="/v1/relays/sessions" method="post" %}
<https://api.edgegap.com/swagger.json>
{% endopenapi %}

{% openapi src="<https://api.edgegap.com/swagger.json>" path="/v1/relays/sessions" method="get" %}
<https://api.edgegap.com/swagger.json>
{% endopenapi %}

{% openapi src="<https://api.edgegap.com/swagger.json>" path="/v1/relays/sessions/{session\_id}" method="delete" %}
<https://api.edgegap.com/swagger.json>
{% endopenapi %}

{% openapi src="<https://api.edgegap.com/swagger.json>" path="/v1/relays/sessions/{session\_id}" method="get" %}
<https://api.edgegap.com/swagger.json>
{% endopenapi %}

{% openapi src="<https://api.edgegap.com/swagger.json>" path="/v1/relays/sessions:authorize-user" method="post" %}
<https://api.edgegap.com/swagger.json>
{% endopenapi %}

{% openapi src="<https://api.edgegap.com/swagger.json>" path="/v1/relays/sessions:revoke-user" method="post" %}
<https://api.edgegap.com/swagger.json>
{% endopenapi %}


# Release Notes

{% hint style="info" %}
View older Release Notes in our [archive](https://docs.edgegap.com/docs/release-notes/archive "mention").
{% endhint %}

### 2026.03.11 (Latest)

**New ✨**

* Access relevant documentation directly from dashboard using our new widget.
* View release notes and new feature announcements directly in dashboard home page.
* Copy outputs now with a single click in our [unreal-engine](https://docs.edgegap.com/unreal-engine "mention") docker extension.

**Fixed ✔**

* Fixed a bug where caching remained active when an application was disabled.
* Fixed a bug where using secret environment variables with non-ASCII characters would return an error when creating a deployment.
* Fixed a bug where credits balance wasn't updating to reflect used or expired credit grants.

### 2026.02.24

**Improvements 💪**

* Improved hover states on the [Deployment List](https://app.edgegap.com/deployment-management/deployments/list?deployments-table-limit=50\&deployments-table-page=1) page for better clarity on available click actions.
* Upgraded Dashboard framework to improve performance and stability. If you notice unexpected behavior, please report it in our [Community Discord](https://discord.gg/NgCnkHbsGp).

**Fixed ✔**

* Fixed a bug where webhook results in the deployment details page incorrectly showed HTTP status code 0 when the webhook handler returned no JSON body.

### 2026.02.16

**New ✨**

* Create [persistent app versions](https://docs.edgegap.com/learn/orchestration/persistence) from dashboard, can only be deployed in [private fleets](https://docs.edgegap.com/learn/orchestration/private-fleets).

### 2026.02.10

**New ✨**

* Measure your deployment total egress with new metric in deployment's metrics history.
* Preview your deployment's public IP address and [webhook](https://docs.edgegap.com/learn/orchestration/deployments#webhooks-and-postbacks) responses in deployment details.

**Improvements 💪**

* Enhanced [v2/deployments](https://docs.edgegap.com/docs/api/dedicated-servers#post-deployments) webhook payloads with:
  * deployment's available resources: `vcpu_units`, `memory_mib` ; and
  * private fleet context: `host_id`, `host_in_private_fleet`, `private_fleet_id`  fields.

{% hint style="success" %}
**Upgrade to v2/deployments today to unlock observability enhancements!** Edgegap's managed services (Matchmaker and Server Browser) use the latest deployment APIs automatically.
{% endhint %}

* Dashboard now indicates when application version changes will reset active caching.
* Updated deployment details dashboard layout to display important information at the top.
* Updated player count metric in dashboard to exclude users from non-ready deployments.
* Separated billing items for Matchmaker, Server Browser, and Clusters for transparency.
* Clarified [pricing page](https://app.edgegap.com/user-settings?tab=memberships) explaining products and services included in each tier.
* Clarified pricing timeline and commitment for private fleets in confirmation modal.

### 2026.01.27

**New ✨**

* Added [dashboard notifications](https://app.edgegap.com/notifications) for Private fleet schedules, with a summary of provisioned hosts.

**Improvements 💪**

* Major improvements for [Deployments in Dashboard](https://app.edgegap.com/deployment-management/deployments/list), making fast scanning more convenient.
* Increased the default deployment list size to 50 for better visibility into recent deployments.
* Improved [Private fleet](https://app.edgegap.com/private-fleet-management/private-fleets/list) schedule date picker to auto-save when clicking outside date picker.
* Added `caching_percent` attribute (always returned) when fetching an [app version with API](https://docs.edgegap.com/docs/api/versioning#get-v1-app-app_name-version-version_name).
* Re-enabled and improved [billing recipients feature in dashboard settings](https://app.edgegap.com/user-settings?tab=general).
* Added timezone indication for [dashboard notifications](https://app.edgegap.com/notifications) to help align multi-national teams.

**Fixed ✔**

* Fixed image tag autocompletion when [creating or editing app version in the dashboard](https://app.edgegap.com/application-management/applications/list).


# Archive

## 2026

<details>

<summary>View Release Notes 2026</summary>

### 2026.01.12

**Improvements 💪**

* Improved messaging on the deployment details page when no [log storage](https://docs.edgegap.com/docs/endpoint-storage/save-container-logs) is configured, displaying a clear explanation instead of a generic error.
* Enhanced container image validation on the dashboard to better prevent the creation of application versions with invalid container images.

**Fixed ✔**

* Fixed an issue where the available credits section on the dashboard incorrectly displayed “Not Available.”
* Fixed the [Out of Memory insights graph](https://app.edgegap.com/analytics/dashboards/list) introduced in the previous release, which was not displaying data correctly.

### 2026.01.07

**New ✨**

* [**Private Fleets**](https://docs.edgegap.com/learn/orchestration/private-fleets) — Reserve and manage your own fleet of persistent servers (bare metal or VMs) across Edgegap locations worldwide via our self-serve platform. Edgegap fully orchestrates your fleet and automatically scales to our regionless cloud when traffic exceeds capacity, optimizing player experience and infrastructure costs.
* [**Server Browser**](https://docs.edgegap.com/learn/server-browser) — Enable players to browse and join persistent servers with ease. Designed for MMOs and social games, it includes game-ready authentication, automated session management with latency optimization, and a scalable private cluster architecture.

</details>

***

## 2025

<details>

<summary>View Release Notes 2025</summary>

### 2025.12.16

**Improvements 💪**

* Added new insights for Deployments Out Of Memory (OOM) in [Analytics](https://app.edgegap.com/analytics/dashboards/list).

**Fixed ✔**

* Added missing [pagination](https://docs.edgegap.com/api#response-pagination) support for [Registry API - listing image tags method](https://docs.edgegap.com/api/versioning#get-v1-container-registry-images-image_name-tags).

### 2025.11.03

**Improvements 💪**

* Added SSO support on the account registration page.
* Improved caching errors for [Deployments in Error](https://docs.edgegap.com/learn/orchestration/deployments#id-4.-deployment-error) for [V2 deployment API](https://docs.edgegap.com/api/dedicated-servers#post-deployments).
* Improved notifications for auto-cleaned [Deployments in Error](https://docs.edgegap.com/learn/orchestration/deployments#id-4.-deployment-error) clarifying no charges were added.
* Improved caching indicator criteria, green caching status is now more reliable.

**Fixed ✔**

* Fixed incorrect browser auto-translation of quick start token.
* Fixed an issue preventing matchmakers or clusters from starting in certain regions.

### 2025.09.11

**New ✨**

* Easily change your organization's owner under [**Settings > Organizations > Manage Roles**](https://app.edgegap.com/user-settings?tab=organizations).

**Fixed ✔**

* Fixed live metrics showing a sum of per-core usage instead of overall percentage.
* Fixed an issue with authentication warning showing on dashboard sign-in sometimes.

### 2025.09.09

**New ✨**

* Link your Discord account for faster support and easier integration.
* Added a new server location in Berlin, Germany.

**Fixed ✔**

* Fixed deployments getting stuck with an empty environment variable and `is_hidden=true`.
* Fixed a bug where a "no login" email was incorrectly sent after a new tier subscription.

### 2025.08.27

**Improvements 💪**

* Dashboard now remembers your signed-in device for 7 days before logging you out.

**Fixed ✔**

* Fixed a bug with deployments not being reused for Sessions after 500x Sessions.
* Fixed an error thrown due to removing endpoint storage from an application version.
* Fixed an error caused by more complex dashboard deployment filters with timestamps.
* Fixed an error with some dashboard notifications not displaying descriptions properly.

### 2025.08.20

**New ✨**

* [Specify your preferred cluster region](https://app.edgegap.com/cluster-management/clusters/list) for private clusters (custom services) through dashboard!

**Improvements 💪**

* Rate limiting alerts are now only sent if exceeded multiple times per minute.
* Updated [Edgegap registry](https://app.edgegap.com/registry-management/repositories/list) URL to `registry.edgegap.com`. Prefix `registry2` kept as an alias.

**Fixed ✔**

* Fixed live metrics errors in deployment dashboard page due to fetching data too early.

### 2025.08.14

**New ✨**

* Specify your preferred matchmaker region for [private matchmaker tiers](https://docs.edgegap.com/learn/matchmaking/matchmaker-in-depth#hosting-cluster) through dashboard! [Change the region of your running cluster](https://app.edgegap.com/matchmaker-management-v2/matchmakers/list) with a stop-start. [Learn more about zero downtime updates.](https://docs.edgegap.com/learn/matchmaking/matchmaker-in-depth#rolling-updates-and-ab-tests)
* Request China mainland region availability for your [app version](https://app.edgegap.com/application-management/applications/list), subject to Edgegap review.

**Improvements 💪**

* [Deployment history metrics](https://docs.edgegap.com/learn/advanced-features/deployments#container-metrics) interval is now 2 minutes, matching the metric aggregation period. Live metrics remain unaggregated with 1 second interval measurements.

**Fixed ✔**

* Fixed missing deployment tags in deployment list and filtering for [Smart Fleets](https://app.edgegap.com/fleet-management/smart-fleets/list).

### 2025.08.07

**Improvements 💪**

* Updated game samples [fishnet-on-edgegap](https://docs.edgegap.com/docs/sample-projects/unity-netcodes/fishnet-on-edgegap "mention") and [unity-netcode-on-edgegap](https://docs.edgegap.com/docs/sample-projects/unity-netcodes/unity-netcode-on-edgegap "mention") for latest Unity 6 LTS.
* Added network metrics legend to deployment live metrics.
* Added security schema to v2 openapi specification to simplify testing.

**Fixed ✔**

* Fixed an internal error in [metrics API](https://docs.edgegap.com/api/dedicated-servers#get-v1-metrics-deployment-request_id) for deployments not reaching [status Ready](https://docs.edgegap.com/learn/orchestration/deployments#id-3.-deployment-ready)

### 2025.07.23

**New ✨**

* Create application versions with up to **4 vCPU and 8 GB of RAM** from dashboard.

**Fixed ✔**

* Fixed an occasional issue with missing data points in deployment details history charts.
* Fixed a bug preventing creating third party registry profiles with a token longer than 1000 characters (e.g., for Google Registry).

### 2025.07.08

**New ✨**

* **Edgegap Container Registry capacity increased to 10 GB for all users**, including free tier!

**Improvements 💪**

* Improved application creation dashboard page user experience.

**Fixed ✔**

* Fixed a bug where the total player count wasn’t displayed correctly on the dashboard homepage in some cases. This represents a sum of all IP addresses and coordinates in deploy requests, including matchmaker deployments.
* Fixed an issue on the new application version page where inputs weren’t pre-filled properly when redirected from the Unity plugin.

***

### 2025.07.02

**New ✨**

* Create and edit app versions more easily, now with automatic input suggestions for containers!
* Filter your [analytics](https://app.edgegap.com/analytics/dashboards/list) reports by application version, to monitor resource usage more easily for versions with varying resource requirements and the same docker image.
* Try our simplified and updated game samples without building servers:
  * Unreal Engine 5.5.4: [lyra-sample](https://docs.edgegap.com/docs/sample-projects/unreal-engine/lyra-sample "mention")
  * Unity 6: [Photon Fusion 2 Asteroids](https://docs.edgegap.com/docs/sample-projects/unity-netcodes/photon-fusion-2-on-edgegap) | [mirror-pong](https://docs.edgegap.com/docs/sample-projects/unity-netcodes/mirror-pong "mention") | [FishNet HashGrid](https://docs.edgegap.com/docs/sample-projects/unity-netcodes/fishnet-on-edgegap)
* Export deployment logs to [endpoint storage](https://app.edgegap.com/endpoint-storage-management/endpoint-storages/list) as newline-delimited JSONs (NDJSON).

**Improvements 💪**

* Updated and improved API specification for [Create Application Version](https://docs.edgegap.com/api/versioning#post-v1-app-app_name-version) and [Update Application Version](https://docs.edgegap.com/api/versioning#patch-v1-app-app_name-version-version_name). No changes have been made to API endpoints request/response payloads.
* Added more hints for [upgrading matchmaker tiers](https://docs.edgegap.com/learn/matchmaking/matchmaker-in-depth#rolling-updates-and-ab-tests) in dashboard.
* View your free credits expiration date in settings.

**Fixed ✔**

* Fixed a bug where deployment tags were not displayed on the archived deployment's detail page.

***

### 2025.06.30

**New ✨**

* **Deploy servers easier, faster, and more reliably than ever** with `v2/deployments` .
  * Matchmaker and engine plugins will be updated shortly to use this API (in a new version).
  * We're keeping `v1/deploy`  functioning for legacy integrations, no changes are required.

**Improvements 💪**

* [Smart Fleets](https://docs.edgegap.com/docs/fleet) now scale up more gradually when started with a high minimum value in policy. You should no longer see errors due to high amount of rapid deployment retries in such scenario.
* Updated [subscription pricing visuals in dashboard](https://app.edgegap.com/user-settings?tab=memberships). No changes have been made to platform pricing.

**Fixed ✔**

* Fixed disabling container log storage by query parameter for [self-stop deployment API endpoint](https://docs.edgegap.com/api/dedicated-servers#delete-v1-self-stop-request_id-access_point_id).

***

### 2025.05.21

{% hint style="success" %}
🚀 **Matchmaker 3.0.0 is here!**

This major update introduces smarter team filling with min/max team size (breaking change), faster and more efficient matchmaking, and improved handling of backfills and latency. [See full changelog...](https://docs.edgegap.com/learn/matchmaking/matchmaker-in-depth#id-3.0.0-may-20-2025)\
\
To upgrade, stop your matchmaker, edit config, and restart. Quick restart won’t apply version updates.
{% endhint %}

**New ✨**

* [**Testing and Releases:**](https://app.edgegap.com/test-and-release-management/test-and-release) You can now schedule releases, playtests, demos, and other key events directly from the dashboard. This gives you access to live support and a dedicated meeting room on your launch day, so you're never alone when it matters most.

**Improvements 💪**

* New matchmakers will now use upgraded Kubernetes version automatically. We'll reach out to notify owners of running matchmakers to schedule updates ahead of time.

**Fixed ✔**

* Fixed a bug where a `label` attribute was incorrectly added to the JSON of pre-configured configurations when creating a matchmaker.

***

### 2025.05.14

**New ✨**

* A warning notice is now displayed when creating or updating an application version using the `latest` Docker tag, which is [strongly discouraged to avoid unpredictable caching behavior](https://docs.edgegap.com/learn/orchestration/application-and-versions#container-parameters-required).
* Review :green\_circle: [available](https://docs.edgegap.com/learn/orchestration/deployments#high-availability) and :blue\_circle: [burstable](https://docs.edgegap.com/learn/orchestration/deployments#high-availability) deployment locations [in dashboard map in real time](https://app.edgegap.com/).

**Fixed ✔**

* Deployment details page now shows all deployment tags (previously showing only 10 results).

***

### 2025.05.01

**New ✨**

* View all associated tags that will be removed when deleting an artifact in [Registry Dashboard](https://app.edgegap.com/registry-management/repositories/list).
* Added a direct “Pay Invoice” link in the [billing section](https://app.edgegap.com/user-settings?tab=invoices) for easier manual payment.

**Improvements 💪**

* [Recent Deployments chart in Dashboard](https://app.edgegap.com/) no longer shows the last incomplete 5 minute interval.
* All table sorting preferences in dashboard are now saved across sessions.
* Removed duplicate deletion messages in dashboard for some edge cases.

***

### 2025.04.28

**New ✨**

* **View live metrics refreshed every 1 second from deployment page!** Troubleshoot and optimize resource usage more easily by monitoring CPU and memory usage in real time.
* **Toggle caching and inspect caching status** easily in your [app versions list dashboard page](https://app.edgegap.com/application-management/applications/list).
* **Prevent slow deployments due to configuration errors** when releasing updates. You will be now [automatically notified](https://app.edgegap.com/notifications) when more than 5 uncached deployments are made within 1 minute.

**Improvements 💪**

* Open recently updated resources' links in dashboard in a new tab with middle-click.
* Improved sign in and sign up layout for a smoother and more intuitive onboarding experience.

**Fixed ✔**

* Fixed a bug where container logs stored on your S3 endpoint were not displayed correctly if the app version name contained special characters on the archived deployment details page.
* Fixed duplicate displaying of logs for some running deployments.

***

### 2025.04.15

{% hint style="success" %}
**Free tier increased to allow** [application-and-versions](https://docs.edgegap.com/learn/orchestration/application-and-versions "mention") **with 1.5 vCPU and 3 GB of memory**, to allow testing more demanding servers (e.g. [Unreal Engine Lyra sample](https://dev.epicgames.com/documentation/en-us/unreal-engine/lyra-sample-game-in-unreal-engine)) before upgrading to pay as you go tier.
{% endhint %}

**Improvements 💪**

* Improved registration and onboarding to provide a smoother experience.
* Improved quick skimming of recent resources - icons are now placed on the left.
* Updated [`/v1/stop/{request_id}`](https://docs.edgegap.com/api/dedicated-servers#v1-stop-request_id) API reference with clearer explanations and refined terminology to make it easier to understand. No changes were made to the actual API endpoint.

***

### 2025.04.10

**New ✨**

* A brand new table is now available on the dashboard home screen! It shows your most recently updated resources—application versions, matchmakers, and clusters—so you can stay on top of what's happening at a glance and jump straight to what matters.

**Fixed ✔**

* Fixed an issue where users registering with an expired invitation link were mistakenly prompted to create an organization. The flow now clearly shows an error if the link is no longer valid.
* Fixed a rare issue where deployment container logs were not visible on the dashboard, even when they should have been.
* Fixed a bug where the caching notification displayed the wrong time format, leading to confusing information.

***

### 2025.04.02

**New ✨**

* Our brand-new analytics section is now live on the dashboard! For Pay-as-You-Go users, gain deeper insights into your running containers with near real-time metrics on vCPU and RAM usage, network bandwidth, and more. Optimize performance and stay ahead with better resource monitoring!

**Improvements 💪**

* You can now sort the versions list for your applications by name on the dashboard, making it easier to organize and manage them.

***

### 2025.03.27

**New ✨**

* Deployment tags are now displayed on the session list page, and you can filter sessions by deployment tags. &#x20;
* We now apply the same validations when starting a matchmaker as when creating one. This change clarifies whether a matchmaker might result in flaky matchmaking due to misconfiguration.&#x20;

**Improvements 💪**

* We've refreshed the [`/v1/deploy`](https://docs.edgegap.com/api/dedicated-servers#v1-deploy) API reference with clearer explanations and improved terminology for better comprehension. No changes were made to the specifications.
* Added visual banners for new users to guide them to the documentation when landing on the dashboard. &#x20;

***

### 2025.03.20

**Improvements 💪**

* The matchmaker creation form has been improved to speed up the creation of new matchmakers using templates. Additionally, changes have been made to ensure ongoing progress is not lost when editing the configuration in the creation modal. We also try to prefill the form with your latest application version when using templates.
* The registration process using invitation links has been improved to automatically use the email provided by the organization owner, ensuring the flow isn't disrupted by a different email during registration.

***

### 2025.03.17

**New ✨**

* [Introducing Self-Healing Fleets](https://docs.edgegap.com/docs/fleet): Edgegap now retries your Fleet deployments in Error up to 5 times every day, if the current deployment count is below your target capacity. [Read more about why your deployment may end up in Error.](https://docs.edgegap.com/learn/advanced-features/deployments#id-4.-deployment-error)

**Improvements 💪**

* Renamed matchmaker dashboard button label to "Force Stop" instead of "Remove" for matchmakers in Error. This action doesn't change your matchmaker URL or Auth token.

***

### 2025.03.05

**New ✨**

* Increased the limit of simultaneous errored deployments for free-tier users from 1 to 10. We observed that some users were hitting the previous limit, which led to a poor experience. This change provides more flexibility when testing deployments on the platform.
* Organization owners can now view pending member invitations on the organization settings page.

**Improvements 💪**

* Added additional validation when creating a matchmaker to help prevent the use of invalid or uncached application versions.
* Reorganized the layout of the organization settings page to improve navigation and make it easier to manage your organization and add members.

***

### 2025.02.19

Hosting for Legacy Managed Matchmaker and [Legacy Advanced Matchmaker](https://docs.edgegap.com/learn/advanced-features/managed-clusters) has been deprecated and is no longer available in the API or dashboard. See [Gen2 Managed Matchmaker](https://docs.edgegap.com/docs/release-notes/broken-reference) or [Advanced Matchmaker on Managed Clusters](https://docs.edgegap.com/learn/advanced-features/managed-clusters#advanced-matchmaker) for our latest generation of matchmaking products.

**Improvements 💪**

* Made the quick restart button for the matchmaker more visible on the dashboard.
* Improved the display of credentials used for pushing images on the registry page.

**Fixed ✔**

* Fixed a bug where the same application version name could be used when duplicating an application version on the dashboard.
* Fixed a bug where certain content, such as tokens, environment variables and container requirements, was incorrectly translated by browser auto-translate features.

***

### 2025.02.12

**New ✨**

* We've redesigned the sidebar layout on the dashboard to make it more user-friendly and easier to navigate.

**Improvements 💪**

* Made further improvements to the matchmaker readiness validation when starting a Gen2 matchmaker, reducing the likelihood of errors during deployment.
* Improved the homepage layout with a smoother loading experience and better element transitions.

**Fixed ✔**

* Fixed a validation issue where uppercase characters could be used in the application version container configuration. This change now enforces lowercase characters only.
* Fixed a bug where the deployment time remaining displayed on the dashboard was inaccurate in some cases.
* Fixed a bug where the matchmaker Swagger documentation was not regenerated after a configuration update.

***

### 2025.02.06

**New ✨**

* We've added a locking mechanism that prevents the deletion of an application version if it is currently in use by a matchmaker. This change applies to both the API and the dashboard.

**Fixed ✔**

* Fixed inconsistencies in the API specifications.

***

### 2025.01.30

**Fixed ✔**

* Fixed an issue where refreshing the matchmaker details page on the dashboard would result in a 500 error.
* Fixed an occurrence where the cache for certain app versions could be disabled when communication with Docker was unreliable.
* Fixed a bug where the beacons list from the API could include duplicate cities.

***

### 2025.01.21

**New ✨**

* We've added more locations to our network, providing greater coverage and improved performance for your deployments.

**Improvements 💪**

* Enhanced the management of default registry profiles for better clarity.

**Fixed ✔**

* Fixed a bug where the container registry page displayed "Invalid DateTime" instead of the actual date in the last pull/push section.
* Fixed a bug on the app version details page where the caching progress always displayed as "low (red)" even when the actual coverage was "high (green)."

***

### 2025.01.15

**New ✨**

* When using a [Docker registry profile](https://docs.edgegap.com/learn/orchestration/application-and-versions#container-parameters-required), creating a new app version will automatically fetch the available images and tags from your repository for selection.
* [Deployment environment variables](https://docs.edgegap.com/learn/advanced-features/application-and-versions/#other-parameters-optional) can now be up to 4KB in size.

**Fixed ✔**

* Fixed an issue where the plugin for initializing the container registry did not work and failed to provide proper access.
* Corrected the return status code from 401 Unauthorized to 400 Bad Request when sending an overly long environment variable in a deployment request.
* Fixed a layout issue on the dashboard across multiple pages.
* Fixed the matchmaker Gen2 startup flow to reduce potential errors during deployment.

***

### 2025.01.13

{% hint style="info" %}
From this release, the API will enforce a CPU/Memory ratio of 1:2. This change aims to keep costs as low as possible for everyone and improve the orchestration of resource usage across all users.
{% endhint %}

**New ✨**

* You can now use application environment variables up to 4KB in size.
* Our Mava AI chatbot is now available in dashboard, in addition to Discord, allowing access from multiple locations.
* We've added a new heatmap to app version details displaying the balance points of your deployment requests.
* The homepage map now displays our available beacons.
* We've added an option to perform a quick restart of your Gen2 matchmaker without needing to change anything in the configuration. Note that this will delete all current tickets and temporarily make the API inaccessible.

**Improvements 💪**

* The relay page now displays the status of your relay sessions.
* Adding tags from the dashboard now uses the same validation as the API, allowing a greater range of values.
* Improved the matchmaker readiness validation when starting a Gen2 matchmaker, reducing false positives where the status displayed as ready but the matchmaker was still unreachable for a short time.
* Accelerated the reload time for a Gen2 matchmaker.
* Made backend optimizations to the dashboard for a slightly faster experience. If you encounter unexpected errors on certain pages, please let us know via our [Discord](https://discord.com/invite/NgCnkHbsGp).

**Fixed ✔**

* Fixed an issue where metric charts sometimes did not display on the deployment details page.
* Fixed an issue where session sockets used always displayed as 0, even when sessions were present in the deployment details page under the session tab.

**Documentation 📚**

* new: [Unreal Engine learning center](https://docs.edgegap.com/docs/release-notes/broken-reference) - [Developer Tools](https://docs.edgegap.com/unreal-engine/developer-tools) and [Getting Started with Servers](https://docs.edgegap.com/unreal-engine)
* updated [Gen2 Unity SDK documentation in Unity Developer Tools](https://docs.edgegap.com/unity/developer-tools#matchmaking-sdk)
* added [Advanced Example configuration to Getting started with Gen2](https://docs.edgegap.com/docs/release-notes/broken-reference)
* added and updated example requests/responses for [Gen2 Matchmaker In-Depth](https://docs.edgegap.com/learn/matchmaking/gen2-matchmaker-in-depth)
* added and updated tips for using [Ping Beacons](https://docs.edgegap.com/learn/orchestration/ping-beacons)

</details>

***

## 2024

<details>

<summary>View Release Notes 2024</summary>

### 2024.12.09

{% hint style="info" %}
Match Players & Launch Games Instantly, the Easy Way

Edgegap’s “Gen 2” Matchmaker is now out of Early Access! What might warrant such a change, you might ask?

**New, Powerful Features!**

Joining the region-less, latency-based matchmaking (the only matchmaker with this feature, that we are aware of) and team matchmaking, we have:

* [Automated Backfill](https://docs.edgegap.com/docs/release-notes/broken-reference): Upon (popular) request, we’re adding backfill with automated ticket assignment, which allows you to reuse server seats when players leave the session.
  * Ideal for filling empty player seats after a match has begun, or for replacing players that have left during a match.
* [Group Matchmaking](https://docs.edgegap.com/docs/release-notes/broken-reference): We’re adding the ability to join as a group to the already available ability to fill multiple teams with players.
  * Ideal for joining up in a matchmaking queue with a group of friends or coming from a common lobby.
    {% endhint %}

**New ✨**

* The dashboard now enforces a minimum of 1/4 vCPU when creating an application version. This change aims to reduce integration issues observed with smaller instances and improve first time user experience. If you need access to smaller increments, please contact us.
* The API now enforces a minimum of 1/4 vCPU when creating an application version. **Users previously using smaller instances will not be affected by this change.** If you need access to smaller increments, please contact us.
* We've added a warning message when updating the maximum duration of an application version. Changing this value can cause running deployments to be immediately stopped.
* You can now edit your configuration while the matchmaker is running. This triggers a quick reload of your configuration without requiring a full on/off cycle for your matchmaker. Note: This feature is not recommended for production environments, as it deletes all current tickets and temporarily makes the API unresponsive.

**Improvements 💪**

* The minimum size for Matchmaker Gen2 has been reduced to 1 CPU & 2GB of Memory, and it's pricing has been decreased to $0.0312/hour. This change lowers costs for development and testing environments.
* We've improved the flow for organization invitations when the invited user is already registered on the platform.
* We've improved the matchmaker Gen2 health status to prevent false positives.

**Fixed ✔**

* Fixed a bug where relay sessions were not automatically deleted when players timed out or disconnected from the relay.
* Fixed a bug where the disable option for an application wasn't preventing deployments from being created.
* Fixed a bug with the deployment metric charts that caused them to display incorrect data on the dashboard.

**Documentation 📚**

* We've fixed the search bar to work in the Learning Center as well.
* Added documentation for the new matchmaker Gen2 features: [Automated Backfill](https://docs.edgegap.com/docs/release-notes/broken-reference) and [Group Matchmaking](https://docs.edgegap.com/docs/release-notes/broken-reference).

***

### 2024.11.21

**New ✨**

* We've added functionality to request our new Premium Consultation Service, available through the user modal on the dashboard.
* Starting from this release, application versions that don't use caching will be deployed on a subset of locations. As a result, your deployments without caching activated may be further away than before. This change has no effect on cached deployments. This is part of our effort to optimize resource usage and provide a better service to all users.
* The dashboard home page now displays a new announcement box at the top to keep you informed of important updates and changes.
* We've added a progress bar to the matchmaker Gen2 creation and removal process to give you a better idea of the time remaining.
* You can now save credentials from external container registries and use them as default credentials when creating a new application version on the dashboard. This feature will be integrated with our plugins in the future. Default credentials are also working with our registry.
* We've added a button to copy your request ID on the deployment page. This feature will help you provide the necessary information when contacting support.
* To improve user experience, all application versions must now have a set maximum time to live (TTL) of 24 hours. While this maximum TTL has been enforced internally since the 2024.09.09 release, this change makes it visible on the dashboard, reducing confusion about deployments being deleted unexpectedly.
* You can now use filters in the list deployments API route to filter deployments. Some of the available filters are status, version, request ID, tags, and more. Documentation will be updated soon with additional details.
* We've added an [API route to delete a lobby](https://docs.edgegap.com/docs/api).
* We've added an [API route to list all lobbies](https://docs.edgegap.com/docs/api).

**Improvements 💪**

* Whitespace is now supported in the creation of organization names.
* Updated lobby name validation to prevent unexpected release errors.
* We now support S3 buckets from AWS, alongside most other S3-compatible storage services already supported.

**Fixed ✔**

* Fixed a UI bug on the deployment page where using a large number of tags would break the layout.
* Fixed a bug where making an API call to a lobby soon after creating it would return a 503 Service Unavailable error.
* Fixed a bug where some individual port environment variables were not injected properly into the deployment's container.
* Fixed a bug where dashboard deployment logs did not display detailed error messages when a deployment failed.
* Fixed a bug where application versions ports would be deleted unexpectedly when updating the application version.
* Fixed a bug that caused session and relay session creation to be slower than expected.
* Fixed a bug where it was impossible to delete a Gen2 matchmaker when too many errors had occurred when releasing it.

**Documentation 📚**

* Added an [Unreal Top-Down](https://docs.edgegap.com/docs/sample-projects/unreal-engine/top-down-sample) sample project.
* Consistency fixes for the Gen2 matchmaker documentation.
* Updated the Learning Center with new content and minor consistency improvements.

***

### 2024.10.30

**New ✨**

* You will now receive a dashboard notification when you reach an API rate limit. This notification helps you avoid unexpected behavior when interacting with the API and alerts you to potential issues and unexpected costs.
* You can now filter your deployments by city, country, and continent on the dashboard.
* Matchmaker Gen2 JSON errors are now more descriptive and easier to understand when creating or updating a matchmaker.
* The JSON configuration editor for the Gen2 matchmaker now supports copy-pasting, undo/redo, collapse/expand, JSON error highlighting, and auto-correction.

**Improvements 💪**

* We’ve improved the private matchmaker creation process to make it more user-friendly and intuitive. The flow for creating and deleting a private matchmaker will be slightly longer, but we plan to add a reload feature, allowing you to change your configuration without having to stop and start the matchmaker.

**Fixed ✔**

* Fixed a bug with the application version bulk delete feature that was not functioning correctly on the dashboard.
* Fixed a bug in which the maximum deployment time was not correctly applied when deploying an application version with caching disabled.
* Fixed a bug where the dashboard validation for endpoint storage was returning false positives for misconfigured buckets.

**Documentation 📚**

* We've introduced our new [Learning Center](https://docs.edgegap.com/learn), where you can find all the resources you need to get started with Edgegap.

***

### 2024.10.08

{% hint style="info" %}
Matchmaker Gen2 We still ironing out bugs and adding new features to our Matchmaker Gen2. We now have a dedicated changelog for it, which you can find \[here]\(/docs/gen2-matchmaker-changelog).
{% endhint %}

**New ✨**

* The dashboard will set the maximum duration for deployment to 60 minutes by default when creating a new application version. This change will help prevent unexpected costs. You can still adjust the duration to your needs.

**Fixed ✔**

* Fixed an issue with lobbies where they would not start correctly and return an error message when getting the status.
* Fixed the average deployment time section on the dashboard's home page that was sometimes displaying an error message.

***

### 2024.09.25

{% hint style="info" %}
Matchmaker Gen2 Our new Matchmaker Gen2 is now live and available to everyone! You can access it directly through the dashboard in the same place as the previous matchmaker.

This latest version offers increased flexibility and control over your matchmaking process, all while being easier to use. You can start by creating matchmakers on our free cluster for early testing, and then seamlessly transition to your own dedicated cluster for live games or uninterrupted testing.

Matchmaker Gen2 is currently in early access until we fully phase out the previous version, and we’re super excited to have everyone onboard! Check out our [documentation](https://docs.edgegap.com/docs/release-notes/broken-reference) to get started, and don’t hesitate to share your feedback with us on [Discord](https://discord.com/invite/NgCnkHbsGp).
{% endhint %}

**New ✨**

* We are introducing a "bring your own DNS" feature. This will allow you to use your own domain name for your deployments. This feature is currently in early access, if you are interested in testing it, please reach out to our support team.
* Effective with this release, we will now delete protected deployment after a period of 48h.

**Improvements 💪**

* Our plugin for Unity has been updated and is now available on the [asset store](https://assetstore.unity.com/packages/tools/network/edgegap-game-server-hosting-212563).

**Fixed ✔**

* Fixed some color formatting issues with the session logs on the dashboard.

***

### 2024.09.09

{% hint style="info" %}
We’ve begun our closed BETA for Matchmaker Gen 2! This new version is a complete overhaul of the current managed matchmaker, offering greater flexibility and control over your matchmaking process.
{% endhint %}

{% hint style="success" %}
Resource Management To improve resource management and help prevent unnecessary costs on your end, we'll now automatically close deployments that run for over 24 hours. If you need a deployment to stay active longer, let us know and we'll be happy to assist.
{% endhint %}

**New ✨**

* Empty relay sessions will now automatically delete after 10 minutes. This change helps manage resources more efficiently and reduces the amount of code needed to manage your relay sessions.

**Improvements 💪**

* The container registry page on the dashboard now correctly displays repositories with subfolders.
* The registry management API endpoints now support repositories with subfolders.
* When creating a new session-type application version, the auto-deploy feature will now be enabled by default. This should reduce confusion around the deployment process. You can still disable auto-deploy if your workflow requires it.
* We've added more locations to our network to provide even more coverage and better performance for your deployments.

**Fixed ✔**

* Fixed a bug where some locations were not displayed correctly on the deployment details page when they were deleted. This occurred with older terminated deployments.
* Fixed a small UI bug with the form inputs on the dashboard.

**Documentation 📚**

* Added an info box on using the `X-Real-IP` header in ticket creation when using the managed matchmaker ([doc](https://docs.edgegap.com/docs/release-notes/broken-reference)).
* Fix the injected selector example in the managed matchmaker configuration ([doc](https://docs.edgegap.com/docs/release-notes/broken-reference)).

***

### 2024.08.13

**New ✨**

* You can now delete your relay session directly from the relay details page on the dashboard.
* We've added a feature for the **relay session** to automatically detect when your players are disconnected and remove them from the relay session. This feature will help you manage your sessions more efficiently. We will add a feature to delete empty sessions automatically in the near future.
* Lobbies will now automatically close after 3 hours for free tier users. This change will help manage resources more efficiently and ensure optimal performance for all users.

**Improvements 💪**

* The default deployment port verification timeout has been increased to 30 seconds. This change will not make your deployment process longer but will prevent errors for customers with longer boot times for their containers.
* We've reenabled the Oauth login for the dashboard. This change will allow you to use your Google or GitHub account to log in to the dashboard.

**Fixed ✔**

* Fixed an issue where using an invalid IP would break the deployment details page on the dashboard.
* Fixed an issue where the sessions tab inside the deployment details page could not be accessed.
* Fixed an issue where tooltips and guided tours on the dashboard were not working correctly upon refreshing the page.
* Fixed an issue causing longer than expected loading times for the login page on the dashboard.

**Documentation 📚**

* Expanded documentation for sessions management with Fishnet netcode integrations ([doc](https://docs.edgegap.com/docs/sample-projects/unity-netcodes/fishnet-on-edgegap)).
* Expanded documentation for sessions management with Mirror netcode integrations ([doc](https://docs.edgegap.com/docs/sample-projects/unity-netcodes/mirror-on-edgegap)).
* Added more warnings and troubleshooting steps for the managed matchmaker sample configuration.
* Added more insights into the Lobby service compatibility with our services .
* Added step to set autodeploy to true when using the managed matchmaker.

***

### 2024.07.24

**New ✨**

* We now provide both IP and FQDN of our beacons when listing them. This will allow you to choose between the two options when coding your integration. We are introducing a permissive rate limit for the API. This change aims to ensure fair usage and maintain optimal performance while providing flexibility for most use cases.

**Improvements 💪**

* We've tweaked the memory usage chart on the dashboard and the API to provide more accurate data when the RAM is spiking. This will help monitor potential issues and optimize your deployments.
* We've removed the automatic creation of the demo application when using the initialization button on our plugins. This behavior was causing confusion and issues when mixed with our free tier limitations.
* Small consistency improvements on the dashboard UI.
* Improved monitoring of our locations to ensure the best performance for your deployments.

**Documentation 📚**

* Added an example for seat sessions management with Fishnet netcode integration ([doc](https://docs.edgegap.com/docs/sample-projects/unity-netcodes/fishnet-on-edgegap))

***

### 2024.07.11

**Improvements 💪**

* We updated our internal application used for the ping beacons. This update uses a more performant language, ensuring minimal application overhead for the most accurate latency measurement. Usage still remains the same, and no changes are required on your end.
* We updated the pricing page on the dashboard to match the pricing page on our website. This update includes a more detailed breakdown of the features available in each tier.

**Fixed ✔**

* Fixed an issue where creating a oneClick token with the dashboard would generate the token correctly but not display it properly within the creation modal.

**Documentation 📚**

* Added example for seat sessions management with Mirror netcode integration ([doc](https://docs.edgegap.com/docs/sample-projects/unity-netcodes/mirror-on-edgegap)).

***

### 2024.07.03

{% hint style="warning" %}
**Notice to all Matchmaker users:** As part of our ongoing efforts to enhance our infrastructure, we will be transitioning the matchmaker clusters to a new provider. This change is necessary to ensure better performance and reliability for your services.

To facilitate this transition, you will need to re-release your matchmaker. The URL will remain the same, so no changes are required on that front. Please note that there will be a brief downtime of approximately 5 minutes during this process.

If you wish to perform the migration using an A/B strategy, you can simply start a new matchmaker. It will be on the new cluster with a new URL. Once you replace the URL in your game clients, delete the old one. This approach minimizes any potential disruption and ensures a seamless transition.

**Deadline: Please complete this transition by Friday, the 12th of July. After this date, we will re-release all matchmakers still running on the old provider.**
{% endhint %}

**New ✨**

* We've added pagination to the artifacts list on the container registry page, making it easier to view all your images.
* We've added API routes to get and delete image tags from the container registry, allowing you to manage your tags directly from your scripts, CI/CD, or applications.

**Fixed ✔**

* Fixed some unexpected behavior with pagination on the dashboard tables.

**Documentation 📚**

* Updated PlayFab matchmaker bridge documentation for Edgegap integration. ([doc](https://github.com/edgegap/docs-gitbook/blob/main/docs/playfab-bridge/README.md)).
* Documentation for deleting artifact tags via API ([doc ](https://github.com/edgegap/docs-gitbook/blob/main/docs/container/edgegap-container-registry/README.md#delete-build-artifacts-via-api), [API](https://github.com/edgegap/docs-gitbook/blob/main/api/README.md#tag/Container-Registry)).
* Added common error warning in the Fishnet integration example ([doc](https://github.com/edgegap/docs-gitbook/blob/main/docs/sample-projects/fishnet-on-edgegap/README.md#configure-the-client-build)).
* Updated documentation links for netcode integrations with our relays ([doc](https://github.com/edgegap/docs-gitbook/blob/main/docs/distributed-relay-manager/README.md#getting-started)).

***

### 2024.06.27

{% hint style="info" %}
A brief notice about our current release cycle: We are currently working on a major update to our matchmaker, focusing our efforts on improving performance, flexibility, and reliability. We're also introducing new features to make creating custom matchmaker rules easier. This explains the slower than usual amount of feature releases you might have noticed.

We aim to release this update in the next quarter. Stay tuned for more information.
{% endhint %}

**New ✨**

* Day by day billing is now available for all organizations. You can now see the cost of your deployments on a daily basis. This feature is available on the billing section of the settings page.
* Relay users are now automatically removed from the session when the relay detects a player has disconnected.

**Fixed ✔**

* Bug where the container logs download file was not correctly generated on the deployment details page.
* Bug where free tier users could not use the sessions with our matchmaker.
* Bug with the removal of a user when a lobby is started.

***

### 2024.05.06

**New ✨**

* The organization owner can now enable two-factor authentication (2FA) for all members of the organization. Once enabled, all members will be required to set up 2FA on their next login.
* We've added a bulk delete option for application versions on the dashboard. You can now select multiple versions and delete them simultaneously.

**Improvements 💪**

* The repository list on the registry page is now paginated.

**Fixed ✔**

* Bug where egress unit was not correctly displayed on the relays charts.
* Bug where the one-to-one port mapping option was not correctly displayed on the port creation form.

***

### 2024.04.29

**New ✨**

* An option is now available to automatically scroll to the bottom of the container logs on the deployment details page.

**Improvements 💪**

* Previously, the `verify_image` option could only be applied to the API route for creating an application version. Now, you can also use it with the API route for updating an application version.

**Fixed ✔**

* Fix a bug where applying a filter on dashboard table would remove the current pagination setting.
* Fix a bug where it was not possible to delete an image from the dashboard repository page when there is multiple images for a same tag.

***

### 2024.04.03

**New ✨**

* See your upcoming billing cycle amount due directly on the dashboard. This feature is available for organization owners on the billing section of the settings page.
* You can now filter the deployment list by tags directly on the dashboard. The API version will be available soon.
* You can now distinctly choose between displaying your current players or Edgegap locations on the homepage map. We're currently working to make it available for your deployments as well.

**Improvements 💪**

* Enhanced clarity in the matchmaker component form fields for better usability.
* Provided additional insights into the subsequent steps after creating a one-click token for plugins.
* Implemented various minor UI enhancements across the dashboard to improve the first-time user experience.

**Fixed ✔**

* Resolved several minor issues with layouts and forms across the dashboard.

***

### 2024.02.29

**New ✨**

* Owners of organizations can now add additional recipients to billing emails. This feature is available on the general settings page.
* You can now select a default landing section for the deployment details page. Choose between the map, details, container logs, and charts sections to be the first one shown when opening the deployment details page.

{% hint style="info" %}
The \`inject\_context\_env\` option in application versions will be deprecated since context will be injected by default in all deployments. These variables are prefixed with \`ARBITRIUM\_\` and are available in the environment of the container. This will not change any behavior and **will be transparent** to the user.&#x20;
{% endhint %}

**Improvements 💪**

* Updated messaging around relay add-ons on the tier subscription page to better explain the key differences between them and our authoritative servers offering.
* Added a warning to inform users that the dashboard is less optimized for mobile devices.
* Registry credentials will now be auto-filled when creating a new application version on the dashboard if you use our registry, making the process faster and less error-prone.

**Fixed ✔**

* Fixed a bug where multiple `one-click` tokens could be created instead of using the existing one with plugins.
* Fixed a bug in matchmaker environment variables where value validation was too strict. Key and value are now validated based on POSIX standards.
* Fixed a bug where creating a session with too many users for the available socket count with the dashboard wizard would fail without proper error message.
* Fixed a bug where the colors of charts on the deployment details were not as expected.

***

### 2024.02.19

#### Special Announcement ❗

{% hint style="info" %}
Users on the Free Tier now have access to 1 CPU for their deployment, up from 0.5 CPU. Along with this change, we're also introducing a 1-hour max deployment time for Free Tier users.

These changes are being introduced to make sure Free Tier users can quickly test more resource-intensive game servers on Edgegap and to ensure these resources are used more efficiently on our infrastructure.

Our self-serve plans continue to offer unlimited deployment time. For more details, explore each option's expanded capacity and features on our pricing page. [View Tiers](https://app.edgegap.com/user-settings?tab=memberships)
{% endhint %}

**New ✨**

* Additional onboarding questions to help us better understand your needs and provide a more tailored experience.
* The remaining time of a deployment will be shown on the deployment details and deployment list page when applicable.
* Button to create a deployment from the home page.
* Terminate multiple sessions directly from the session list page.

**Improvements 💪**

* Added more guidance when container validation fails during application version creation.
* Added more guidance for application version credentials during application version creation.
* Added more guidance to create container log storage from the deployment container logs section.
* Added more explanation to the application version port creation modal to help users better understand the process.

**Fixed ✔**

* Unexpected behavior on the deployment details page when using the back button.

***

### 2024.02.01

**New ✨**

* View the current caching status of your application versions on their details page.
* Terminate multiple deployments directly from the deployment list page.

**Fixed ✔**

* Bug where the deployment details page chart, logs, and container logs were not loading correctly in some cases.
* Smaller bugs and UI improvements across the dashboard.

***

### 2024.01.23

**New ✨**

* The modal to create policies on the fleet management page is now showing the available locations to deploy your servers.
* You can now duplicate an existing application version from the dashboard, including the ports and environment variables.
* You will now see at a glance on the dashboard homepage if you have any deployment in error.
* The application version creation page is now showing your available images if you use the Edgegap Container Registry.

**Improvements 💪**

* Colors standardization for a better experience on both light and dark mode.
* Modal standardization, they will now be using the same format across the dashboard to improve the user experience.
* Standardized the registry access request email to be more in line with the other emails sent by the dashboard.

**Fixed ✔**

* Bug where you could not update the port of an application version. Note that you still cannot update a port when one or more deployment are running.
* Fix a typo in the pull command on the Edgegap Container Registry page.

</details>

***

## 2023

<details>

<summary>View Release Notes 2023</summary>

### 2023.12.13

**New ✨**

* The invoice will now include a summary of the egress and vCPU usage (grouped by size) for the month.
* We will send a notification to your dashboard notification center when there's a deployment we can't cache due to misconfiguration.

**Improvements 💪**

* Improved the homepage "Average Deployment Time" statistic to reflect the last 24 hours of deployments instead of the current live deployments.
* You can now update your application and version names directly from the dashboard.
* Minor UI tweaks to the dashboard for consistency and clarity.

**Fixed ✔**

* Resolved a bug that caused padding issues with the "Recent Deployment" chart when resizing the homepage.

***

### 2023.12.05

**New ✨**

* We've added JSON snippets on multiple object creation within the dashboard to help you integrate faster with our API.
* A button to delete your deployment within the deployment list to help you manage your deployments faster.
* Added a button to create deployment from the deployment list. You will be able to select a specific application version.

**Improvements 💪**

* Added more locations to deploy your applications.
* You can now click on your application version name to access the application version details page quicker from the deployment details page.
* Added a new call to action on many pages displaying a list of objects. The call to action will be displayed when the list is empty.
* The deployment and session modals have received some UI tweaks to be more consistent with the rest of the dashboard. It also displays a button to create a new application version if you don't have any.

**Fixed ✔**

* Fixed a small bug where the organization name was not displayed correctly on the dashboard navbar.
* Fixed some weird loading behavior on the dashboard login and account creation.
* Fixed a bug where sometimes the dashboard was displaying two different pages at the same time.
* Fixed a bug where some pages on the dashboard were scrollable when they shouldn't be.

***

### 2023.11.29

**New ✨**

* Button to delete your artifacts from the container registry on the new dashboard.
* Create an account with your Google or GitHub account on the new dashboard.

**Improvements 💪**

* Optimization with the caching to prevent our system from automatically turning off the cache option on an invalid application version repository and image configuration.
* Insights on the new dashboard when your application version container image validation fails.

***

### 2023.11.14

**New ✨**

* Container registry access requests now get auto-approved after successful validation.

**Improvements 💪**

* Minor tweaks on the new dashboard.
* Various backend optimizations to continuously improve the experience when deploying your game servers.

**Fixed ✔**

* Bug preventing the editing of registry username or token on the dashboard.
* Bug causing relay sessions to end up in unintended locations or fail without clear reasons.
* Bug in the API where application version names could be empty.

***

### 2023.10.25

We are back with another monumental release 🎉, and this time we are filling in the missing pieces to provide you with a holistic dashboard experience. Your patience and feedback have been invaluable, and we are thrilled to unveil the newly incorporated features. These additions are designed to empower you with more control and insight over your orchestration processes. Let’s dive into what’s new!

**New ✨**

* **Matchmaker Integration:** Optimize player experiences with our enhanced matchmaking capabilities now available right from the dashboard. Tailor matchmaking processes with configurable rulesets to meet the unique needs of your player base.
* **Sessions Management:** Monitor and manage your sessions directly from the dashboard, providing you with real-time insights into player interactions. Leverage robust filtering options to sift through session data effortlessly, making deployment management a breeze.
* **Smart Fleets:** Manage your fleets more intelligently with the new UI integrations, ensuring optimal resource allocation and performance. Gain a clear view of your fleet's status and performance with real-time metrics and interactive graphs.

**Coming Soon 🕒**

* **OneClick Plugin:** With just a click, deploy your game servers directly from Unity and Unreal game engines using our OneClick plugin. This integration aims to streamline the process.
* **2F Auth & SSO Integration:** Enhance your security posture with Two-Factor Authentication and Single Sign-On capabilities, coming soon to the dashboard.
* **And More:** Stay tuned for more updates as we continually strive to refine and expand our offerings based on your feedback.

We are dedicated to providing you with a powerful, user-friendly dashboard, and these updates mark a significant stride towards that goal. Your continuous feedback is a cornerstone of our development process, and we eagerly await your thoughts on these new features.

As always, thank you for your trust and partnership. Happy deploying!

***

### 2023.09.26

This release introduces a new UI interface for our Container Registry Connector and adds invoice management to your user settings. We're also excited to preview upcoming features: Smart Fleets and Sessions will soon be accessible via the UI.

**New ✨**

* **Container Registry Connector:** Now available in the new dashboard. Offers a privately managed container repository with enhanced security, connection scans, and more.
* **Invoices in User Settings:** Users can now manage and view their invoices directly from their settings.

**Coming Soon 🕒**

* **Smart Fleets:** Manage your fleets more intelligently, soon to be available in the UI.
* **Sessions:** Monitor and manage your sessions directly from the UI, coming soon.

***

### 2023.08.23

🎉 **We're thrilled to announce the release of the completely revamped Dashboard!**

It's been a while since our last release notes, and we want to take a moment to explain why. Our team has been working tirelessly on this major overhaul, focusing on delivering a set of groundbreaking features and improvements. This extended development period has allowed us to ensure that every aspect of the new dashboard meets our high standards of quality and innovation. This marks the beginning of a new journey as we fine-tune and add awesome features. We've poured our hearts and minds into this project, and we're eager to share the outcome that will undoubtedly elevate your orchestration management experience.

**Major Enhancements**

**Enhancing Speed, Control, and Insight 🚀**

* **Lightning-Fast Experience:** The new dashboard has been completely restructured with a cutting-edge framework, bringing you a lightning-fast user experience. This pivotal upgrade considerably reduces loading times, helping you manage your Deployments and Applications with unprecedented efficiency.
* **Advanced Sorting and Filtering Options:** Enjoy greater control and flexibility with our advanced sorting and filtering options for your Deployments and Applications. This optimized functionality will allow you to pinpoint exactly what you need, freeing up more time to focus on improving your applications.
* **Real-Time Metrics and Graphs:** The console now integrates real-time metrics and interactive graphs, providing a clear view of the status and performance of your Deployments and Applications. These powerful tools will assist in your decision-making and development.
* **Deployment History:** We're introducing the ability to sort and filter past deployments, providing you with a streamlined way to navigate through your deployment history. This feature will empower you to find the information you need quickly and efficiently.

**Distributed P2P Relays 🗼**

We're introducing Distributed Relays, an innovative distributed peer-to-peer relay network. This exciting feature raises the bar by enhancing application performance and network reliability. While the relay system itself will function regardless of the console via the API, the metrics and graphs associated with it are exclusive to the new Console.

**Endpoint Storage 🗃️**

Your container logs are now securely stored in remote S3 buckets, ensuring that logs that would previously be deleted are now saved. This robust and scalable solution enhances log management and accessibility.

**Revamp to Organization and Billing 💼**

Managing your organizations and billing has never been easier. For users who upgraded in the old dashboard, you'll be pleased to know that you are grandfathered into that membership. However, switching to the new billing system could potentially lower your costs, providing an opportunity for savings. Contact our support team to transfer applications between organizations, and enjoy a more transparent and user-friendly billing experience.

**Coming Soon**

**New Features and Enhancements 🎮**

* **Matchmaker**: Enhanced matchmaking capabilities for optimal player experiences.
* **Container Registry**: A privately managed container repository that works much like standard public container registries, but with the added benefit of increased security, vulnerability scans, and other goodies!
* **Smart Fleets**: Previously only available through the API, now accessible through the UI.
* **Sessions**: Previously only available through the API, now accessible through the UI.
* **2F Auth & SSO**: Increased security with two-factor authentication and single sign-on.

We're continuously working on new features and improvements to provide you with the best possible experience. Stay tuned for more updates and exciting announcements in the near future!

Your feedback is vital to our ongoing development, and we encourage you to share your thoughts and suggestions with us. 💡

Thank you for your continued support and partnership. Happy deploying! 🙏

The Edgegap Team

***

### 2023.05.16

**New ✨**

* You can now add and remove tags to your deployment using the API. Additionally, you have the option to tag from within your deployment's container. It was previously only possible to tag from the dashboard and at the start of the deployment request. To learn more about this new feature, please refer to [this documentation](https://github.com/edgegap/docs-gitbook/blob/main/docs/deployment/tags/README.md).
* You now have access to more robust filtering options for sessions and relay sessions, which function in a similar manner to the deployments filter.

**Improvements 💪**

* Added new locations to deploy your applications.

**Fixed ✔**

* A correction has been made to address a mismatch in the locations. Certain locations were erroneously identified as "United States" instead of the accurate designation "United States of America."

***

### 2023.04.18

**New ✨**

* A feedback tool is available on almost all pages of the documentation. You can now tell us whether the information you just read was helpful or not.
* We are excited to announce a new way to deploy on the edge with Edgegap distributed relays. With this update, you can now deploy relay sessions across multiple locations in our infrastructure, providing you with all the benefits of the Edgegap solution, including low latency, scalability, and easy integration. To learn more about this new feature, please refer to [this documentation](https://github.com/edgegap/docs-gitbook/blob/main/docs/distributed-relay-manager/README.md).

**Improvements 💪**

* Deployments and sessions that are in an error status will be automatically deleted after a certain period of time. Currently, this is set to occur after 24 hours. Deployments or sessions in error do not have any live games or applications running, so users will not be disconnected from any server.

***

### 2023.03.07

**Improvements 💪**

* We have increased the maximum termination grace period from 180 seconds to 3600 seconds, allowing more time for post-delete processes to complete. Please note that this extended time period will be billed, even if the deployment is in a terminating state, as compute resources are still in use during this time.

**Fixed ✔**

* Bug in which the "Contact Us" button on the login page was not functioning properly, instead redirecting users back to the login page.
* Bug where, when specifying container logs storage during application version creation through the API, the storage was associated but not activated by default. As a result, users had to manually activate it using the dashboard form.

***

### 2023.01.17

**New ✨**

* Documentation has been restructured. We aim to make integration and search for core components of the Edgegap solution easier.

**Fixed ✔**

* Bug with the Container Registry page on the dashboard where you couldn't see your images if you previously pushed the same tag twice.
* The `kind` in the `session_config` key of the body of an application version creation response with the API will now be `Seat` instead of `seat` to be consistent with the parameter needed for the creation.

</details>

***

## 2022

<details>

<summary>View Release Notes 2022</summary>

### 2022.12.06

**New ✨**

* Organization Admins now have access to the approximate cost for the month on the billing page.

**Improvements 💪**

* API Documentation has been updated with relevant titles for all the routes.
* Added more locations to deploy your applications.
* Our documentation for the Unity plugin has been updated according to the last version.

**Fixed ✔**

* Bug where the deployment details page was sometimes returning a 500.

***

### 2022.11.21

**New ✨**

* You can now override your Dockerfile *ENTRYPOINT* and *CMD* by adding commands and arguments in your application version or deployment. [link](https://github.com/edgegap/docs-gitbook/blob/main/docs/application/command-override/README.md)
* Added more environment variables with your port information. It is now easier to retrieve the data without parsing a JSON string. [link](https://github.com/edgegap/docs-gitbook/blob/main/docs/deployment/injected-variables/README.md)

**Improvements 💪**

* Added more locations to deploy your applications.

**Fixed ✔**

* Bug where ports were not shown correctly on the "Save as New" application version page.

***

### 2022.11.08

**New ✨**

* Notifications on the dashboard are now available to give users feedback and visibility of the system status. Notifications will be gradually added over the following months.

**Improvements 💪**

* Improved look of the documentation homepage.
* Images from the dashboard have been updated in the documentation.
* Added more locations to deploy your applications.

***

### 2022.10.24

**New ✨**

* New location beacons that can be used to ping locations within our network to improve your matchmaking and deployment strategies. [link](https://github.com/edgegap/docs-gitbook/blob/main/docs/deployment/locations/beacons/README.md)
* Bulk delete is now available from the dashboard.
* 1:1 Port mapping is now available for legacy game servers or games that don't support NAT punching. [link](https://github.com/edgegap/docs-gitbook/blob/main/docs/application/one-to-one-port-mapping/README.md)
* Port mapping and IP of your deployment are now accessible as environment variables from your deployed container.
* Added multiple popular netcode samples and documentation to ease integration.

**Fixed ✔**

* A rare occurrence of error when accessing application version pages on the dashboard.

***

### 2022.10.11

**New ✨**

* Linking endpoint storage to an application version to store your logs will now be available from the API.
* All admins of an organization will now be able to see its invoices.

**Improvements 💪**

* Added more locations to deploy your applications.

**Fixed ✔**

* Fix the dashboard UI on the email management page.

***

### 2022.09.27

**New ✨**

* The billing invoice will now only contain a summary of your resource usage. You can still view a full detailed invoice from the Edgegap dashboard.

**Improvements 💪**

* UI updates of the dashboard to improve the first-time user experience and application creation.
* Added more locations to deploy your applications.

**Fixed ✔**

* Minor bug fixes and improvements.

***

### 2022.08.30

**New ✨**

* API route to get geolocation information about an IP or a list of IPs. link
* The termination grace period is now customizable within the settings of an app version. Increasing it lets you gracefully terminate your application before the container is fully killed.
* Best practices CICD guide to help integrate Edgegap in your development pipelines. [link](https://github.com/edgegap/docs-gitbook/blob/main/docs/tools-and-integrations/cicd-integration/README.md)

**Improvements 💪**

* Added information parsing buttons in the Container Registry section for easier manipulation of registry commands.

**Fixed ✔**

* Bug where Container Registry was throwing irrelevant error message in the dashboard when application count tier limit was reached.

***

### 2022.08.16

**New ✨**

* Bulk delete for deployments and sessions.

**Improvements 💪**

* More locations added in different parts of the world.
* Deployment created by the Fleet manager will be automatically tagged with the fleet and policy name.

**Fixed ✔**

* Bug where fleet's policy with coordinates without decimal wasn't working.

***

### 2022.08.02

**New ✨**

* Added a default configuration when creating a new Fleet in the Fleet Manager.
* Deployment storage is now available for small files (5Mb limit).

**Improvements 💪**

* Dashboard UI tweaks for consistency.

**Fixed ✔**

* Bug where app version ports were not showing on the app version page.

***

### 2022.07.19

**New ✨**

* Fleet manager: the Deployment Scaler has been removed and replaced by the Fleet Manager. You can now create your fleets, policies, and filters which will automatically scale your Sessions at specific sites according to your configuration. [Documentation](https://github.com/edgegap/docs-gitbook/blob/main/docs/deployment/session/fleet-manager/fleet/README.md)
* You can now check out Edgegap's services uptime here: <https://status.edgegap.com/>

**Improvements 💪**

* Small Dashboard UI change for consistency.

**Fixed ✔**

* Container image validation when updating an application version.
* The deployment's FQDN will no longer include the application name. It was sometime causing issues in the FQDN creation process. From now on, it will only have the deployment's request ID.

***

### 2022.06.21

**New ✨**

* Platform logs have been reworked to be more relevant to users.

**Fixed ✔**

* Bug with the application version image verification not working when using certain repository providers.
* Bug where using the "filters" body parameters with deployment without IPs was returning a bad request.

***

### 2022.06.07

**New ✨**

* API route to get your public IP

**Fixed ✔**

* Bug where the application versions errors were not cleaned correctly on an update, making our caching system disable cache for these versions needlessly.
* Bug where an error was returned when requesting deployment metrics via the API too soon in the deployment lifecycle.
* Bug when creating an application where the API was requesting optional parameters when using the "verify\_image" option.
* Bug with the container registry creating duplicate application versions when pushing the same tag multiple times.

***

### 2022.05.24

**New ✨**

* It's now possible to use a webhook for Sessions deployment when they are in a "ready" state.
* You can now deploy on a specific location by using a filter for a location tag.
* Added a contact form so you can get in touch with our team directly from the dashboard.

**Improvements 💪**

* Minor API changes to match the documentation correctly.

**Fixed ✔**

* API bug with the application version update where optional parameters were throwing validation error.
* Bug where the route to add players to a session, wasn't validating the session capacity.
* Bug that resulted in the session being put in error when an application startup timed out.

***

### 2022.05.10

**New ✨**

* Deployment timeline now available from the "Platform Info" tab on the deployment details page. This visual guide will make it easier to understand and improve each step of a deployment.

**Improvements 💪**

* A warning message will now be shown on the deployment page when deploying using a reserved IP (e.g. 0.0.0.0). Since the geolocation cannot be determined in such a case, the default location of this player will be at lat/long 0.0.
* Improvement in the Edge locations lifecycle management.

***

### 2022.05.03

**New ✨**

* Edgegap Container Registry: Push and update your container images directly to the fully integrated Edgegap Container Registry for a simple version management experience ([link](https://github.com/edgegap/docs-gitbook/blob/main/docs/container/edgegap-container-registry/README.md)).
* You can now exclude region, city, country, etc from your deployment request.
* You can now validate the container image for an application version to ensure that we can pull it from your selected registry. Available from the API and the dashboard.
* You can now download a preconfigured TOML file for our CLI directly on the app version detail page.

**Improvements 💪**

* Dashboard UI color-matching with our new website.
* New style for the login and registration pages.
* The documentation tree has been redesigned to facilitate integration flow.

**Fixed ✔**

* Rare cases of a 500 status on the deployments page.
* Bug where new users that didn't verify their email have a 500 status when trying to log in.

***

### 2022.02.29

**New ✨**

* You can now access the container logs of past deployments from the deployment history in the dashboard if you have setup an Endpoint Storage S3 bucket for your account.
* You can now request telemetry for a list of IPs on existing deployments. (Documentation coming soon)

**Improvements 💪**

* Readiness verification with TLS enabled ports.

**Fixed ✔**

* Session request creation with the dashboard wizard.

***

### 2022.02.14

**New ✨**

* Page to bulk delete app versions.
* Search bar in the application list.
* "Save as new" button for app version.
* Documentation on how to switch from Gamelift to Edgegap.
* Documentation on how to create a container for an Unreal Engine project.

**Improvements 💪**

* Removed misleading logs when using the TLS upgrade option on ports.
* More comprehensible response from the API when sending a bad JSON request.
* 23 more instant locations available for deployments.

**Fixed ✔**

* Managed Matchmaker without filters sometimes crashes.

***

### 2022.02.01

**New ✨**

* CLI to help you manage your application versions and simplify integration with your CICD pipeline.
* Edgegap Unity package to help you deploy and test faster directly from the Unity Engine.

**Improvements 💪**

* More flex locations are now available.

**Fixed ✔**

* Matchmaker update form missing the name field

***

### 2022.01.18

**Improvements 💪**

* Image repository name validation with a regex ensuring valid value.

**Fixed ✔**

* Various minor fixes.

***

### 2022.01.06

**New ✨**

* Experimental code-free matchmaker.
* Crash logs are now available in Arbitrium OpenMatch.
* Save your crash logs directly in your S3 bucket.

**Improvements 💪**

* More detailed dashboard register page.
* Updated Demo application with more information about your deployment.
* Better display for invoices.

**Fixed ✔**

* Fix a bug where the session linking process was not taking the best deployment available.
* Platform and container logs displayed in the dashboard were sometimes showing nothing and/or having weird behavior.
* Download pod logs in Arbitrium OpenMatch.

</details>

***

## 2021

<details>

<summary>View Release Notes 2021</summary>

### 2021.12.08

**New ✨**

* Sessions selectors for better management between session and deployment ([link](https://github.com/edgegap/docs-gitbook/blob/main/docs/deployment/session/selectors/README.md)).

**Improvements 💪**

* Platform registration is now protected by reCAPTCHA.
* Added more Flex Locations.

**Fixed ✔**

* Logging issue spamming an error while an application was caching.

***

### 2021.11.23

**New ✨**

* System will automatically disable the cache on unused app versions ([link](https://github.com/edgegap/docs-gitbook/blob/main/docs/application/version/README.md#optional-fields)).
* Free swag available once registered on the platform.
* Session automatic cleaner. No more need to manually delete unlinked sessions ([link](https://github.com/edgegap/docs-gitbook/blob/main/docs/deployment/session/more-in-depth/README.md#empty-time-to-live)).

**Improvements 💪**

* Tier management got more simple with more insights when you need to downgrade or upgrade your tier.
* You can now choose to connect automatically in your organization instead of switching each time you log in.
* When switching in organization view, you will stay on the page you were on.
* Organization owners can now set admins that can invite people to your organization.
* Deployments logs will now indicate if you need to increase your minimal time to deploy or activate caching in case of deployment in an error state.

**Fixed ✔**

* Bug where you were unable to edit env containing "\n" for app versions and matchmakers.
* Bug where JSON snippet tool in app creation form page wasn't displaying anything. Also improved its content to reflect the API validations.
* Correction of some location information.

***

### 2021.11.02

**New ✨**

* You can now test an application deployment faster with our one-click application creation.
* Access logs of a crashed container directly from the deployment page.
* Upgrade HTTP and Websocket connections to HTTPS and WSS with the flip of a switch.

**Improvements 💪**

* Application ports now support naming for easier retrieval.
* Simplified application creation form for easier understanding. Advanced settings are still available.
* We now have a C# tutorial for OpenMatch integration.
* More location are available with advanced setting.

**Fixed ✔**

* Unusual caching behavior.

***

### 2021.10.05

**New ✨**

* Self-serve, You can now easily register and get some deployments going. However, we will always be here to help.
* The sidebar showes all the new supported tech staks @ Edgegap.
* Integration with a payment processor, you will have the option to pay your Edgegap Invoices in Arbitrium directly.
* We integrate support with Intercom support directly on your dashboard.
* Edgegap Wallet.

**Improvements 💪**

* We added new edges sites with more features.
* With one click, you can see the amount of credit remaining in your Edgegap wallet.

**Fixed ✔**

* Added a longer timeout in ASD.
* Minor cosmetic changes.

***

### 2021.08.18

**New ✨**

* Ship your logs to S3
  * We added a new feature that allows you to store your container logs automatically to S3 type storage. You can follow our doc to enable it on your apps. [link](https://github.com/edgegap/docs-gitbook/blob/main/docs/deployment/endpoint-storage/save-container-logs/README.md).

**Improvements 💪**

* Arbitrium Open Match
  * Have a look at our new feature in the Matchmaker UI that is helping you troubleshoot your deployment now with Container logs.
* Session-based deployment
  * We added more ways of doing Session-based deployment to ease your work.
  * The “Create Deployment” Button Allow to send a Session instance for Session-Based Application

**Fixed ✔**

* Various minor bugfix and enhancements in the decision-making process.
* Various updates and hardening were done on the edge computing infrastructure.
* Arbitrium Webhook feature will return if the Deployment is in Error in early steps of the process.

***

### 2021.06.18

**New ✨**

* Arbitrium Open Match
  * You can now create your Matchmaker directly in the Arbitrium Dashboard. You can follow the documentation under the Arbitrium Open Match.
* SDK generator in Dashboard
  * Increased integration between your game server and Arbitrium, you can now generate the SDK from our Dashboard.
* Protection of your deployment is automatically done.
  * If enabled in your application configuration, Arbitrium will protect your deployment. It will be reached ONLY from IP that you allowed.
* Organization support in Dashboard.
  * We have the support of Organizations built into your Dashboard. Invite your coworker to the Organization, then hop in and out to leverage the same account.
* Deployment context in the container
  * We added more information in your container. When you need to have scripts in your container to display information on the location, see the documentation to get more information on this feature.
* Session-based deployment
  * We support matches that players are getting in and out of at any given time. We will add the players in the session that is in the best location for your players.
  * The horizontal Deployment Session tool will make sure you always have sessions ready to onboard new players.

**Improvements 💪**

* New steps when terminating a deployment
  * We have a new Step when stopping a deployment, Ready -> Terminating -> Terminated.
* SSO in Arbitrium
  * We support using Okta as the Single Sign-On on all Edgegap tools.
* Dashboard Tags
  * You can see all tags assigned to your application deployment in your deployment list.

**Fixed ✔**

* When starting new processes in your container, the display of your CPU/RAM metrics was not rendered correctly in the Dashboard.
* When only one access point available, an empty IP string, the deployment was not processed correctly.

***

### 2021.04.30

**New ✨**

* We support Tier management by clients.
* New Awesome landing page with essential stats to Studio about your deployments.
* Security to the Dashboard login process.

**Improvements 💪**

* You can disable port validation from the app version page.
* Add the flexibility to allow more time to deploy the application before cached on the Access Points.
* Caching is done passively at the Edge level now.

**Fixed ✔**

* Fixed inconstancy in ping results
* Fixed typos in documentation.

***

### 2021.04.15

**New ✨**

* Now supporting AWS Local Zone

**Improvements 💪**

* Improvements made to the console logs, it's now reflecting more what a console should look like

**Fixed ✔**

* Fixed small memory leaks
* Fixed small monitoring bug
* Fixed handled-error showing as error in logs

***

### 2021.03.09

**New ✨**

* Added the option to deploy to a specific location without taking telemetry data into account.
* Added a “lock deployment” option if you need to have a deployment remain active. As long as a deployment is locked, the deployment cannot be killed by any requests.
* Added access to more information inside our BigData repository directly from the Dashboard.
* Added support for returning information to your matchmaker using a webhook.
* Added the ability to create tags on your deployments to identify them more easily.

**Improvements 💪**

* Improvements made to the DDOS detection for game servers.
* Improvements on how we handle traffic coming into our Arbitrium platform to make it faster and more secure.
* Improved the Documentation.

**Fixed ✔**

* Fixing minor bugs for stability in the backend.

</details>


# Sample Projects

Explore our sample projects and build on a strong multiplayer foundation:

<table data-view="cards"><thead><tr><th></th></tr></thead><tbody><tr><td><a href="sample-projects/unreal-engine/lyra-sample">Lyra Sample<br>(Unreal Engine)</a></td></tr><tr><td><a href="sample-projects/unreal-engine/top-down-sample">Top-Down Sample<br>(Unreal Engine)</a></td></tr></tbody></table>

***

<table data-view="cards"><thead><tr><th></th></tr></thead><tbody><tr><td><a href="sample-projects/unity-netcodes/photon-fusion-2-on-edgegap">Asteroids Sample<br>(Unity + Photon Fusion 2)</a></td></tr><tr><td><a href="sample-projects/unity-netcodes/photon-fusion-on-edgegap">Tanknarok Sample<br>(Unity + Photon Fusion 1)</a></td></tr><tr><td><a href="sample-projects/unity-netcodes/unity-netcode-on-edgegap">2D Space Shooter<br>(Unity + NGO)</a></td></tr><tr><td><a href="sample-projects/unity-netcodes/mirror-pong">Pong Sample<br>(Unity + Mirror)</a></td></tr><tr><td><a href="sample-projects/unity-netcodes/fishnet-on-edgegap">Space Edge Sample<br>(Unity + FishNet)</a></td></tr><tr><td><a href="sample-projects/unity-netcodes/photon-bolt-on-arbitrium">Demo Sample<br>(Unity + Photon Bolt)</a></td></tr><tr><td><a href="sample-projects/unity-netcodes/mirror-on-edgegap-websocket">Tanks WebGL Sample<br>(Unity + Mirror)</a></td></tr><tr><td><a href="sample-projects/unity-netcodes/fishnet-on-edgegap-webgl">Space Edge WebGL Sample<br>(Unity + FishNet)</a></td></tr></tbody></table>

***

<table data-view="cards"><thead><tr><th></th></tr></thead><tbody><tr><td><a href="sample-projects/nuxt-on-edgegap">Single Page App Sample<br>(NuxtJS)</a></td></tr><tr><td><a href="sample-projects/ruby-on-rails">MVC Web App Sample<br>(Ruby on Rails)</a></td></tr></tbody></table>


# Unreal Engine


# Lyra Sample

Explore how to host Unreal Engine projects on Edgegap using techniques from the [Lyra Sample](https://dev.epicgames.com/documentation/en-us/unreal-engine/lyra-sample-game-in-unreal-engine).

## ✔️ Preparation

Before we start, you will need:

* Unreal Engine 5.5 - [download using Epic Games Launcher](https://www.unrealengine.com/en-US/download),
* Lyra Starter Game - [download from Fab](https://www.fab.com/listings/93faede1-4434-47c0-85f1-bf27c0820ad0).

Open your Epic Games launcher and navigate to Unreal Engine / Library / Fab Library.

Search for "lyra", then Create Project. We recommend using SSD for faster builds.

## ⚡ Deploy and Connect

### 1. Deploy a Server on Edgegap

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

☑️ [Create a new app version for your application](https://app.edgegap.com/application-management/applications/lyra-sample/versions/create), choose Lyra Sample.

☑️ [Deploy a server with your Lyra Sample app version](https://app.edgegap.com/deployment-management/deployments/list).

☑️ [Open your new deployment's details](https://app.edgegap.com/deployment-management/deployments/list).

☑️ Find your deployment's unique, one-time connection details:

* **Host URL** in format `780aa4260e83.pr.edgegap.net` ,
* **External Port** in format `30854`  (5 digits).

✅ You may now proceed to the next step.

### 2. Play In Editor (PIE)

☑️ Navigate to your new Lyra Starter Game project root folder on your drive.

☑️ Edit file Config / DefaultEngine.ini with a text editor (such as notepad).

☑️ For each `[section]`  below, add the following contents if it exists or create the section.

```
[ConsoleVariables]
net.IgnoreNetworkChecksumMismatch=1
net.CurrentHandshakeVersion=2
net.MinHandshakeVersion=2
net.VerifyNetSessionID=0
net.VerifyNetClientID=0

[/Script/Engine.GameEngine]
!NetDriverDefinitions=ClearArray
+NetDriverDefinitions(DefName="GameNetDriver",DriverClassName="OnlineSubsystemUtils.IpNetDriver",DriverClassNameFallback="OnlineSubsystemUtils.IpNetDriver")

[/Script/OnlineSubsystemUtils.IpNetDriver]
MaxClientRate=1000000000 
MaxInternetClientRate=1000000000
InitialConnectTimeout=120.0

[/Script/BuildSettings.BuildSettings]
DefaultServerTarget=LyraServer
```

☑️ Open your new project in Unreal Engine.

☑️ Press the ▶️ Play button to start your game client.

☑️ Press tilde `~`  and input `open {host}:{port}`  with connection details from previous step.&#x20;

🙌 Congratulations on your first Deployment on Edgegap!

## ✏️ Customize Server Build

{% hint style="success" %}
See [unreal-engine](https://docs.edgegap.com/unreal-engine "mention") for Unreal Engine to **learn how to build and customize servers**.
{% endhint %}


# Top-Down Sample

Launching an Unreal Engine game with dedicated game servers can be daunting project, from individual developers to experienced medium-sized teams.

Fortunately, the Edgegap platform makes it easy, with a simple integration process that takes minutes. Your game will then be online, ready to connect players worldwide to play. Helping you allocate precious development resources to what you love – making a great game.

Here is Edgegap's plugin video tutorial:

{% embed url="<https://youtu.be/J8WNC6itYTE>" %}

***

{% hint style="success" %}
See our [Unreal Engine sample project](https://github.com/edgegap/unreal-sample) using the Top-Down sample for inspiration.
{% endhint %}

{% hint style="info" %}
See [unreal-engine](https://docs.edgegap.com/unreal-engine "mention") for Unreal Engine to **learn how to build and customize servers**.
{% endhint %}


# Unity


# Photon Fusion 2

Explore how to host Unity projects on Edgegap using techniques from the [Fusion 2 Asteroids Sample](https://doc.photonengine.com/fusion/current/game-samples/fusion-asteroids).

{% embed url="<https://youtu.be/bg41HpPmE3E>" %}

## ✔️ Preparation

Before we start, you will need:

* Unity 6 - [download using Unity Hub](https://unity.com/releases/unity-6),
* Fusion 2 Asteroids Sample project (modified for Edgegap) - [download from GitHub](https://github.com/edgegap/netcode-sample-photon-fusion-2).

## ⚡ Deploy and Connect

### 1. Deploy a Server on Edgegap

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

☑️ [Create a new app version for your application](https://app.edgegap.com/application-management/applications/fusion-2-asteroids-sample/versions/create), choose Fusion 2 Asteroids Sample.

☑️ Open your new project in Unity.

☑️ Navigate to Tools / Edgegap Hosting, then to step 6. Deploy a Server on Edgegap.

☑️ Press Deploy to cloud and [open your new deployment's details](https://app.edgegap.com/deployment-management/deployments/list).

☑️ Find your deployment's unique, one-time connection details:

* **Host URL** in format `780aa4260e83.pr.edgegap.net` .

✅ You may now proceed to the next step.

### 2. Connect from Editor

☑️ Open your new project in Unity.

☑️ Press the ▶️ Play button to start your game client.

☑️ Input Host URL (connection details from previous step) as room name.

☑️ Press Start Edgegap button to connect to your server.

☑️ Connect a second virtual Player with [Multiplayer Play Mode](https://docs-multiplayer.unity3d.com/mppm/current/about/) or [ParrelSync](https://github.com/VeriorPies/ParrelSync).

🙌 Congratulations on your first Deployment on Edgegap!

## ✏️ Customize Server Build

{% hint style="success" %}
See [unity](https://docs.edgegap.com/unity "mention") for Unity to **learn how to build and customize servers**.
{% endhint %}

### Create an App on Photon

{% hint style="info" %}
To make the initial demo easy, we used a free tier Photon Cloud account owned by Edgegap.
{% endhint %}

☑️ [Create a free account with Photon](https://dashboard.photonengine.com/).

☑️ [Create an Application on Photon](https://dashboard.photonengine.com/app/create):

* `Multiplayer Game`,
* `Fusion` Photon SDK,
* `Fusion 2` SDK version.

☑️ Find your Application ID in format `85314a99-56fc-4ab3-ba26-50efca09f303` .

☑️ Input your ID in Photon Settings under Tools / Fusion / Fusion Hub (Alt + F).

### Integrate Fusion 2 Project with Edgegap

{% hint style="success" %}
See `EdgegapServerManager.cs`  script for an example integration of Fusion 2 with Edgegap.
{% endhint %}

{% hint style="warning" %}
Your `NetworkProjectConfig`  **must use `Peer Mode = Single` (Ded. Server)**, not `Multiple` (Client-Host)!
{% endhint %}

Game clients will connect to game servers through [Photon Fusion 2 ](https://doc.photonengine.com/fusion/current/manual/connection-and-matchmaking/matchmaking#creating-and-joining-a-game-session)[Session (room) ](https://doc.photonengine.com/fusion/current/manual/connection-and-matchmaking/matchmaking#creating-and-joining-a-game-session)[feature](https://doc.photonengine.com/fusion/current/manual/connection-and-matchmaking/matchmaking#creating-and-joining-a-game-session).

Your game server needs to register it's IP address and external port with the Session name, when calling `_runnerInstance.StartGame(StartGameArgs args)`:

* use `GameMode.Server`  to ensure your connection isn't relayed over Photon Cloud (adds latency),
* use `NetAddress.CreateFromIpPort` method from Fusion,
* provide server's IP address:\
  `Environment.GetEnvironmentVariable("ARBITRIUM_PUBLIC_IP")`
* provide server's external port:\
  `Environment.GetEnvironmentVariable("ARBITRIUM_PORT_GAMEPORT_EXTERNAL")`
  * this is the default port mapping name if you use our [Unity plugin to package your server](https://docs.edgegap.com/unity).

Use Edgegap Deployment Host URL as a Session name:

* in game server, get it with\
  `$"{Environment.GetEnvironmentVariable("ARBITRIUM_REQUEST_ID")}.pr.edgegap.net"`
* when testing game client, get it from dashboard - deployment details page / Host URL
  * create deployments for testing from our [quickstart hosting plugin](https://docs.edgegap.com/unity/developer-tools#dedicated-servers-quickstart-plugin),
* when live in game client, get it from [matchmaking / ticket assignment / fqdn](https://docs.edgegap.com/learn/matchmaking/matchmaker-in-depth#player-api):
  * see also [getting started with Matchmaking](https://docs.edgegap.com/learn/matchmaking).

{% tabs %}
{% tab title="Client Integration" %}
{% code title="EdgegapClientManager.cs" %}

```csharp
// get fusion 2 network runner
_runnerInstance = FindFirstObjectByType<NetworkRunner>();
_runnerInstance.ProvideInput = true;

// get this value from Edgegap Matchmaker Assignment or Fusion 2 Sessions API
string sessionName = "<requestId.pr.edgegap.net>";

// find fusion 2 session (using session name)
var result = await _runnerInstance.StartGame(
    new StartGameArgs() {
        GameMode = GameMode.Client,
        SessionName = sessionName,
        ObjectProvider = _runnerInstance.GetComponent<NetworkObjectPoolDefault>(),
    }
);

// fusion will now fetch server IP and port based on session name and connect
```

{% endcode %}
{% endtab %}

{% tab title="Server Integration" %}
{% code title="EdgegapServerManager.cs" %}

```csharp
// read edgegap injected environment variables
string requestId = Environment.GetEnvironmentVariable("ARBITRIUM_REQUEST_ID");
string listenPort = Environment.GetEnvironmentVariable("ARBITRIUM_PORT_GAMEPORT_INTERNAL");
string connectIP = Environment.GetEnvironmentVariable("ARBITRIUM_PUBLIC_IP");
string connectPort = Environment.GetEnvironmentVariable("ARBITRIUM_PORT_GAMEPORT_EXTERNAL");

// get fusion 2 network runner
_runnerInstance = FindFirstObjectByType<NetworkRunner>();
_runnerInstance.ProvideInput = true;

// register fusion 2 session for clients to find it later (using session name)
var result = await _runnerInstance.StartGame(
    new StartGameArgs() {
        GameMode = GameMode.Server,
        SessionName = $"{requestId}.pr.edgegap.net",
        ObjectProvider = _runnerInstance.GetComponent<NetworkObjectPoolDefault>(),
        Address = NetAddress.Any(listenPort),
        CustomPublicAddress = NetAddress.CreateFromIpPort(connectIP, connectPort),
    }
);

// load initial scene
if (result.Ok && _runnerInstance.IsServer) {
    await _runnerInstance.LoadScene(sceneName);
}
```

{% endcode %}
{% endtab %}
{% endtabs %}

### Troubleshooting

<details>

<summary><code>Game Does Not Exist (32758)</code></summary>

* Photon rooms require the player to be connecting to the Photon Cloud region where the deployment is located. Deploying from dashboard uses a randomized player IP.
* You may need to find the deployment's location on the map, and configure your game client in Assets / Photon / Fusion / Resources / PhotonAppSettings.asset with the matching [Photon Cloud region](https://doc.photonengine.com/fusion/current/manual/connection-and-matchmaking/regions#photon-cloud-for-gaming).
* Edgegap [deploys as close to the player as possible](https://docs.edgegap.com/learn/orchestration/deployments#id-1.-server-score-strategy-best-practice) when using our [plugins](https://docs.edgegap.com/unity/developer-tools) or [API](https://docs.edgegap.com/docs/api/dedicated-servers) so in production, setting Photon Cloud region is not required.

</details>


# Photon Fusion 1

### Photon Fusion on Arbitrium

This guide will help you create a headless server on Edgegap for a Unity project using [Photon Fusion](https://doc.photonengine.com/en-us/fusion/current/getting-started/fusion-intro) as its networking solution.

We will use the sample project [Tanknarok from Photon Fusion](https://doc.photonengine.com/en-us/fusion/current/samples/fusion-tanknarok) as an example.

Because Edgegap works best when it knows where all the players are (so it can pick a server in the optimal location) the Tanknarok game will first start in client-hosted mode and then switch to the Edgegap server once all the players have joined. This is because Tanknarok has a playable lobby that runs before the match starts where players are able to join and leave at will. So the flow of logic is as follow:

1. Players connect to the same room using `AutoHostOrClient` mode. Which automatically picks the first player in the room as the host.
2. All players send their IP address to the host when they join.
3. Once the players ready-up, the host uses these IP addresses to start an Edgegap server version of the game with a randomized room code (using a guid).
4. When the host sees that the Edgegap instance has finished deploying, it tells the other players about the new room code.
5. All players, including the host, disconnect from their current room and reconnect in Client mode to the new room being hosted by the Edgegap server.
6. When the Edgegap server sees all expected players have joined, it starts the match.
7. When the Edgegap server sees that everyone has left the match, it shuts itself down.

### Account setup

To run this application, you will need to have both a Photon account and an account with Edgegap. First, you will need to make a Fusion app on the Photon dashboard and set the app id in the `PhotonAppSettings` scriptable object file. Then, you will need to add an application and create an API token on the dashboard. You will use these to set the App Name, Version, and Api Token in the `EdgegapConfig` scriptable object file.

{% hint style="info" %}
When making the Edgegap app, this program requires 512 CPU units and 512 MB of memory.
{% endhint %}

There are also two plugins to help with development: Newtonsoft Json for better Json serialization and [ParrelSync](https://github.com/VeriorPies/ParrelSync) for easier testing with multiple unity editors.

### Step 1: Server mode setup

You can grab the modified Tanknarok project on [GitHub](https://github.com/edgegap). You will also need to import the [Photon Fusion SDK](https://doc.photonengine.com/en-us/fusion/current/getting-started/sdk-download) into the project.

The Photon Fusion Tanknarok project needed to be slightly altered to work as a server. This mostly involved automatically starting the match and setting the mode.

1. Modified `GameLauncher.cs` to launch on start with `GameMode.Server`.
2. Modified `FusionLauncher.cs` to call `_spawnWorldCallback` once game is running instead of relying on `InstantiatePlayer` (since no players are instantiated for server).
3. Skipping the lobby scene if it’s a server and going straight to the match when all the players have joined.

This has already been completed in the modified Tanknarok project available our [GitHub](https://github.com/edgegap).

#### Dockerfile

The docker file is pretty basic. We’re just using an ubuntu base, copying over the compiled linux server build, setting the permissions on the file, and running it.

### Step 2: The first client

The initial client takes on a role of host and of managing the Edgegap server. It does this through the `EdgegapManager.cs` file, which in turn uses the `EdgegapAPIInterface.cs` file, which wraps up most of the functionality surrounding interacting with Edgegap.

In `GameManager.cs`, the `OnAllPlayersReady` function for the host will deploy an Edgegap server instead of starting the match. It does this based on the IP addresses of all the players. Unity coroutines allow these actions to happen asynchronously. The Deploy method takes a callback function, which is fed the name of the new room the server will use. A Photon RPC function is sent to signal to all the clients to switch over.

```cs
    if (EdgegapManager.EdgegapPreServerMode)
    {
        //if host, spin up new edgegap server
        //once server is ready, connect to it

        FindObjectOfType<GameLauncher>().ShowMatchStartingUI();

        if (Object.HasStateAuthority)
        {
            string[] ips = PlayerManager.allPlayers.Select(p => p.ipAddress).ToArray();
            StartCoroutine(EdgegapManager.Instance.Deploy(ips, RpcOnEdgegapServerReady));
        }
    }
    else
    {
        LoadLevel(_levelManager.GetRandomLevelIndex(), -1);
    }
```

The switch over happens in an empty scene named `TransferringScene`.

Inside EdgegapManager, a randomized room code is created and passed, along with the player count as Environment variables to the newly created instance through the deploy API. This is combined with the `status` api calls that start checking once a second to see when the instance is done deploying. You could also use the [webhook](https://docs.edgegap.com/docs/deployment/arbitrium-deploy-webhook) option.

```cs
    /// <summary>
    /// Calls the Edgegap API to deploy a server
    /// </summary>
    /// <param name="clientIpList">A list of client IP addresses</param>
    /// <param name="OnDeployed">A callback method with the session name as a parameter</param>
    public IEnumerator Deploy(string[] clientIpList, Action<string> OnDeployed = null)
    {
        var roomCode = Guid.NewGuid().ToString();
        yield return EdgegapAPIInterface.RequestDeployment(clientIpList,
             new Dictionary<string, string> {
                { "room_code", roomCode },
                { "player_count", clientIpList.Length.ToString() } });

        yield return EdgegapAPIInterface.WaitForDeployment();

        OnDeployed(roomCode);
    }
```

### Step 3: Joining players

Besides switching over to the new Edgegap server when told to, joining players also need to tell the host player what their IP address is. Since Photon doesn’t provide this information, an RPC call in `GameManager` called `ShareIpAddress` is called from the `Player.cs` class in the `Spawned` method.

The host then stores these IP addresses in the player class for all the players based on who the source of the RPC message was:

```cs
    [Rpc(sources:RpcSources.All, RpcTargets.StateAuthority)]
    public void RpcShareIpAddress(string ipAddress, RpcInfo info = default)
    {
        if (info.Source == PlayerRef.None)
        {
            // source will be None for local player
            Player.local.ipAddress = ipAddress;
            return;
        }

        foreach (var player in PlayerManager.allPlayers)
        {
            if (player.playerID == info.Source.PlayerId)
            {
                player.ipAddress = ipAddress;
                break;
            }
        }
    }
```

### Step 4: Cleaning up

Back in the server, the modified `GameManager.cs` keeps track of the number of players in the match in the main Update function. It both checks for when the target number of players have joined, so it can start the match, but also determines when it’s time to shut itself down. If the game has been running for over a minute and there aren’t any players left, it calls the Edgegap API to stop its own deployment.

```cs
    if (EdgegapManager.IsServer())
    {
        if (GameManager.playState == GameManager.PlayState.LOBBY)
        {
            // if we're in the lobby and all players have joined, start the match
            if (PlayerManager.allPlayers.Count >= EdgegapManager.ExpectedPlayerCount)
            {
                OnAllPlayersReady();
            }
        }

        if(Time.time > 60 && PlayerManager.allPlayers.Count == 0
            && GameManager.playState != GameManager.PlayState.TRANSITION)
        {
            // if it's been over a minute and there's no one here, stop the server
            Debug.LogWarning("Shutting Down");
            StartCoroutine(EdgegapAPIInterface.StopDeploymentFromServer());
            GameManager.playState = PlayState.TRANSITION;
        }
    }
```

You now have a Photon Fusion project available to deploy on demand!


# Unity NGO

Explore how to host Unity projects on Edgegap using techniques from the [NGO Boss Room Sample](https://unity.com/demos/small-scale-coop-sample).

{% hint style="info" %}
This sample **does not require any Unity Gaming Services (UGS)**, Multiplay, or Relays to run.
{% endhint %}

{% embed url="<https://youtu.be/8Qi-wXswjkw>" %}

## ✔️ Preparation

Before we start, you will need:

* Unity 6 - [download using Unity Hub](https://unity.com/releases/unity-6),
* Unity NGO \[Netcode for Game Objects] Boss Room Sample project (modified for Edgegap):
  * [download from Github](https://github.com/edgegap/netcode-sample-unity-ngo-bossroom).

## ⚡ Deploy and Connect

### 1. Deploy a Server on Edgegap

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

☑️ [Create a new app version for your application](https://app.edgegap.com/application-management/applications/unity-ngo-bossroom-sample/versions/create), choose NGO Boss Room Sample.

☑️ [Deploy a server with your NGO Boss Room Sample app version](https://app.edgegap.com/deployment-management/deployments/list).

☑️ [Open your new deployment's details](https://app.edgegap.com/deployment-management/deployments/list) and find your unique, one-time connection details:

* **External Port** in format `30854`  (5 digits).

☑️ Navigate to tab Logs and find (CTRL+F) your unique, one-time connection details:

* `ARBITRIUM_PUBLIC_IP` in format `172.234.244.38` .

✅ You may now proceed to the next step.

### 2. Connect from Editor

☑️ Open your new project in Unity.

☑️ Verify that you have opened scene: `Assets/Scenes/MainMenu.unity`.

☑️ Press the ▶️ Play button to start your game client:

* press **START WITH DIRECT IP** button,
* select tab **JOIN WITH IP.**

☑️ Input connection details from previous step.

☑️ Press **JOIN** button to connect to your server.

☑️ Connect a second virtual Player with [Multiplayer Play Mode](https://docs-multiplayer.unity3d.com/mppm/current/about/) or [ParrelSync](https://github.com/VeriorPies/ParrelSync).

🙌 Congratulations on your first Deployment on Edgegap!

## ✏️ Customize Server Build

{% hint style="success" %}
See [unity](https://docs.edgegap.com/unity "mention") for Unity to **learn how to build and customize servers**.
{% endhint %}

### Run as Dedicated Server

For this sample to run as dedicated server, we made the following changes:

{% tabs %}
{% tab title="Server Initialization" %}
New script (added to your `MainMenu` scene in a new empty `GameObject`):

<pre class="language-csharp" data-title="Assets/Scripts/EdgegapServerStarter.cs" data-line-numbers><code class="lang-csharp">using System;
using System.Collections;
using System.Collections.Generic;
using Unity.BossRoom.ConnectionManagement;
using UnityEngine;

namespace Unity.Multiplayer.Samples.BossRoom
{
    public class EdgegapServerStarter : MonoBehaviour
    {
<strong>        public string portMapName = <a data-footnote-ref href="#user-content-fn-1">"gameport"</a>;
</strong>
        // Start is called before the first frame update
        void Start()
        {
            if (Application.isBatchMode)
            {
                ConnectionManager connectionManager = GameObject.Find("ConnectionManager").GetComponent&#x3C;ConnectionManager>();
<strong>                string internalPortAsStr = Environment.GetEnvironmentVariable($"ARBITRIUM_PORT_{portMapName.ToUpper()}_INTERNAL");
</strong>
                if (internalPortAsStr == null || !ushort.TryParse(internalPortAsStr, out ushort port))
                {
                    throw new Exception($"Could not find port mapping, make sure your app version port name matches with \"{portMapName}\"");
                }

<strong>                connectionManager.StartHostIp("<a data-footnote-ref href="#user-content-fn-2">SERVER</a>", "0.0.0.0", port);
</strong>            }
        }
    }
}
</code></pre>

{% endtab %}

{% tab title="Connection Management" %}
Modified files:

<pre class="language-csharp" data-title="Assets/Scripts/ConnectionManagement/ConnectionMethod.cs"><code class="lang-csharp"><strong>116        public override async Task SetupHostConnectionAsync()
</strong>117        {
<strong>118            <a data-footnote-ref href="#user-content-fn-3">//SetConnectionPayload(GetPlayerId(), m_PlayerName); // Need to set connection payload for host as well, as host is a client too</a>
</strong>119            var utp = (UnityTransport)m_ConnectionManager.NetworkManager.NetworkConfig.NetworkTransport;
120            utp.SetConnectionData(m_Ipaddress, m_Port);
121        }
</code></pre>

<pre class="language-csharp" data-title="Assets/Scripts/ConnectionManagement/ConnectionState/StartingHostState.cs"><code class="lang-csharp"><strong>66        async void StartHost()
</strong>67        {
              ...

72                // NGO's StartHost launches everything
<strong>--                <a data-footnote-ref href="#user-content-fn-3">//if (!m_ConnectionManager.NetworkManager.StartHost())</a>
</strong><strong>73                <a data-footnote-ref href="#user-content-fn-4">if (!m_ConnectionManager.NetworkManager.StartServer())</a>
</strong>74                {
75                    StartHostFailed();
76                }

              ...
</code></pre>

<pre class="language-csharp" data-title="Assets/Scripts/Gameplay/GameplayObjects/Character/ClientCharacter.cs"><code class="lang-csharp"><strong>112        public override void OnNetworkSpawn()
</strong>113        {
               ...

125            m_ServerCharacter.IsStealthy.OnValueChanged += OnStealthyChanged;
126            m_ServerCharacter.MovementStatus.OnValueChanged += OnMovementStatusChanged;
<strong>127            <a data-footnote-ref href="#user-content-fn-3">//OnMovementStatusChanged(MovementStatus.Normal, m_ServerCharacter.MovementStatus.Value);</a>
</strong> 
               ...
</code></pre>

{% endtab %}

{% tab title="Editor/Server Compatibility" %}
Modify files:

<pre class="language-csharp" data-title="Assets/Scripts/ConnectionManagement/ConnectionState/HostingState.cs"><code class="lang-csharp"><strong>148        ConnectStatus GetConnectStatus(ConnectionPayload connectionPayload)
</strong>149        {
               ...
                
<strong>155            <a data-footnote-ref href="#user-content-fn-5">//if (connectionPayload.isDebug != Debug.isDebugBuild)</a>
</strong><strong>156            //{
</strong><strong>157            //    return ConnectStatus.IncompatibleBuildType;
</strong><strong>158            //}
</strong>
               ...
</code></pre>

{% endtab %}
{% endtabs %}

[^1]: default port name on Edgegap

[^2]: player name for server can be any value

[^3]: p2p only ⇒ comment this out

[^4]: start as dedicated server instead

[^5]: Editor compatibility ⇒ comment this out


# Mirror Pong

Explore how to host Unity projects on Edgegap using techniques from the [Mirror Pong Sample](https://mirror-networking.gitbook.io/docs/manual/examples/pong).

{% embed url="<https://youtu.be/bvBkObGLTMk>" %}

## ✔️ Preparation

Before we start, you will need:

* Unity 6 - [download using Unity Hub](https://unity.com/releases/unity-6),
* Mirror Unity package - [download from Unity Asset Store](https://assetstore.unity.com/packages/tools/network/mirror-129321),
  * this package includes the Pong sample.

Create a new project and import the Mirror package above.

## ⚡ Deploy and Connect

### 1. Deploy a Server on Edgegap

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

☑️ [Create a new app version for your application](https://app.edgegap.com/application-management/applications/mirror-pong-sample/versions/create), choose Mirror Pong Sample.

☑️ [Deploy a server with your Mirror Pong Sample app version](https://app.edgegap.com/deployment-management/deployments/list).

☑️ [Open your new deployment's details](https://app.edgegap.com/deployment-management/deployments/list).

☑️ Find your deployment's unique, one-time connection details:

* **Host URL** in format `780aa4260e83.pr.edgegap.net` ,
* **External Port** in format `30854`  (5 digits).

✅ You may now proceed to the next step.

### 2. Connect from Editor

☑️ Open your new project in Unity.

☑️ Open scene in folder Mirror / Examples / Pong / Scenes / MirrorPong.unity.

☑️ Press the ▶️ Play button to start your game client.

☑️ Input connection details from previous step.

☑️ Press Client button to connect to your server.

☑️ Connect a second virtual Player with [Multiplayer Play Mode](https://docs-multiplayer.unity3d.com/mppm/current/about/) or [ParrelSync](https://github.com/VeriorPies/ParrelSync).

🙌 Congratulations on your first Deployment on Edgegap!

## ✏️ Customize Server Build

{% hint style="success" %}
See [unity](https://docs.edgegap.com/unity "mention") for Unity to **learn how to build and customize servers**.
{% endhint %}


# Mirror

### Mirror on Edgegap

This guide will help you create a headless server on Edgegap for a Unity project using [Mirror](https://mirror-networking.com/) as its networking solution.

This guide will use the open-source sample project `Tanks`, which is already available in your Mirror sample, location Assets/Mirror/Examples/Tanks.

The final sample can be found on our [GitHub](https://github.com/edgegap/netcode-sample-unity-mirror).

### Build the game server

Once ready with your game, head to the `Build` screen of the Unity Editor, under `File -> Build Settings` in the top menus. Make sure to select the right presets depending on your version of Unity.

* Prior to version 2021.2:
  * Set `Target Platform` to `Linux`;
  * Set `Architecture` to `x86_64`;
  * Check the `Server Build` option.
* Otherwise:
  * Set `Platform` to `Dedicated Server`;
  * Set `Target Platform` to `Linux`.

Then press build and select a new empty folder named `linux_server` as the file destination. Transfer `linux_server` folder to a second empty folder, which will be refered as the `[SERVER BUILD]` folder in this document.

### Containerizing the dedicated game server

We will create a docker image containing the dedicated game server in this part. You might also be interested in reading [Unity Server in Docker](https://docs.edgegap.com/docs/sample-projects/unity-netcodes/broken-reference).

If you need more informations about Docker with Edgegap, please refer to [this](https://docs.edgegap.com/docs/tools-and-integrations/container/docker) documentation.

#### Dockerfile

```
FROM ubuntu:bionic
MAINTAINER <author_detail>

ARG debian_frontend=noninteractive
ARG docker_version=17.06.0-ce

RUN apt-get update && \
    apt-get install -y libglu1 xvfb libxcursor1 ca-certificates && \
    apt-get clean && \
    update-ca-certificates

EXPOSE 3389/TCP
EXPOSE [GAME PORT]/TCP
EXPOSE [GAME PORT]/UDP

COPY linux_server/ /root/linux_server/
COPY boot.sh /boot.sh

WORKDIR /root/
ENTRYPOINT ["/bin/bash", "/boot.sh"]
```

Take note of the port you use for network communications, referred as the `[GAME PORT]`. By default, the port used is `7777`. You can find this information in the Unity Editor, on the `NetworkManager` game object, in the `Transport` component.

* Copy the above lines and paste them in your Dockerfile, placed inside `[SERVER BUILD]`. Modify the `[GAME PORT]` placeholders to your game port.

Having the `[GAME PORT]` opened on both TCP and UDP allow you to use any transport you prefer in the `NetworkManager` Mirror component. Finally, create a file named `boot.sh` at the root of the `[SERVER BUILD]` folder. It will be executed when starting the image in a container.

* Copy the following two lines, make sure to replace the `[YOUR GAME]` placeholders with the name of the generated file.

```
xvfb-run --auto-servernum --server-args='-screen 0 640X480X24:32' /root/build/[YOUR GAME].x86_64 -batchmode -nographics
```

At this point, you should have the following hierarchy:

> * `[SERVER BUILD] folder` > > - `Dockerfile` > > - `boot.sh` > > - `linux_server` folder > > > - Unity generated files

* Start a command prompt in the `[SERVER BUILD]` folder, and run the following Docker commands:

{% hint style="warning" %}
For ARM CPU (Mac M1, M2, etc.) users, add `--platform linux/amd64`  option to your build command.
{% endhint %}

#### Using Linux

```bash
# build the image
docker build . -t <IMAGE_NAME>:<IMAGE_VERSION>

# login, a prompt will ask the password
docker login -u '<REGISTRY_USERNAME>' <REGISTRY_URL>

# add another tag to your image corresponding to the registry
docker image tag <IMAGE_NAME>:<IMAGE_VERSION> <REGISTRY_URL>/<PROJECT_NAME>/<IMAGE_NAME>:<IMAGE_VERSION>

#push the image
docker push <REGISTRY_URL>/<PROJECT_NAME>/<IMAGE_NAME>:<IMAGE_VERSION>
```

#### Using cmd

```bash
# build the image
docker build . -t <IMAGE_NAME>:<IMAGE_VERSION>

# login, a prompt will ask the password
docker login -u <REGISTRY_USERNAME> <REGISTRY_URL>

# add another tag to your image corresponding to the registry
docker image tag <IMAGE_NAME>:<IMAGE_VERSION> <REGISTRY_URL>/<PROJECT_NAME>/<IMAGE_NAME>:<IMAGE_VERSION>

#push the image
docker push <REGISTRY_URL>/<PROJECT_NAME>/<IMAGE_NAME>:<IMAGE_VERSION>
```

#### Using Powershell

```bash
# build the image
docker build . -t <IMAGE_NAME>:<IMAGE_VERSION>

# login, a prompt will ask the password
docker login -u '<REGISTRY_USERNAME>' <REGISTRY_URL>

# add another tag to your image corresponding to the registry
docker image tag <IMAGE_NAME>:<IMAGE_VERSION> <REGISTRY_URL>/<PROJECT_NAME>/<IMAGE_NAME>:<IMAGE_VERSION>

#push the image
docker push <REGISTRY_URL>/<PROJECT_NAME>/<IMAGE_NAME>:<IMAGE_VERSION>
```

After these commands, you should be able to see your uploaded image on the Edgegap website if you are using the Edgegap Container Registry. See [this doc](https://docs.edgegap.com/learn/advanced-features/edgegap-container-registry) if you want to use the Edgegap registry. You can also use another private registry.

### Deploying to Edgegap

Navigate to the `Applications & Games` page of the website. Click on the `Create New` button in the top right hand corner to access the application form. Here are the fields and how to fill them properly:

* Application name : Can be any notable name you want to use to easily recognize your application among others.
* Image : Can be any specific image you want to use to easily recognize your application among others.
* Version name : You may want to use a version name to describe the scope of the version you are deploying. Examples may be “demo”, “production”, “v1”, “v2”
* Container :
  * Registry : “\[URL]”, where \[URL] is the value from the credentials you can display on the Container Repository page.
  * Image repository : “\[PROJECT]/\[YOUR GAME]”, where \[PROJECT] and \[YOUR GAME] are the values you used earlier when pushing the docker image.
  * Tag : “\[TAG]”, where \[TAG] is the value you used earlier when pushing the docker image.
  * Tick “Using a private repository”
  * Private registry username : “\[USERNAME]”, where \[USERNAME] is the value from your credentials.
  * Private registry token : “\[TOKEN]”, where \[TOKEN] is the value from your credentials.
  * Requirements : Left as is.
  * Ports :
    * Click the `+ Add port` link to add a new port, and add the following entries :
      * `[GAME PORT]` - `TCP/UDP` - disable Verifications
      * 3389 - TCP - disable Verifications

Once your application has been created, you can press the `Deploy` button to proceed with deploying your game server. Choose the region you want to deploy in, and enter the number of random players you want to generate depending on your game. Check that everything is running smoothly by verifying the following:

* Latest Status should be set to `Ready`.
* In the `Port Mapping` tab, you should be seeing the port you set in the application creation form:

<figure><img src="https://3027732442-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2Fgit-blob-583d6356cdf560e89fc338bde5c125a81c77a9ee%2Fmirror-app-creation.png?alt=media" alt=""><figcaption></figcaption></figure>

### Add sample HUD in your client application

* Set the `Port` value of the `Transport` component of the `NetworkManager` to the external port defined in the `Port Mapping` tab of your deployment.

In this example, the port was set to `31887`. This primarily depends on the game you are developing and will most likely be set programmatically in the game’s codebase.

* Set the value of `Network Address` of the `Network Manager` to your deployment's `Host`. This URL can be found in the `Deployment Summary` on the dashboard or with the API.

In this example, the address was set to `0ace560706a5.pr.edgegap.net`. Again, this value will most likely be set programmatically during the client’s communication with the master server/API responsible for the matchmaking process.

With the correct information, you should be able to connect to the game server normally and be able to start playing right away.

You now have a Mirror project available to deploy on demand!

With seat-based deployments, it's possible to use Mirror to create a system that automatically removes hanging Edgegap sessions once a player disconnects from the server, using `NetworkManager` callback functions, and a `NetworkBehaviour` script attached to the player prefab that uses a Remote Procedure Call (RPC) function and a Command function.

When the server starts, the `NetworkManager` retrieves the list of `session IDs` linked to its deployment from the Edgegap API and stores it. Afterwards, when a new player connects to the server, a client-side function is initiated via `RPC` that will send the `player's IP address` back to the server with a `command`. With the player's IP, the server checks for a matching IP in each session's data; The server gets the session data using its cached ID with the Edgegap API. If a match is found, the `session ID` is mapped to that player's `NetworkConnectionToClient`.

Since new sessions can be added after the server starts, the list of session IDs is updated and the new sessions are checked if a match can't be found the first time around.

Finally, once a player disconnects from the server, the server uses that player's `NetworkConnectionToClient` to retrieve their associated `session ID`, then uses the Edgegap API to delete that session. This frees a socket in the deployment for a new player to join.

#### PlayerNetworkBehaviour

```cs
public class PlayerNetworkBehaviour : NetworkBehaviour
{
    [ClientRpc]
    public void RpcSendClientIpAddress()
    {
        StartCoroutine(FetchPublicIpAndSendToServer());
    }

    private IEnumerator FetchPublicIpAndSendToServer(" alt=""><figcaption></figcaption></figure>
    {
        UnityWebRequest request = UnityWebRequest.Get("https://api.ipify.org?format=json");
        yield return request.SendWebRequest();

        if (request.result == UnityWebRequest.Result.Success)
        {
            string responseText = request.downloadHandler.text;
            string clientIp = JObject.Parse(responseText)["ip"].ToString();
            CmdSendIpAddressToServer(clientIp);
        }
        else
        {
            Debug.LogError("Failed to fetch public IP address.");
        }
    }

    [Command]
    public void CmdSendIpAddressToServer(string clientIp)
    {
        NetworkConnectionToClient conn = connectionToClient;
        if (conn != null)
        {
            CustomNetworkManager.Instance.StoreClientIpAddress(conn, clientIp);
        }
        else
        {
            Debug.LogError("Connection not found.");
        }
    }
}
```

#### CustomNetworkManager

```cs
public class CustomNetworkManager : NetworkManager
{
    private static readonly string edgegapUrl = "https://api.edgegap.com/v1";
    private string apiToken;
    private string deploymentId;
    private Dictionary<NetworkConnectionToClient, string> connectionToSessionIdMap = new Dictionary<NetworkConnectionToClient, string>();
    private Dictionary<NetworkConnectionToClient, bool> mappingInProgress = new Dictionary<NetworkConnectionToClient, bool>();

    private ArrayList currentDeploymentSessions = new();
    private ArrayList newSessions = new();

    public static CustomNetworkManager Instance;

    public override void Awake()
    {
        base.Awake();
        Instance = this;
    }

    public override void OnStartServer()
    {
        base.OnStartServer();
        deploymentId = System.Environment.GetEnvironmentVariable("ARBITRIUM_REQUEST_ID");
        apiToken = System.Environment.GetEnvironmentVariable("API_TOKEN");
        if (string.IsNullOrEmpty(apiToken))
        {
            Debug.LogError("Edgegap API token not found in environment variables.");
        }

        StartCoroutine(GetNewSessionList());
    }

    public override void OnServerAddPlayer(NetworkConnectionToClient conn)
    {
        base.OnServerAddPlayer(conn);
        Debug.Log($"Adding player for connection: {conn.connectionId}");

        // Get the PlayerNetworkBehaviour from the player object
        PlayerNetworkBehaviour playerNetworkBehaviour = conn.identity.GetComponent<PlayerNetworkBehaviour>();
        playerNetworkBehaviour.RpcSendClientIpAddress();
    }

    public void StoreClientIpAddress(NetworkConnectionToClient conn, string clientIp)
    {
        mappingInProgress[conn] = true; // Set mapping in progress to true
        Debug.Log($"Stored IP address for connection {conn.connectionId}: {clientIp}");

        // Start mapping the session to the connection
        StartCoroutine(CheckCachedSessions(conn, clientIp));
    }

    private IEnumerator GetNewSessionList()
    {
        newSessions.Clear();
        string url = $"{edgegapUrl}/status/{deploymentId}";
        UnityWebRequest request = UnityWebRequest.Get(url);
        request.SetRequestHeader("Authorization", apiToken);

        yield return request.SendWebRequest();

        if (request.result == UnityWebRequest.Result.Success)
        {
            string responseText = request.downloadHandler.text;
            Debug.Log("Deployment Status Response: " + responseText);

            var json = JObject.Parse(responseText);
            var sessions = json["sessions"] as JArray;

            foreach (var session in sessions)
            {
                string sessionId = session["session_id"]?.ToString();

                if (!currentDeploymentSessions.Contains(sessionId))
                {
                    newSessions.Add(sessionId);
                    currentDeploymentSessions.Add(sessionId);
                }
            }

            Debug.Log("New session list initialized");
        }
    }

    private IEnumerator CheckCachedSessions(NetworkConnectionToClient conn, string clientAddress)
    {
        foreach (string sessionId in currentDeploymentSessions)
        {
            yield return GetSessionAndMap(conn, sessionId, clientAddress);

            if (connectionToSessionIdMap.ContainsKey(conn))
            {
                break;
            }
        }

        if (!connectionToSessionIdMap.ContainsKey(conn))
        {
            Debug.Log("Could not map player with current cached sessions");
            yield return GetNewSessionList();

            foreach (string sessionId in newSessions)
            {
                yield return GetSessionAndMap(conn, sessionId, clientAddress);

                if (connectionToSessionIdMap.ContainsKey(conn))
                {
                    break;
                }
            }
        }
    }

    private IEnumerator GetSessionAndMap(NetworkConnectionToClient conn, string sessionId, string clientAddress)
    {
        Debug.Log($"Fetching session details for session ID: {sessionId}");
        string url = $"{edgegapUrl}/session/{sessionId}";
        UnityWebRequest request = UnityWebRequest.Get(url);
        request.SetRequestHeader("Authorization", apiToken);

        yield return request.SendWebRequest();

        if (request.result == UnityWebRequest.Result.Success)
        {
            Debug.Log("Session fetched successfully.");
            string responseText = request.downloadHandler.text;
            Debug.Log("Session Response: " + responseText);

            var session = JObject.Parse(responseText);
            var sessionUsers = session["session_users"] as JArray;

            if (sessionUsers != null && sessionUsers.Count > 0)
            {
                Debug.Log($"Found {sessionUsers.Count} users in session.");
                foreach (var user in sessionUsers)
                {
                    string playerIp = user["ip"]?.ToString();
                    Debug.Log($"Player IP: {playerIp}, Connection IP: {clientAddress}");
                    if (playerIp == clientAddress)
                    {
                        connectionToSessionIdMap[conn] = sessionId;
                        Debug.Log($"Mapped session ID {sessionId} to connection {conn.connectionId} with IP {playerIp}");

                        // Additional confirmation logging
                        if (connectionToSessionIdMap.ContainsKey(conn))
                        {
                            Debug.Log($"Session ID {sessionId} successfully stored for connection {conn.connectionId} with IP {playerIp}");
                        }
                        else
                        {
                            Debug.LogError($"Failed to store session ID {sessionId} for connection {conn.connectionId} with IP {playerIp}");
                        }

                        break;
                    }
                }
            }
            else
            {
                Debug.LogError("No users found in session.");
            }
        }
        else
        {
            Debug.LogError($"Error fetching session: {request.error}");
            Debug.LogError($"Response Code: {request.responseCode}");
            Debug.LogError($"Response Text: {request.downloadHandler.text}");
        }

        mappingInProgress[conn] = false; // Set mapping in progress to false once done
    }

    public override void OnServerDisconnect(NetworkConnectionToClient conn)
    {
        base.OnServerDisconnect(conn);
        Debug.Log($"Server disconnected client: {conn.connectionId}");

        StartCoroutine(HandleDisconnect(conn));
    }

    private IEnumerator HandleDisconnect(NetworkConnectionToClient conn)
    {
        while (mappingInProgress.ContainsKey(conn) && mappingInProgress[conn])
        {
            Debug.Log($"Waiting for session mapping to complete for connection {conn.connectionId}...");
            yield return new WaitForSeconds(0.1f);
        }

        if (connectionToSessionIdMap.TryGetValue(conn, out string sessionId))
        {
            Debug.Log($"Deleting session ID: {sessionId}");
            StartCoroutine(DeleteSession(sessionId));
            connectionToSessionIdMap.Remove(conn);
            mappingInProgress.Remove(conn);
            currentDeploymentSessions.Remove(sessionId);
        }
        else
        {
            Debug.LogWarning("No session ID found for this connection.");
        }
    }

    private IEnumerator DeleteSession(string sessionId)
    {
        Debug.Log($"Sending request to delete session ID: {sessionId}");
        string url = $"{edgegapUrl}/session/{sessionId}";
        UnityWebRequest request = UnityWebRequest.Delete(url);
        request.SetRequestHeader("Authorization", apiToken);

        yield return request.SendWebRequest();

        if (request.result == UnityWebRequest.Result.Success)
        {
            Debug.Log("Session deleted successfully.");
        }
        else
        {
            Debug.LogError($"Error deleting session: {request.error}");
            Debug.LogError($"Response Code: {request.responseCode}");
            Debug.LogError($"Response Text: {request.downloadHandler.text}");
        }
    }

}
```

#### Optional features

This script can be expanded upon with optional, independent features that help manage the sessions in specific cases.

For example, a `timeout` can be set to remove `empty seat sessions` after a configurable amount of time `following full server initialization`. This is a useful feature in the case of a player that quits before their matchmaker ticket gets resolved, which would create an empty session once a match is found. If the player never sends their IP address to be mapped to the session ID before the timeout resolves, then that session gets deleted to free up a socket.

Another feature can be to `disconnect inactive players` after a prolonged period of time in order to free up sockets. Once connected to the server, the client needs to `send some minimalistic heartbeat message` to the server `every few seconds`, or otherwise gets disconnected if too many `heartbeats are missed in a row`. Both the amount of time between heartbeats and the maximum number of messages that can be missed in a row can be configured, depending on the game's needs. In this sample, a heartbeat gets sent every few seconds if the tank is moving around the map or shooting.

#### PlayerNetworkBehaviour - Seat Session Management

```cs
    public class PlayerNetworkBehaviour : NetworkBehaviour
    {
        private bool enableInactiveTimeout;
        private float clientTimeSinceLastHeartbeat = 0;
        private float secondsBetweenHeartbeats;

        [ClientRpc]
        public void RpcSendClientIpAddress()
        {
            StartCoroutine(FetchPublicIpAndSendToServer());
            secondsBetweenHeartbeats = CustomNetworkManager.Instance.GetSecondsBetweenHeartbeats();
            enableInactiveTimeout = CustomNetworkManager.Instance.IsEnableInactiveTimeout();
            clientTimeSinceLastHeartbeat = secondsBetweenHeartbeats;
        }

        ...

        private void Update()
        {
            if (isLocalPlayer && enableInactiveTimeout)
            {
                float horizontal = Input.GetAxis("Horizontal");
                float vertical = Input.GetAxis("Vertical");

                if (clientTimeSinceLastHeartbeat >= secondsBetweenHeartbeats && (Input.GetKeyDown(KeyCode.Space) || horizontal != 0 || vertical != 0))
                {
                    CmdSendHeartbeatTimeToServer(NetworkTime.predictedTime);
                    clientTimeSinceLastHeartbeat = 0;
                }

                clientTimeSinceLastHeartbeat += Time.deltaTime;
            }
        }

        [Command]
        public void CmdSendHeartbeatTimeToServer(double time)
        {
            NetworkConnectionToClient conn = connectionToClient;
            if (conn != null)
            {
                CustomNetworkManager.Instance.StoreClientHeartbeatTime(conn, time);
            }
            else
            {
                Debug.LogError("Connection not found.");
            }
        }
    }
```

#### CustomNetworkManager - Seat Session Management

```cs
public class CustomNetworkManager : NetworkManager
{
    ...
    private bool listInProgress = false;

    [Header("Empty Session Timeout")]
    [SerializeField] private bool enableEmptyTimeout;
    [SerializeField] private float deleteAfterSeconds = 15f;

    [Header("Inactive Player Timeout")]
    [SerializeField] private bool enableInactiveTimeout;
    [SerializeField] private int maxMissedHeartbeats = 3;
    [SerializeField] private float secondsBetweenHeartbeats = 3f;
    private Dictionary<NetworkConnectionToClient, double> connectionToLastHeartbeatMap = new();

    ...

    public override void OnStartServer()
    {
        base.OnStartServer();
        deploymentId = Environment.GetEnvironmentVariable("ARBITRIUM_REQUEST_ID");
        apiToken = Environment.GetEnvironmentVariable("API_TOKEN");
        if (string.IsNullOrEmpty(apiToken))
        {
            Debug.LogError("Edgegap API token not found in environment variables.");
        }
        else
        {
            Debug.Log("Edgegap API token found: " + apiToken);
        }

        StartCoroutine(InitiateSessionManage());
    }

    private IEnumerator InitiateSessionManage()
    {
        yield return new WaitForSeconds(0.5f);

        StartCoroutine(GetNewSessionList());

        if (enableEmptyTimeout)
        {
            StartCoroutine(StartServerInitSessionsTimeout());
        }
    }

    ...

    private IEnumerator GetNewSessionList()
    {
        listInProgress = true;
        newSessions.Clear();
        string url = $"{edgegapUrl}/status/{deploymentId}";
        UnityWebRequest request = UnityWebRequest.Get(url);
        request.SetRequestHeader("Authorization", apiToken);

        yield return request.SendWebRequest();

        if (request.result == UnityWebRequest.Result.Success)
        {
            string responseText = request.downloadHandler.text;
            Debug.Log("Deployment Status Response: " + responseText);

            var json = JObject.Parse(responseText);
            var sessions = json["sessions"] as JArray;

            foreach (var session in sessions)
            {
                string sessionId = session["session_id"]?.ToString();

                if (!currentDeploymentSessions.Contains(sessionId))
                {
                    newSessions.Add(sessionId);
                    currentDeploymentSessions.Add(sessionId);
                }
            }

            Debug.Log("New session list initialized");
        }
        else
        {
            Debug.LogError($"Error fetching session list: {request.error}");
            Debug.LogError($"Response Code: {request.responseCode}");
            Debug.LogError($"Response Text: {request.downloadHandler.text}");
        }

        listInProgress = false;
    }

    ...

    private IEnumerator GetSessionAndMap(NetworkConnectionToClient conn, string sessionId, string clientAddress)
    {
        Debug.Log($"Fetching session details for session ID: {sessionId}");
        string url = $"{edgegapUrl}/session/{sessionId}";
        UnityWebRequest request = UnityWebRequest.Get(url);
        request.SetRequestHeader("Authorization", apiToken);

        yield return request.SendWebRequest();

        if (request.result == UnityWebRequest.Result.Success)
        {
            Debug.Log("Session fetched successfully.");
            string responseText = request.downloadHandler.text;
            Debug.Log("Session Response: " + responseText);

            var session = JObject.Parse(responseText);
            var sessionUsers = session["session_users"] as JArray;

            if (sessionUsers != null && sessionUsers.Count > 0)
            {
                Debug.Log($"Found {sessionUsers.Count} users in session.");
                foreach (var user in sessionUsers)
                {
                    string playerIp = user["ip"]?.ToString();
                    Debug.Log($"Player IP: {playerIp}, Connection IP: {clientAddress}");
                    if (playerIp == clientAddress)
                    {
                        connectionToSessionIdMap[conn] = sessionId;
                        Debug.Log($"Mapped session ID {sessionId} to connection {conn.connectionId} with IP {playerIp}");

                        if (enableInactiveTimeout)
                        {
                            connectionToLastHeartbeatMap[conn] = conn.lastMessageTime;
                            StartCoroutine(CheckClientHeartbeat(conn));
                        }

                        // Additional confirmation logging
                        if (connectionToSessionIdMap.ContainsKey(conn))
                        {
                            Debug.Log($"Session ID {sessionId} successfully stored for connection {conn.connectionId} with IP {playerIp}");
                        }
                        else
                        {
                            Debug.LogError($"Failed to store session ID {sessionId} for connection {conn.connectionId} with IP {playerIp}");
                        }

                        break;
                    }
                }
            }
            else
            {
                Debug.LogError("No users found in session.");
            }
        }
        else
        {
            Debug.LogError($"Error fetching session: {request.error}");
            Debug.LogError($"Response Code: {request.responseCode}");
            Debug.LogError($"Response Text: {request.downloadHandler.text}");
        }

        mappingInProgress[conn] = false; // Set mapping in progress to false once done
    }

    ...

    #region EmptySessionTimeout

    private IEnumerator StartServerInitSessionsTimeout()
    {
        while (listInProgress)
        {
            Debug.Log($"Waiting to retrieve session list...");
            yield return new WaitForSeconds(0.1f);
        }

        foreach (string sessionId in currentDeploymentSessions)
        {
            StartCoroutine(WaitForConnectionTimeout(sessionId));
        }
    }

    private IEnumerator WaitForConnectionTimeout(string sessionID)
    {
        Debug.Log($"Checking for empty timeout on session {sessionID}");
        bool delete = false;
        DateTime timeout = DateTime.Now.AddSeconds(deleteAfterSeconds);

        while (!connectionToSessionIdMap.ContainsValue(sessionID))
        {
            yield return new WaitForSeconds(0.1f);
            if (DateTime.Now >= timeout)
            {
                delete = true;
                break;
            }
        }

        if (delete && !connectionToSessionIdMap.ContainsValue(sessionID))
        {
            Debug.Log($"No connection initiated by client after {deleteAfterSeconds}s, deleting session {sessionID}");
            StartCoroutine(DeleteSession(sessionID));
            currentDeploymentSessions.Remove(sessionID);
            newSessions.Remove(sessionID);
        }
    }

    #endregion

    #region InactivePlayerTimeout

    private IEnumerator CheckClientHeartbeat(NetworkConnectionToClient conn)
    {
        int counter = 0;

        while (counter < maxMissedHeartbeats && connectionToSessionIdMap.ContainsKey(conn))
        {
            double lastHeartbeatDiff = NetworkTime.localTime - connectionToLastHeartbeatMap[conn];

            if (lastHeartbeatDiff >= secondsBetweenHeartbeats)
            {
                counter += 1;

                Debug.Log($"Connection {conn.connectionId} has missed {counter} heartbeat(s) in a row");
            }
            else
            {
                counter = 0;
                Debug.Log($"Reset heartbeat counter for connection {conn.connectionId}");
            }

            yield return new WaitForSeconds(secondsBetweenHeartbeats);
        }

        if (counter >= maxMissedHeartbeats && conn.isReady)
        {
            Debug.Log($"Connection {conn.connectionId} inactive for too long, disconnecting");
            conn.Disconnect();
            connectionToLastHeartbeatMap.Remove(conn);
        }
    }

    public void StoreClientHeartbeatTime(NetworkConnectionToClient conn, double time)
    {
        connectionToLastHeartbeatMap[conn] = time;
    }

    public float GetSecondsBetweenHeartbeats() => secondsBetweenHeartbeats;

    public bool IsEnableInactiveTimeout() => enableInactiveTimeout;

    #endregion
}
```


# Fishnet

Explore how to host Unity projects on Edgegap using techniques from the FishNet HashGrid Sample.

{% embed url="<https://youtu.be/9Tnlgklg_qY>" %}

## ✔️ Preparation

Before we start, you will need:

* Unity 6 - [download using Unity Hub](https://unity.com/releases/unity-6),
* FishNet Unity package - [download from Unity Asset Store](https://assetstore.unity.com/packages/tools/network/fishnet-networking-evolved-207815),
  * this package includes the HashGrid sample.

Create a new project and import the FishNet package above.

## ⚡ Deploy and Connect

### 1. Deploy a Server on Edgegap

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

☑️ [Create a new app version for your application](https://app.edgegap.com/application-management/applications/fishnet-hashgrid-sample/versions/create), choose FishNet HashGrid Sample.

☑️ [Deploy a server with your FishNet HashGrid Sample app version](https://app.edgegap.com/deployment-management/deployments/list).

☑️ [Open your new deployment's details](https://app.edgegap.com/deployment-management/deployments/list).

☑️ Find your deployment's unique, one-time connection details:

* **Host URL** in format `780aa4260e83.pr.edgegap.net` ,
* **External Port** in format `30854`  (5 digits).

✅ You may now proceed to the next step.

### 2. Connect from Editor

☑️ Open your new project in Unity.

☑️ Open scene in folder FishNet / Demos / HashGrid / Scenes / HashGrid\_Demo.unity.

☑️ Select NetworkManager object in the scene, and modify Tugboat component in Inspector:

* set Client / Client Address to **Host URL** from previous step,
* set Server / Port to **External Port** from previous step.

☑️ Expand NetworkManager child game objects and select NetworkHudCanvas, then set `Auto Start Type`  to `Disabled`  to prevent your editor from starting in client-host mode.

☑️ Press the ▶️ Play button to start your game client.

☑️ Press Client button to connect to your server.

☑️ Connect a second virtual Player with [Multiplayer Play Mode](https://docs-multiplayer.unity3d.com/mppm/current/about/) or [ParrelSync](https://github.com/VeriorPies/ParrelSync).

🙌 Congratulations on your first Deployment on Edgegap!

## ✏️ Customize Server Build

To ensure your server build starts properly:

* edit your build profile (**Edit Build Settings** in Edgegap plugin) and add your scene,
* set `Auto Start Type`  to `Server`  in `NetworkHudCanvases`  component (child of `NetworkManager`),
* enable `Reuse Server Address` in your `Tugboat`  component to prevent error `AddressAlreadyInUse`.

{% hint style="success" %}
See [unity](https://docs.edgegap.com/unity "mention") for Unity to **learn how to build and customize servers**.
{% endhint %}


# Photon Bolt

This guide will help you create a headless server on Edgegap for a Unity project using Photon Bolt as its networking solution.

In this guide, we will be using a custom demonstration project as an example.

### Preparing the Unity project

### Clone the Unity project

The first step is to clone the Edgegap demo game project from git. You can do so using this command in your command prompt:

The command will create a folder containing the source Unity project, called `demo-game`.

Once the process is over, you can open Unity Hub and add the project by pressing the `Add` button in the Projects tab then finding the project's folder on your computer:

To open the project, you will need to have the correct version of Unity installed. In our case, we will use Unity `2020.3.3`. You can find it by visiting Unity's download archive: <https://unity3d.com/get-unity/download/archive>.

Once the installation is complete, you can now select the new Unity version through the drop-down menu adjacent to the project name in Unity Hub:

You can now open the Unity project to proceed to the next steps.

### Setting up the game

### Setting up Photon Bolt

#### Add Photon App ID and compile Bolt

For the game to communicate with Photon's services, you will need to add an App to your Photon dashboard. If you do not have an account with Photon yet, you can easily create one on their [website](https://id.photonengine.com/Account/).

Once signed in, you can create an app and give it a name. Every app has its unique `App ID`. You will need to copy and paste this ID in the `Bolt Settings` window within the Unity project:

<figure><img src="https://3027732442-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2Fgit-blob-85755915f46bb51ed45784518d86ce278e998650%2Funity_photon_bolt_settings.png?alt=media" alt=""><figcaption></figcaption></figure>

<figure><img src="https://3027732442-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2Fgit-blob-fccf1cdf65056d42522cd4405f5a5dfbc5265106%2Funity_photon_bolt_app_id.png?alt=media" alt=""><figcaption></figcaption></figure>

Once you enter the ID, you can close the Bolt Settings window. In the same `Bolt` menu as before, you will have to execute two actions: `Update Prefab Database` and `Compile Assembly`, respectively.

<figure><img src="https://3027732442-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2Fgit-blob-93c9dc4b160db8a4b12142313da2c48bdb6a05cb%2Funity_photon_bolt_compile.png?alt=media" alt=""><figcaption></figcaption></figure>

At this point, you should be able to launch the game's `StartScene` scene without any errors or warnings in the debug console. However, you cannot start playing on a server just yet.

That concludes the generic changes needed for your Photon Bolt to work. These changes will work both for the clients and servers of your game.

### Preparing a headless server

For your app to work with containers efficiently, you will need to make a few changes to your game to create a "headless server" build. For most projects, this will only require a few straightforward steps.

#### Requirements for the Unity project

First, it is essential to note that Photon Bolt's headless server mode requires loading a scene holding a script called `HeadlessServerManager`.

The generic, unaltered script in question (taken from Bolt's documentation) looks like this:

```cs
using System;
using Bolt.Matchmaking;
using Bolt.Photon;
using UnityEngine;
using UnityEngine.SceneManagement;

namespace Bolt.Samples.HeadlessServer
{
    public class HeadlessServerManager : Bolt.GlobalEventListener
    {
        public string Map = "";
        public string GameType = "";
        public string RoomID = "";

        public override void BoltStartBegin(" alt=""><figcaption></figcaption></figure>
        {
            // Register any Protocol Token that are you using
            BoltNetwork.RegisterTokenClass<PhotonRoomProperties>();
        }

        public override void BoltStartDone()
        {
            if (BoltNetwork.IsServer)
            {
                // Create some room custom properties
                PhotonRoomProperties roomProperties = new PhotonRoomProperties();

                roomProperties.AddRoomProperty("t", GameType); // ex: game type
                roomProperties.AddRoomProperty("m", Map); // ex: map id

                roomProperties.IsOpen = true;
                roomProperties.IsVisible = true;

                // If RoomID was not set, create a random one
                if (RoomID.Length == 0)
                {
                    RoomID = Guid.NewGuid().ToString();
                }

                // Create the Photon Room
                BoltMatchmaking.CreateSession(
                    sessionID: RoomID,
                    token: roomProperties,
                    sceneToLoad: Map
                );
            }
        }

        // Use this for initialization
        void Start()
        {
            // Get custom arguments from command line
            Map = GetArg("-m", "-map") ?? Map;
            GameType = GetArg("-t", "-gameType") ?? GameType; // ex: get game type from command line
            RoomID = GetArg("-r", "-room") ?? RoomID;

            // Validate the requested Level
            var validMap = false;

            foreach (string value in BoltScenes.AllScenes)
            {
                if (SceneManager.GetActiveScene().name != value)
                {
                    if (Map == value)
                    {
                        validMap = true;
                        break;
                    }
                }
            }

            if (!validMap)
            {
                BoltLog.Error("Invalid configuration: please verify level name");
                Application.Quit();
            }

            // Start the Server
            BoltLauncher.StartServer();
            DontDestroyOnLoad(this);
        }

        /// <summary>
        /// Utility function to detect if the game instance was started in headless mode.
        /// </summary>
        /// <returns><c>true</c>, if headless mode was ised, <c>false</c> otherwise.</returns>
        public static bool IsHeadlessMode()
        {
            return Environment.CommandLine.Contains("-batchmode") && Environment.CommandLine.Contains("-nographics");
        }

        static string GetArg(params string[] names)
        {
            var args = Environment.GetCommandLineArgs();
            for (int i = 0; i < args.Length; i++)
            {
                foreach (var name in names)
                {
                    if (args[i] == name && args.Length > i + 1)
                    {
                        return args[i + 1];
                    }
                }
            }

            return null;
        }
    }
}
```

Usually, it will be held by an empty GameObject in an empty scene (which will only be used for headless server builds).

The script has been slightly altered for this demo to fit the project's structure, and it is currently placed in an empty GameObject in a scene located in `Assets/Scenes/BoltHeadlessServer`.

#### Adding headless server checks to your game

The above script contains a static utility method called `IsHeadlessMode`, to be used to check if the running game is headless or not. If you are updating an existing project, you might want to add this check to remove or add features for the headless server, like preventing the instantiation of a player character.

#### Build settings

In the `Buid Settings` of the project, add the `BoltHeadlessServer` scene at the very top, so it is the first to be loaded by the server.

Next, choose `Linux` as the target platform and check `Server Build`.

<figure><img src="https://3027732442-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2Fgit-blob-119e3c54e779d1120313d9dbba22037fbe3670ca%2Funity_photon_bolt_build_settings.png?alt=media" alt=""><figcaption></figcaption></figure>

Now you can build your game under Linux with the above settings.

For **client builds**, do not forget to uncheck the `BoltHeadlessServer` scene and the `IsServer` option so your game functions properly.

For every step concerning the making of a headless server for Photon Bolt, more details are available in the [official documentation](https://doc.photonengine.com/en-us/bolt/current/demos-and-tutorials/headless-server).

### Create a container for the server

If you aren't familiar with Docker or containers, you can learn more by checking out [What is Docker?](https://docs.edgegap.com/docs/tools-and-integrations/container/docker)

To create a container from a Unity project, please refer to [Unity on Docker](https://docs.edgegap.com/docs/sample-projects/unity-netcodes/broken-reference).

### Add your app to Edgegap

You can now add your container to Edgegap so it can be hosted everywhere your players are.

If you don't know how to add an app to Edgegap, please refer to the [integration tutorial](https://docs.edgegap.com/learn/orchestration/application-and-versions).

However, you will need to make sure the name of your app is `demo-game` and that it has a version called `v1`. Else, you will need to update these values in the script located in `Assets/Scripts/StaginController.cs`.

Also, within the `Assets/Scripts/StaginController.cs` script, you will find a constant variable called `API_TOKEN`. You will need to create a token from your Edgegap account and paste it as a string into this variable. That token will be used to authorize the API requests sent to Edgegap.

Here is the script in question, with the token from Edgegap in blue and the app parameters in red:

<figure><img src="https://3027732442-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2Fgit-blob-356f4d51a5c114024fea432e8fcd9b677d3c9e98%2Funity_photon_bolt_staging_controller.png?alt=media" alt=""><figcaption></figcaption></figure>

## Playing the demo game

Finally, you can start a demo game client build to play it. You can either build a client version of the game and launch or play it directly from the Unity interface. Just make sure to start it on the `StartScene` scene.

Once launched, an interface will show up. It contains a text field at the top, two large buttons and a label at the bottom left of the screen showing Bolt's current state.

<figure><img src="https://3027732442-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2Fgit-blob-3ace5ac3f2d80112f7564e85fdcf8c65d844bf34%2Funity_photon_bolt_demo_game.png?alt=media" alt=""><figcaption></figcaption></figure>

You can copy your API Token from Edgegap into the text field at the top. Once your Token is pasted, you can now press the `Request Server` button to send an API call to Edgegap to start a server.

A few seconds later, you should see the label at the bottom of the interface showing the number of available servers. You will now press the `Connect to a random server` button to join a game and start playing.


# Mirror WebGL

This guide will help you use [Mirror](https://mirror-networking.com/)'s Websocket Transport and create a headless server on Edgegap for a Unity project.

This guide will use the open-source sample project `Tanks`, available in the Mirror sample under `Assets/Mirror/Examples/Tanks`.

You can find the final version of this sample on our [GitHub](https://github.com/edgegap/mirror-webgl)

### Switch the transport

We first need to make some changes to the base scene before we're ready to build the game server.

* Open `Scene.unity` located under `Assets/Mirror/Examples/Tanks/Scenes`;
* In the `NetworkManager` gameObject, remove the `KcpTransport` script and replace it with the `SimpleWebTransport` located under `Assets/Mirror/Transports/SimpleWeb`, make sure to also update the Transport field of the `NetworkManager` script component with this new transport. Make sure that the `Auto Start Server Build` option is selected as well.
* Depending on your version of Mirror, you might need to change/update the `NetworkManagerHUD` to make it work with different transports than KCP, as well as to let you input the port value in the HUD before joining a server.

Take note of the port used for network communications, referred as the `[GAME PORT]`. In this case, the port used is `7778`.

### Build the game server & Containerizing

{% hint style="info" %}
To facilitate the containerizing and deployment process, it's possible to use the latest version of the Edgegap Unity Plugin on our [GitHub](https://github.com/edgegap/edgegap-unity-plugin) to automate the process. For more information on how to use this plugin, you can check our [documentation](https://docs.edgegap.com/docs/sample-projects/unity-netcodes/broken-reference).

If you want instead, you may also follow these step-by-step instructions.
{% endhint %}

Once ready with your game, head to the `Build` screen of the Unity Editor, under `File -> Build Settings` in the top menus. Make sure to select the right presets depending on your version of Unity.

* Prior to version 2021.2:
  * Set `Target Platform` to `Linux`;
  * Set `Architecture` to `x86_64`;
  * Check the `Server Build` option.
* Otherwise:
  * Set `Platform` to `Dedicated Server`;
  * Set `Target Platform` to `Linux`.

Then press build and select a new empty folder named `linux_server` as the file destination. Transfer the `linux_server` folder to a second empty folder, which will be refered as the `[SERVER BUILD]` folder in this document. Add the following `Dockerfile` and `boot.sh` file to the `[SERVER BUILD]` folder:

#### Dockerfile

```
FROM ubuntu:bionic
MAINTAINER <author_detail>

ARG DEBIAN_FRONTEND=noninteractive
ARG docker_version=17.06.0-ce

RUN
    apt-get update && \
    apt-get install -y libglu1 xvfb libxcursor1 ca-certificates && \
    update-ca-certificates && \
    apt-get clean

EXPOSE 7778/TCP

COPY linux_server/  /root/linux_server/
COPY boot.sh        /boot.sh

WORKDIR /root/
ENTRYPOINT ["/bin/bash", "/boot.sh"]
```

#### boot.sh

```
xvfb-run --auto-servernum --server-args='-screen 0 640x480x24:32' /root/linux_server/[YOUR GAME].x86_64 -batchmode -nographics
```

Make sure to replace the `[YOUR GAME]` placeholders with the name of the generated file

Then, start a command prompt in the `[SERVER BUILD]` folder; Run the following Docker commands to create an image of your build and push it to a private registry:

{% hint style="warning" %}
For ARM CPU (Mac M1, M2, etc.) users, add `--platform linux/amd64`  option to your build command.
{% endhint %}

#### Using Linux

```bash
# build the image
docker build . -t <IMAGE_NAME>:<IMAGE_TAG>

# login, a prompt will ask the password
docker login -u '<REGISTRY_USERNAME>' <REGISTRY_URL>

# add another tag to your image corresponding to the registry
docker image tag <IMAGE_NAME>:<IMAGE_TAG> <REGISTRY_URL>/<PROJECT_NAME>/<IMAGE_NAME>:<IMAGE_TAG>

#push the image
docker push <REGISTRY_URL>/<PROJECT_NAME>/<IMAGE_NAME>:<IMAGE_TAG>
```

#### Using cmd

```bash
# build the image
docker build . -t <IMAGE_NAME>:<IMAGE_TAG>

# login, a prompt will ask the password
docker login -u <REGISTRY_USERNAME> <REGISTRY_URL>

# add another tag to your image corresponding to the registry
docker image tag <IMAGE_NAME>:<IMAGE_TAG> <REGISTRY_URL>/<PROJECT_NAME>/<IMAGE_NAME>:<IMAGE_TAG>

#push the image
docker push <REGISTRY_URL>/<PROJECT_NAME>/<IMAGE_NAME>:<IMAGE_TAG>
```

#### Using Powershell

```bash
# build the image
docker build . -t <IMAGE_NAME>:<IMAGE_TAG>

# login, a prompt will ask the password
docker login -u '<REGISTRY_USERNAME>' <REGISTRY_URL>

# add another tag to your image corresponding to the registry
docker image tag <IMAGE_NAME>:<IMAGE_TAG> <REGISTRY_URL>/<PROJECT_NAME>/<IMAGE_NAME>:<IMAGE_TAG>

#push the image
docker push <REGISTRY_URL>/<PROJECT_NAME>/<IMAGE_NAME>:<IMAGE_TAG>
```

### Deploying server to Edgegap

After logging in on the Edgegap Dashboard, navigate to the `Applications & Games` page. Click on the `Create New` button in the top right hand corner to access the application form. Here are the fields and how to fill them properly:

* Application name : Can be any notable name you want to use to easily recognize your application among others.
* Image : Can be any specific image you want to use to easily recognize your application among others.
* Version name : You may want to use a version name to describe the scope of the version you are deploying. Examples may be “demo”, “production”, “v1”, “v2”
* Container :
  * Registry : “\[URL]”, where \[URL] is the value from the credentials you can display on the Container Repository page.
  * Image repository : “\[PROJECT]/\[YOUR GAME]”, where \[PROJECT] and \[YOUR GAME] are the values you used earlier when pushing the docker image.
  * Tag : “\[TAG]”, where \[TAG] is the value you used earlier when pushing the docker image.
  * Tick “Using a private repository”
  * Private registry username : “\[USERNAME]”, where \[USERNAME] is the value from your credentials.
  * Private registry token : “\[TOKEN]”, where \[TOKEN] is the value from your credentials.
  * Requirements : Left as is.
  * Ports : Click the `+ Add port` link to add a new port, and add the following entries :
    * `7778` - WS - enable TLS Upgrade (Beta)

{% hint style="warning" %}
If you use the WSS option, it is important to enable the `TLS Upgrade` option. Otherwise, you will encounter errors similar to this one in your container logs on the Edgegap dashboard.

```cmd
First bytes from client was not 'GET' for handshake, instead was 16-03-01
```

{% endhint %}

<figure><img src="https://3027732442-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2Fgit-blob-4996c904d603b04628fdd82091b1d3a5768aac40%2Fserver-port.png?alt=media" alt=""><figcaption></figcaption></figure>

Once your application has been created, you can press the `Deploy` button to proceed with deploying your game server. Once the latest status of you deployment is set to `Ready`, you will be able to connect to the server with a client version of the game. Take note of the `Host` url and, in the Port Mapping tab of your deployment, the `external port` that's publicly available.

### Testing the client

#### In the editor

Back in the Unity editor in the tank scene, select the `NetworkManager` gameObject and change the following settings:

* In the `Network Manager` component:
  * Set the `Network Address` to the the server deployment's `Host` url;
  * Uncheck the `Auto Start Server Build` option.
* In the `Simple Web Transport` component:
  * Set the `Port` value to the Edgegap deployment's `external port` e.g.: `32821`;
  * Make sure the `Client Use WSS` option is enabled.

<figure><img src="https://3027732442-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2Fgit-blob-8fe3a5d63fc65f33f18d8e0c39a5d2d5a5b97e6c%2Fnetwork-manager-client-settings-1.png?alt=media" alt=""><figcaption></figcaption></figure>

<figure><img src="https://3027732442-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2Fgit-blob-8a7da870b869174fc4117dc6e6e44edb8e62b906%2Fnetwork-manager-client-settings-2.png?alt=media" alt=""><figcaption></figcaption></figure>

Once this is done, click `Play` in the editor, then click the `Client` button; You'll get connected to the server and be able to play the game after a short moment.

#### On Itch.io

To put your game client on Itch, you will need to make a client build; You will need to install the `WebGL Build Support` module for your version of Unity to do that. Once that's done, head back to the `Build` screen of the Unity Editor, under `File -> Build Settings`, and select the following options:

* Set `Platform` to `WebGL`;
* Open up the `Player Settings`. Under `Player -> Publishing Settings`, set the `Compression Format` to `Gzip` and make sure the `Decompression Fallback` option is selected. Save these settings, and close the window.

<figure><img src="https://3027732442-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2Fgit-blob-04b0077a769072f95884b660b71bc3e93655f6a6%2Fclient-build.png?alt=media" alt=""><figcaption></figcaption></figure>

Then press build and select a new empty folder named `build` as the file destination. Transfer the `build` folder to a second empty folder, which will be refered as the `[CLIENT BUILD]` folder in this document.

Once your game has finished building, compress the files of this `build` folder into a zip folder, making sure that they are at the root of it. Then you simply need to upload the zip folder to your Itch project, and make sure to select the option for the file to play in the browser. Once you launch the game, you just need to make sure that the network address and port values are set correctly in the HUD, then click the `Client` button to play.

#### Hosting the client on Edgegap

It's even possible to host your game client on Edgegap! To do so, add the following `Dockerfile` and `nginx.conf` file to the `[CLIENT BUILD]` folder:

**Dockerfile**

```
FROM nginx:alpine
MAINTAINER <author_detail>

COPY build/ /usr/share/nginx/html
copy nginx.conf /etc/nginx/
```

**nginx.conf**

```
user  nginx;
worker_processes  auto;

error_log  /var/log/nginx/error.log notice;
pid        /var/run/nginx.pid;


events {
worker_connections  1024;
}


http {
include       /etc/nginx/mime.types;
default_type  application/octet-stream;

log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';

access_log  /var/log/nginx/access.log  main;

sendfile        on;
#tcp_nopush     on;

keepalive_timeout  65;

#gzip  on;

include /etc/nginx/conf.d/*.conf;

server {
# Add the following config within http server configuration
# ...

    # On-disk Brotli-precompressed data files should be served with compression enabled:
    location ~ .+\.(data|symbols\.json)\.br$ {
        # Because this file is already pre-compressed on disk, disable the on-demand compression on it.
        # Otherwise nginx would attempt double compression.
        gzip off;
        add_header Content-Encoding br;
        default_type application/octet-stream;
    }

    # On-disk Brotli-precompressed JavaScript code files:
    location ~ .+\.js\.br$ {
        gzip off; # Do not attempt dynamic gzip compression on an already compressed file
        add_header Content-Encoding br;
        default_type application/javascript;
    }

    # On-disk Brotli-precompressed WebAssembly files:
    location ~ .+\.wasm\.br$ {
        gzip off; # Do not attempt dynamic gzip compression on an already compressed file
        add_header Content-Encoding br;
        # Enable streaming WebAssembly compilation by specifying the correct MIME type for
        # Wasm files.
        default_type application/wasm;
    }

    # On-disk gzip-precompressed data files should be served with compression enabled:
    location ~ .+\.(data|symbols\.json)\.gz$ {
        gzip off; # Do not attempt dynamic gzip compression on an already compressed file
        add_header Content-Encoding gzip;
        default_type application/octet-stream;
    }

    # On-disk gzip-precompressed JavaScript code files:
    location ~ .+\.js\.gz$ {
        gzip off; # Do not attempt dynamic gzip compression on an already compressed file
        add_header Content-Encoding gzip;
        default_type application/javascript;
    }

    # On-disk gzip-precompressed WebAssembly files:
    location ~ .+\.wasm\.gz$ {
        gzip off; # Do not attempt dynamic gzip compression on an already compressed file
        add_header Content-Encoding gzip;
        # Enable streaming WebAssembly compilation by specifying the correct MIME type for
        # Wasm files.
        default_type application/wasm;
    }
}
}
```

Proceed with the [same Docker commands as before](#bootsh) to build and push an image of your game client to a private repository, but from a command window opened in the `[CLIENT BUILD]` folder. Make sure to use a different image name than the one for your server.

Then, create a new application for your client on the Edgegap dashboard with the following settings:

* Application name : Can be any notable name you want to use to easily recognize your application among others.
* Image : Can be any specific image you want to use to easily recognize your application among others.
* Version name : You may want to use a version name to describe the scope of the version you are deploying. Examples may be “demo”, “production”, “v1”, “v2”
* Container :
  * Registry : “\[URL]”, where \[URL] is the value from the credentials you can display on the Container Repository page.
  * Image repository : “\[PROJECT]/\[YOUR GAME]”, where \[PROJECT] and \[YOUR GAME] are the values you used earlier when pushing the docker image.
  * Tag : “\[TAG]”, where \[TAG] is the value you used earlier when pushing the docker image.
  * Tick “Using a private repository”
  * Private registry username : “\[USERNAME]”, where \[USERNAME] is the value from your credentials.
  * Private registry token : “\[TOKEN]”, where \[TOKEN] is the value from your credentials.
  * Requirements : Left as is.
  * Ports : Click the `+ Add port` link to add a new port, and add the following entries :
    * `80` - HTTPS

<figure><img src="https://3027732442-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2Fgit-blob-f88e313ed093082a221680f4b59b241afe7cbf70%2Fclient-port.png?alt=media" alt=""><figcaption></figcaption></figure>

Once your application has been created, you can press the `Deploy` button to proceed with deploying your game client. With both the server and client deployments set to `Ready`, open the game client's `Host` url at the specified `external port` in your browser, and you'll be able to play the game after setting the correct values in the game's HUD!

<figure><img src="https://3027732442-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2Fgit-blob-b140451a9c9404cba2498e715c6c83abb656e655%2Fonline-client.png?alt=media" alt=""><figcaption></figcaption></figure>

{% hint style="info" %}
If you need more information about the Mirror integration and websocket, you can refer to their [documentation](https://mirror-networking.gitbook.io/docs/manual/transports/websockets-transport).
{% endhint %}


# Fishnet WebGL

This guide will help you use [FishNet](https://github.com/FirstGearGames/FishNet)'s Websocket Transport, [Bayou](https://fish-networking.gitbook.io/docs/manual/components/transports/bayou), and create a headless server on Edgegap for a Unity project.

You can find the final sample project on our [GitHub](https://github.com/edgegap/netcode-sample-unity-fishnet), under the `Fishnet_v4.1.6R_WebGL` folder. This guide should work with any version of Fishnet, so long as you use the appropriate version of Bayou for it.

{% hint style="info" %}
Since FishNet version 4.1.6R comes with the Edgegap plugin included, we will use it to automatically build and containerize our game server, even if it is possible to do so manually using a Dockerfile.

For more information on the plugin, you can read our documentation [here](https://docs.edgegap.com/docs/sample-projects/unity-netcodes/broken-reference).

You will need to have Docker running for it to work properly.
{% endhint %}

### Unity requirements

This project is tested on Unity version `2021.3.16f1`. You will need the following modules to be installed with it:

* WebGL Build Support;
* Linux Dedicated Server Build Support;
* Linux Build Support (IL2CPP).

### Switch the transport

Download the Unity package for Bayou on [this GitHub](https://github.com/FirstGearGames/Bayou/releases). Import the package in the game project with the toolbar under `Asset/Import Package/Custom Package...`.

Open the `MainMenu` scene located under `Assets/SpaceEdge/Scenes`. In the `NetworkManager` gameObject, remove the `Tugboat` transport component. Replace it with the `Bayou` transport, located under `Asstes/FishNet/Plugins/Bayou`. Take note of the port value that's set, in this case `7770`.

Make sure to enable the `Start On Headless` option for the server build.

<figure><img src="https://3027732442-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2Fgit-blob-594181325c3fba9f457c57865daad12b3acc32d3%2Fnetwork-manager-setup.png?alt=media" alt=""><figcaption></figcaption></figure>

### Build the game server & Containerizing

Open the Edgegap plugin with the `Edgegap/Edgegap Hosting` toolbar menu. Verify your `Edgegap API Token` and either create or load an application for the game. Make sure the `port` value matches that of the Bayou transport. Select the `WS` protocol, then enter a `New Version Tag`.

Once this is properly set up, click on `Build and Push`, which will automatically containerize your game server and create a new application version on the Edgegap dashboard after a short waiting period.

### Testing the client

#### In the editor

Back in the project, select the `MatchmakingSystem` gameObject and change the following fields:

<figure><img src="https://3027732442-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2Fgit-blob-7e7c88646513c68ea7dd68ba7aba1a40aa1b09d1%2Ffishnet-matchmaking-system.png?alt=media" alt=""><figcaption></figcaption></figure>

* AppName: Set it to the “Application name” you used with the Edgegap plugin.
* AppVersion: Set it to the “Version name” you used with the Edgegap plugin.
* AuthHeaderValue: Set it to your Edgegap API token that you used with the Edgegap plugin.

{% hint style="info" %}
Remove the `token` word from the API token because we are setting this as the Authentication Header schema during the `Awake()` method of the `MatchmakingSystem`.
{% endhint %}

Open the `MatchmakingSystem` script, located under `Assets/SpaceEdge/Scripts/Systems`, where you may also update those same values. Search for `"UDP_PORT"` and replace it with `"Game Port"`.

{% hint style="info" %}
Previous versions of this sample would manually create the application via the Edgegap dashboard, and the name `UDP_PORT` would be used for the port used by the server.

The Edgegap plugin automatically names the port `Game Port` instead, which is why we must make sure to update the script. The game will not work otherwise.
{% endhint %}

<figure><img src="https://3027732442-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2Fgit-blob-2a6ddd5037990eccf3c62943a9f6cc610ff175e8%2Ffishnet-code.png?alt=media" alt=""><figcaption></figcaption></figure>

<figure><img src="https://3027732442-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2Fgit-blob-7a1523917e1509cab8490108ed7a98b44ae5423e%2Fport-name.png?alt=media" alt=""><figcaption></figcaption></figure>

Make sure that you uncheck the `Start On Headless` option in the `NetworkManager` gameObject as well.

Once this is done, click `Play` in the editor, then enter a name in the text box and click on `Start Game`. The game will check for any available server, or automatically have one get deployed if none exist, before connecting to it.

{% hint style="warning" %}
If there is a `ConnectionFailed` error on the client side, it may be because the `Start On Headless` option was not enabled in the `server build`, which means the deployment is not in a state to accept connections since the server never properly started. Make sure the option is enabled before trying again by creating a new container image and app version.

It may also be because app version's `port name` is not the same as in the `MatchmakingSystem` script. Make sure that both have the same name, in this case `"Game Port"`, before trying again.
{% endhint %}

#### On Itch.io

Once you've confirmed the game client works in the editor, it should also work in Itch.io. To upload your game there, you will need to make a client build in the `Build` screen of the Unity Editor, under `File -> Build Settings`. Select the following options:

* Set `Platform` to `WebGL`;
* Open up the `Player Settings`. Under `Player -> Publishing Settings`, set the `Compression Format` to `Gzip` and make sure the `Decompression Fallback` option is selected. Save these settings, and close the window.

<figure><img src="https://3027732442-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2Fgit-blob-d31291cf36a863193c24a856718a791db0c61577%2Fbuild-settings.png?alt=media" alt=""><figcaption></figcaption></figure>

Then press build and select a new empty folder named `build` as the file destination. Compress the files of this `build` folder into a zip folder, making sure that they are at the root of it. Then you simply need to upload the zip folder to your Itch project, and make sure to select the option for the file to play in the browser. The game should then work the same way as in the editor.


# NuxtJS

### Geting Started

Edgegap offers you a very intuitive platform to deploy a serverless web application wherever you need it. For this tutorial, we will go over the steps to deploy a Nuxt app. Before checking for anything else, make sure you have yarn or another packet management software like npm or npx. For this tutorial, we will stick to yarn. You must have it running in your application directory, which can be, at the beginning just an empty folder.

Open your terminal at the location of your folder, and run the following command:

```
C:\Users\JohnDoe\Documents\demo-nuxt-edgegap> yarn
```

Once it installs all the dependencies, make sure it installed properly by running this command:

```
C:\Users\JohnDoe\Documents\demo-nuxt-edgegap> yarn dev
```

Yarn dev should return the version of yarn installed if everything went smoothly. With this out of the way, we can now look at the remaining requirements to successfully complete this tutorial.

### Requirements

### Containerize your application

Containerizing most applications is straightforward. You must create a Dockerfile and then run that file on Docker to create the image. Visual Studio Code is a good platform to create your Dockerfile since, by default, it does not put an extension to every new file that we create. That is exactly what we need. Simply create a new file and name it Dockerfile. You will see the little docker logo appear next to it.

Now, you can copy and paste this script into it to get the main dependencies. Keep in mind that this will create an image a little over 1GB in size. For the purpose of this tutorial, this is fine. But for an application in production, you will have to optimize it:

```dockerfile
FROM node:lts as builder

WORKDIR /app

COPY . .

RUN yarn install \
  --prefer-offline \
  --frozen-lockfile \
  --non-interactive \
  --production=false

RUN yarn build

RUN rm -rf node_modules && \
  NODE_ENV=production yarn install \
  --prefer-offline \
  --pure-lockfile \
  --non-interactive \
  --production=true

FROM node:lts

WORKDIR /app

COPY --from=builder /app  .

ENV HOST 0.0.0.0
EXPOSE 80

CMD [ "yarn", "start" ]
```

After saving your Dockerfile, it is time to create the image. You can easily do so by running the following command:

{% hint style="warning" %}
For ARM CPU (Mac M1, M2, etc.) users, see the [dedicated page](https://docs.edgegap.com/docs/sample-projects/broken-reference).
{% endhint %}

```sh
docker build . -t regsitry.edgegap.com/<YOUR_REPO>/demo-nuxt-edgegap:<YOUR_VERSION_NUMBER>
```

It is preferable you put a version number following semantic versioning, but if you don’t plan on updating your build on Edgegap after your first deployment, you can omit the version number entirely.

But before that, you need to push your newly created docker image to the image repository of your choice. Remember that we offer private repositories through Harbor that offer you a series of security advantages you would not necessarily have by using the default Docker repository.

But before that, you need to push your newly created docker image to the image repository of your choice. Remember that we offer private repositories through Edgegap Registry that offer you a series of security advantages you would not necessarily have by using the default Docker repository.

To push your image to our repository, you will have to first log in with your credentials by using this command:

```sh
docker login regsitry.edgegap.com
```

Now, the only thing left is to push your image like this:

```sh
docker push regsitry.edgegap.com/<YOUR_REPO>/demo-nuxt-edgegap:<YOUR_VERSION_NUMBER>
```

Great! Now, you are only one step away from deploying your Nuxt app on Edgegap’s platform.

### Deploy your application on Edgegap

There are two ways of deploying an application on Edgegap. For both, you will need to have an account with us, which you can create for free by clicking the link right here. First, let’s go over on how to deploy our containerized application through our website.

#### Deploying an application through Edgegap’s dashboard:

You will have to head over to the following web address and enter your credentials. Once you do so, you will be automatically redirected to your dashboard. If you have just created your account, you will see an option to launch your first application right away. If not, simply head to the “Applications and games” tab on the menu on the left of your screen. You will see an option to create a new application on the right corner:

<figure><img src="https://3027732442-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2Fgit-blob-fc4b2486acb434863c2a6fd0e3772e02bfd2e214%2Fcreate-app-nuxt-js.png?alt=media" alt=""><figcaption></figcaption></figure>

Once you click on it, the following form should appear:

<figure><img src="https://3027732442-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2Fgit-blob-488e9bf3f56918ab3e01c15c9364a8fe321a40b5%2Fapp-form-nuxt-js.png?alt=media" alt=""><figcaption></figcaption></figure>

You should fill all the required fields and, once you’re done, there is a few things you will need to modify from the defaults:

* Port number: This application needs to have port 3000 open, so please add it in the “ports” section of the creation form.
* Maximum time to deploy: As mentioned previously in this tutorial, our NuxtJS image is around 1GB in size. To deploy an image that big on Edgegap, you will have to increase the Maximum time to deploy to around 300 seconds.

Once you’ve finished filling out the form with the adequate information, you simply must submit it, and you will be ready for deployment. Simply select the region and the number of players you wish to emulate.

<figure><img src="https://3027732442-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2Fgit-blob-3f94772bc292c12029b2fcf24a8e4f22df406d08%2Fnuxt-js-app-launch-1.png?alt=media" alt=""><figcaption></figcaption></figure>

Once you confirm your choices, your application will be online shortly. Here’s what you will see once it’s been deployed. You can access it yourself by clicking on the icon we’ve circled in this image.

<figure><img src="https://3027732442-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2Fgit-blob-7963d541fcb7a40b3733247854e0fe3e346475b9%2Fnuxt-js-app-launch-2.png?alt=media" alt=""><figcaption></figcaption></figure>

This will open a new tab where you will find the default landing page of your Nuxt application.

#### Deploying an application through Edgegap’s API

While our web dashboard is the most user-friendly way of deploying an application, you can also do so through a very simple API request. For this, you can use postman. It is important you visit the dashboard to [create an API token](https://docs.edgegap.com/docs/sample-projects/broken-reference) through the options on your profile. Here’s a simple guide on how to create your API token.

Once you have the API token in your hands, the only thing left to do is formulate a deployment request with your application name, its version, the IP addresses, the region you want to make your deployment in and, of course, your token as part of the authorization parameters. You can see what a full request looks like on our documentation here.

Once you send the request, you should see a response on your command line or on Postman should look like this:

<figure><img src="https://3027732442-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2Fgit-blob-4963dbbc9a5be5f79c9e449038b40eb250489bba%2Fnuxt-js-app-launch-api.png?alt=media" alt=""><figcaption></figcaption></figure>

That is all you must do to deploy an application through a CLI. To confirm your app was deployed, you can head over to the dashboard again and see your active deployment at work by clicking on the “Active deployments” tab.


# Ruby On Rails

### Installing Ruby

Edgegap offers you a very intuitive platform to deploy a serverless web application wherever you need it. For this tutorial, we will go over the steps to deploy a Ruby on Rails. Before checking for anything else, make sure you have Ruby installed.

If you’re running on a Linux/UNIX machine, you can use the pre-installed package manager on your machine and install Ruby through your terminal. You can refer to [Ruby’s official documentation](https://www.ruby-lang.org/en/documentation/installation/) to find the precise command that corresponds to your Linux/UNIX distribution.

On Windows machines, you will have to [download RubyInstaller](https://rubyinstaller.org) to get Ruby.

At the end of the installation, you can check Ruby is installed properly with the following command:

```
ruby -v
```

Now with Ruby installed, you will obviously have to install Rails. This is rather straightforward and can be done with this single command:

```
gem install rails
```

You can easily confirm that Rails was installed correctly in a similar way as what we used to verify Ruby’s installation.

```
rails -v
```

### Requirements

To follow this tutorial, you will need to have the following besides Ruby and Ruby on Rails:

* [Docker Desktop](https://www.docker.com/get-started/)
* [An account on Edgegap](https://app.edgegap.com/auth/login)
* Access to [Edgegap's private container repository](https://docs.edgegap.com/learn/advanced-features/edgegap-container-registry) or another registry like [Docker's container registry](https://hub.docker.com/)

### Getting Started with Ruby on Rails

To get started with ruby on rails, you will have to create a folder for your new project and run the following command on it:

```
rails new edgegap-ruby-rails-demo
```

Once the process finishes installing, you will have to modify your routes.rb file, which you will find in the config folder. Your routes file should contain the following:

```ruby
Rails.application.routes.draw do
  root 'hello_world#index'
end
```

You may notice there is no ‘hello\_world’ page in your project in the ‘views’ folder. You can easily generate it with its corresponding controller. First, make sure you’re in the folder Rails generated for you when you ran the `rails new` command.

If you’re using a Linux distribution, use the following command to create the HelloWorld controller:

```
rails generate controller HelloWorld index --skip-routes
```

The skip-routes option ensures this command won’t generate a new route to this controller, which is what we want since we already created one manually.

For windows, you will have to add some keywords to your command as follows:

```
ruby bin/rails generate controller HelloWorld index –skip-routes
```

Once the command executes successfully, you will see the HelloWorld page in the ‘views’ folder. You may have to correct the HTML syntax to get a proper section before you deploy it. The file should look like this:

<figure><img src="https://3027732442-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2Fgit-blob-203bfc13bd043df0ca5bbc9cd9e267e456e53a9e%2Fruby-index-page.png?alt=media" alt=""><figcaption></figcaption></figure>

The only step left to do to finish your project is deploying your Ruby on Rails app locally. Once again, the command to do so varies between Linux and Windows as follows:

Linux:

```sh
rails server
```

Windows:

```sh
ruby bin/rails server
```

### Containerize your application

Containerizing most applications is straightforward. You must create a Dockerfile and then run that file on Docker to create the image. Visual Studio Code is a good platform to create your Dockerfile since, by default, it does not put an extension to every new file that we create. That is exactly what we need. Simply create a new file and name it Dockerfile. You will see the little docker logo appear next to it. Now, you can copy and paste this script into it to get the main dependencies. The image this dockerfile will create is around 700 MB. Of course, you can optimize it, but a container this size will run very smoothly on Edgegap:

```dockerfile
FROM ruby:3-alpine
WORKDIR /app
COPY . .
RUN apk add --no-cache build-base tzdata nodejs yarn sqlite-dev postgresql-dev mysql-dev
RUN gem install bundler
RUN bundle install
ENV RAILS_ENV=production
RUN bundle exec rails assets:precompile
EXPOSE 3000
CMD ["rails", "server", "-b", "0.0.0.0"]
```

After saving your Dockerfile, it is time to create the image. You can easily do so by running the following command:

{% hint style="warning" %}
For ARM CPU (Mac M1, M2, etc.) users, add `--platform linux/amd64`  option to your build command.
{% endhint %}

```sh
docker build -t registry.edgegap.com/<YOUR_REPO>/ruby-rails-demo:<YOUR_VERSION_NUMBER> .
```

It is preferable you put a version number following semantic versioning, but if you don’t plan on updating your build on Edgegap after your first deployment, you can omit the version number entirely. But before that, you need to push your newly created docker image to the image repository of your choice. Remember that we offer private repositories through Edgegap Registry that offer you a series of security advantages you would not necessarily have by using the default Docker repository. To push your image to our repository, you will have to first log in with your credentials by using this command:

```sh
docker login registry.edgegap.com
```

Now, the only thing left is to push your image like this:

```sh
docker push registry.edgegap.com/<YOUR_REPO>/ruby-rails-demo:<YOUR_VERSION_NUMBER>
```

Great! Now, you are only one step away from deploying your Nuxt app on Edgegap’s platform.

### Deploy your application on Edgegap

There are two ways of deploying an application on Edgegap. For both, you will need to have an account with us, which you can create for free by clicking the link right here. First, let’s go over on how to deploy our containerized application through our website.

#### Deploying an application through Edgegap’s dashboard

You will have to head over to the [Edgegap Platform website](https://console.edgegap.com/) and enter your credentials. Once you do so, you will be automatically redirected to your dashboard. If you have just created your account, you will see an option to launch your first application right away. If not, simply head to the “Applications & Games” tab on the menu on the left of your screen. You will see an option to create a new application on the right corner:

<figure><img src="https://3027732442-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2Fgit-blob-fc4b2486acb434863c2a6fd0e3772e02bfd2e214%2Fcreate-app-nuxt-js.png?alt=media" alt=""><figcaption></figcaption></figure>

Once you click on it, the following form should appear:

<figure><img src="https://3027732442-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2Fgit-blob-488e9bf3f56918ab3e01c15c9364a8fe321a40b5%2Fapp-form-nuxt-js.png?alt=media" alt=""><figcaption></figcaption></figure>

You should fill all the required fields and, once you’re done, there is a few things you will need to modify from the defaults:

* Port number: This application needs to have port 3000 open, so please add it in the “ports” section of the creation form. Uncheck the option to verify the port.

Once you’ve finished filling out the form with the adequate information, you simply must submit it, and you will be ready for deployment. Simply select the region and the number of players you wish to emulate.

Once you’ve finished filling out the form with the adequate information, you simply must submit it, and you will be ready for deployment. Simply select the region and the number of players you wish to emulate.

<figure><img src="https://3027732442-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2Fgit-blob-810022e4ed498eed59c957e369b76261513c0daa%2Fruby-deployment-edgegap.png?alt=media" alt=""><figcaption></figcaption></figure>

Once you confirm your choices, your application will be online shortly. Here’s what you will see once it’s been deployed. You can access it yourself by clicking on the icon we’ve circled in this image.

<figure><img src="https://3027732442-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2Fgit-blob-b407d8a535e2c875804fc36d55999d68b2c82121%2Fruby-deployment-edgegap-2.png?alt=media" alt=""><figcaption></figcaption></figure>

This will open a new tab where you will find the default landing page of your Nuxt application.

#### Deploying an application through Edgegap’s API

While our web dashboard is the most user-friendly way of deploying an application, you can also do so through a very simple API request. For this, you can use postman. It is important you visit the dashboard to [create an API token](https://docs.edgegap.com/docs/sample-projects/broken-reference) through the options on your profile.

Once you have the API token in your hands, the only thing left to do is formulate a deployment request with your application name, its version, the IP addresses, the region you want to make your deployment in and, of course, your token as part of the authorization parameters. You can see what a full request looks like on our documentation here.

Once you send the request, you should see a response on your command line or on Postman should look like this:

<figure><img src="https://3027732442-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2Fgit-blob-902356a5acce346433cb04f870f205cc4f161e2d%2Fruby-deployment-api.png?alt=media" alt=""><figcaption></figcaption></figure>

That is all you must do to deploy an application through a CLI. To confirm your app was deployed, you can head over to the dashboard again and see your active deployment at work by clicking on the “Active deployments” tab.


# Tools & Integrations


# Container


# What is Docker

At Edgegap, we work with containers to distribute the load evenly across the globe. We need to have your game started within milliseconds, so the containers need to have speed in mind and build accordingly. We will walk you through creating a docker image, also known as a container.

{% hint style="info" %}
If you want to familiarize yourself with containers quickly, we strongly recommend [this quick video](https://www.youtube.com/watch?v=J0NuOlA2xDc\&ab_channel=Coderized).
{% endhint %}

<figure><img src="https://3027732442-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2Fgit-blob-e6111f686dccc8bebc29f2f10fe2ce093f9c2b9c%2Fdocker.png?alt=media" alt=""><figcaption></figcaption></figure>

### **What is Docker?**

* Docker is a PaaS (Platform as a Service) that allows OS-level virtualization.

### **What is the Docker Run command?**

* The docker run command allows a container to be created from an image so that the Docker desktop engine can run the Container.

### **Give it a try**

Let's start by adding the tools you will need on your computer to create your first Container.

You can follow the installation procedure as stated on Docker desktop.

if you are running [Windows 10 Pro](https://docs.docker.com/docker-for-windows/install/) If you are running [Windows 10 Home Edition](https://docs.docker.com/docker-for-windows/install-windows-home/) If you are running [macOS](https://docs.docker.com/docker-for-mac/install/)

Now that you have your local machine running Docker, we can start with a simple hello world.

```sh
docker run -d -p 80:80 --name speedtest edgegap/speedtest-edge
```

You can go to your command prompt and type the command above.

The steps will proceed automatically.

1. Download the Container from the Edgegap Repository (Only the first time)
2. Start the Container
3. The name will be speedtest (--name)
4. To expose your Container, you need to do it in the docker run command. In this example, we will expose port 80 on the outside, pointing to the exposed 80 in the Container (-p)
5. You can try it by going on your Web browser and hitting [http://localhost](http://localhost/)
6. Voila, you have run your first Container.

Now that you have your Container running, you can interact with it. We will restart the Container, stop it, and see its network in the next session. First, you will need to locally see what is running on your docker-engine at the command line type.

```sh
docker ps
```

You should see something similar too.

```
CONTAINER ID        IMAGE                    COMMAND                  CREATED             STATUS              PORTS                NAMES
dbf4d3734111        edgegap/speedtest-edge   "docker-php-entrypoi…"   29 minutes ago      Up 29 minutes       0.0.0.0:80->80/tcp   speedtest
```

You visually see the Container information running on your computer; you can have more than one running on this list.

`docker ps` is a simple command; you will learn to use it a lot.

Let's say that you need to have more information about your running container. You can ask the docker engine to give you all the details about your Container by running the following command:

```sh
docker container inspect speedtest
```

If you wish to see the internal network created by the docker engine, you can do so by running the following command.

```sh
docker network ls
```

You will get something similar to this:

```
NETWORK ID          NAME                DRIVER              SCOPE
67b24038b9ca        bridge              bridge              local
6f7fe43a489d        host                host                local
3d80cdb86a7e        none                null                local
```

If you wish to dig deeper into the network configuration, you can run the following command:

```sh
docker network inspect 67b24038b9ca
# where 678b24038b9ca is your network connected to your Container
```

Docker Stop

Now that you start your Container, you can stop it using:

```sh
docker container stop speedtest
```


# Your First Docker

Now that you have docker running on your computer let's create your first Dockerfile.

Before creating a container, you need to understand what a container is. A container runs natively on Linux (or in Docker desktop) and shares the host machine's kernel with other containers. It runs a discrete process, taking no more memory than any further executable, making it lightweight.

<figure><img src="https://3027732442-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2Fgit-blob-f150d345ddba740a7babd5338aca3f557cc1886c%2Fcontainer-architecture.png?alt=media" alt=""><figcaption></figcaption></figure>

Now that you've set up your environment, you can begin to develop containerized applications.

Since the documentation on how to create a container is already readily available online, we suggest you follow this excellent guide from Docker on Building and Running your image:

[Docker - Get Started Guide](https://docs.docker.com/get-started/02_our_app/)

{% hint style="info" %}
We recommend using the base image that you are comfortable ([CentOS](https://hub.docker.com/_/centos), [Ubuntu](https://hub.docker.com/_/ubuntu), [Debian](https://hub.docker.com/_/debian) or [Alpine](https://hub.docker.com/alpine)). We can run all Linux-based kernels without issues.
{% endhint %}


# SSH in Your Container

{% hint style="warning" %}
Edgegap does not recommend having SSH service accessible in your production deployments.
{% endhint %}

### Modifying your Dockerfile

We will build the docker container using a different Docker `Dockerfile` in this version.

We will need to install the OpenSSH service and enable it Create a User and a password to connect to your server.

In a container running on **Alpine**, merge the following:

```dockerfile
RUN apk --update add --no-cache openssh bash
RUN sed -i s/#PermitRootLogin.*/PermitRootLogin\ yes/ /etc/ssh/sshd_config
RUN echo "tester:$ecureP@ss" | chpasswd

EXPOSE 22
```

In a container running on **Ubuntu**, add the following:

```dockerfile
RUN apt-get update
RUN apt-get install openssh-server sudo -y

RUN useradd -rm -d /home/ubuntu -s /bin/bash -g root -G sudo -u 1000
RUN echo 'tester:$ecureP@ss' | chpasswd

EXPOSE 22
```

In your entrypoint, you will need to add the following command:

```sh
service ssh start
```

We suggest testing the deployment locally, using the docker run command to test the server start.

Once tested, you can push your new version on the container repository.

### On Edgegap

We suggest having a version called `-dev` or something that would make sense in your service. By doing so, you will have the option to do some tests and log into your container easily using the Edgegap infrastructure.

1. Create a new version of your app, adding the `Expose TCP Port 22`
2. Create a deployment using the new version you just created
3. Once you have the service running (Ready), look in your deployment information. You will see the external port mapping of port 22.
4. You can use Putty and connect using the FQDN of the deployment or Ip & the port mapping used
5. The username and password that you configured.


# External Registries


# Docker Hub

{% hint style="warning" %}
We strongly recommend upgrading to paid docker hub tier to prevent image download throttling.
{% endhint %}

### You need to have on hand

* [x] Your Docker Repository name
* [x] Your Docker Access token

### Access Token OR Deploy Token

{% hint style="success" %}
We recommend a Read-Only Token for production usage
{% endhint %}

You can follow this [**Tutorial**](https://docs.docker.com/docker-hub/access-tokens) to generate an Access Token

### Split the Repository Name

Given this Full Repository: **group/project**

Your **Repository** will always be: **docker.io**

and your **Image** will be: **group/project**

### Add the app on Edgegap

**API Example**

```json
{
    [...]
    "docker_repository": "docker.io",
    "docker_image": "group/project",
    "docker_tag": "v1",
    "private_username": "example@edgegap.com",
    "private_token": "<Access Token>",
    [...]
}
```

**From Dashboard**

From our Dashboard, The **Private registry token** will be the content of your **Access Token**

<figure><img src="https://3027732442-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2Fgit-blob-ea76944577acd25849fd5997abd2bde056d9b01e%2Fdocker-hub-example.png?alt=media" alt=""><figcaption></figcaption></figure>


# AWS ECR

*Make sure that you have the latest version of the AWS CLI and Docker installed.*

### You need to have on hand

* [x] The AWS Region of your ECR
* [x] The Registry URI

### To get this information, go to AWS Console

1. Go to your ECR Region
2. Go to Elastic Container Registry
3. Then to Repositories
4. Click on the Repository you wish to get your image from
5. Click on the **View push commands**.

### Split the URI

By default the AWS **URI** contains the Registry and the Image, you will need to split those

Imagine having this **URI**: **597351113950.dkr.ecr.ca-central-1.amazonaws.com/example**

Your **Repository** will be: **597351113950.dkr.ecr.ca-central-1.amazonaws.com**

and your **Image** will be: **example**

### Get the password

To get your ECR Login Password

```bash
aws ecr get-login-password --region ca-central-1
```

{% hint style="success" %}
You can change to your region (e.g. us-east-1, us-west-1, etc).
{% endhint %}

#### More info on [**AWS Doc**](https://docs.aws.amazon.com/cli/latest/reference/ecr/get-login-password.html)[**umentation**](https://docs.aws.amazon.com/cli/latest/reference/ecr/get-login-password.html)

### Add the app to Edgegap

#### API Example

{% hint style="info" %}
The username will always be AWS
{% endhint %}

```json
{
    [...]
    "docker_repository": "597351113950.dkr.ecr.ca-central-1.amazonaws.com",
    "docker_image": "example",
    "docker_tag": "v1",
    "private_username": "AWS",
    "private_token": "<ecr login-password>",
    [...]
}
```

#### From Dashboard

From our Dashboard, The **Private registry token** will be your **ecr login-password**

<figure><img src="https://3027732442-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2Fgit-blob-5818f97e273c73aa37bddcc3ce7c10e61356bb6c%2Fecr-example.png?alt=media" alt=""><figcaption></figcaption></figure>


# GCP GCR

### Use Edgegap with Google Container Registry

### You need to have on hand

* [x] The GCP Region of your GCR
* [x] Your GCP Project Name
* [x] Your JSON Key for the IAM User

### To get this information, go to GCP Console

1. Go to your Project
2. Go to Container Registry
3. Copy the Full Repository Name

### Split the Full Repository Name

Given this Full Repository: **gcr.io/project-name/example**

Your **Repository** will be: **gcr.io**

and your **Image** will be: **project-name/example**

### Generate your JSON Key File

Follow [**GCP Steps**](https://cloud.google.com/container-registry/docs/advanced-authentication#json-key) to generate this file.

{% hint style="warning" %}
Please Verify that your `Google Service Account` has the right permissions to manage your container registry
{% endhint %}

You will end with a file that contains something similar

```json
{
  "type": "service_account",
  "project_id": "project-name",
  "private_key_id": "12345abcdef12345",
  "private_key": "-----BEGIN PRIVATE KEY-----\n[...]\n-----END PRIVATE KEY-----\n",
  "client_email": "example@project-name.iam.gserviceaccount.com",
  "client_id": "1234567890",
  "auth_uri": "https://accounts.google.com/o/oauth2/auth",
  "token_uri": "https://oauth2.googleapis.com/token",
  "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
  "client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/example%40project-name.iam.gserviceaccount.com"
}
```

### Add the app on Edgegap

#### **API Example**

{% hint style="info" %}
The username will always be **\_json\_key**
{% endhint %}

```json
{
    [...]
    "docker_repository": "gcr.io",
    "docker_image": "project-name/repository-name",
    "docker_tag": "v1",
    "private_username": "_json_key",
    "private_token": "<The Content of JSON key file as JSON String>",
    [...]
}
```

The Private Token will look something like this

```json
{
    [...]
    "private_token": "{\"type\": \"service_account\", \"project_id\": \"project-name\", \"private_key_id\": \"12345abcdef12345\", \"private_key\": \"-----BEGIN PRIVATE KEY-----\\n[...]\\n-----END PRIVATE KEY-----\\n\", \"client_email\": \"example@project-name.iam.gserviceaccount.com\", \"client_id\": \"1234567890\", \"auth_uri\": \"https://accounts.google.com/o/oauth2/auth\", \"token_uri\": \"https://oauth2.googleapis.com/token\", \"auth_provider_x509_cert_url\": \"https://www.googleapis.com/oauth2/v1/certs\", \"client_x509_cert_url\": \"https://www.googleapis.com/robot/v1/metadata/x509/example%40project-name.iam.gserviceaccount.com\"}",
    [...]
}
```

#### **From Dashboard**

From our Dashboard, The **Private registry token** will be the content of your **JSON key file**

**You can copy the content directly without Stringify it**

<figure><img src="https://3027732442-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2Fgit-blob-7302363fb151d9cdc2e8f010c04158138c9379f0%2Fgcr-example.png?alt=media" alt=""><figcaption></figcaption></figure>


# Gitlab registry

### You need to have on hand

* [x] Your Gitlab Registry Full Repository name
* [x] Your Gitlab Personal access token OR a deploy token

### Access Token OR Deploy Token

You can follow this [**Tutorial**](https://docs.gitlab.com/ee/user/profile/personal_access_tokens.html) to generate a Personal Access Token

OR

You can follow this [**Tutorial**](https://docs.gitlab.com/ee/user/project/deploy_tokens/index.html) to generate a Deploy Token

### Split the Full Repository Name

Given this Full Repository: **registry.gitlab.com/group/project**

Your **Repository** will be: **registry.gitlab.com**

and your **Image** will be: **group/project**

### Add the app on Edgegap

#### **API Example**

```json
{
    [...]
    "docker_repository": "registry.gitlab.com",
    "docker_image": "group/project",
    "docker_tag": "v1",
    "private_username": "example@edgegap.com",
    "private_token": "<Personal Access Token OR Deploy Token>",
    [...]
}
```

#### **From Dashboard**

From our Dashboard, The **Private registry token** will be the content of your **Personal Access Token OR Deploy Token**

<figure><img src="https://3027732442-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2Fgit-blob-4a6825b8dde4e365db487e258513c52aa919fce0%2Fgitlab-registry-example.png?alt=media" alt=""><figcaption></figcaption></figure>


# Switch From Multiplay

**Take advantage of free integration support for Unity and Unreal projects** and migrate to our reliable hosting easily. If you're relying on Multiplay hosting services, the time to switch is now.

{% hint style="success" %}
[orchestration](https://docs.edgegap.com/learn/orchestration "mention") and DevOps are at the core of Edgegap platform. **Focus on your core business** instead of building scaffolding. **Minimize vendor lock-in** with cloud native approach and loose service coupling.
{% endhint %}

## 🚨 Multiplay End of Life

{% hint style="danger" %}
Unity is beginning a phased exit from the Multiplay Game Server Hosting service. Unity will operate the service through **March 31, 2026. You must choose and complete a transition path before this date.**
{% endhint %}

## 🚀 Getting Started

With Multiplay end of life closing in, evaluating replacements is an urgent need to keep your business running and prevent negative impact on your player base. Edgegap engineers and our amazing dev community are available for integration support and navigating this stressful situation.

Try one of our quick start guides supported with game engine plugins:

* [unreal-engine](https://docs.edgegap.com/unreal-engine "mention"),
* [unity](https://docs.edgegap.com/unity "mention").

{% hint style="success" %}
[Browse our Game Samples](https://docs.edgegap.com/docs/sample-projects) to get inspired and gain confidence to move forward with your project.
{% endhint %}

{% hint style="info" %}
If you need help, [please reach out to us over Discord](https://discord.gg/MmJf8fWjnt). For live games support see our [ticketing system](https://edgegap.atlassian.net/servicedesk/customer/portal/3).
{% endhint %}

## 💡 Case Studies

{% hint style="success" %}
[Discover how Ghosts of Tabor, the #1 extraction shooter on VR, migrated to Edgegap from Multiplay.](https://edgegap.com/gaming/case-studies)
{% endhint %}

## 🗺️ Replace Features

Review and identify Multiplay and Unity services and features which you need to replace:

<table><thead><tr><th width="196" valign="top">Multiplay Feature</th><th width="552">Edgegap Features</th></tr></thead><tbody><tr><td valign="top">Authentication</td><td><p>Optionally, add fine-grained access controls:</p><ul><li><a href="../../../learn/matchmaking/matchmaker-in-depth#authenticate">matchmaker API token,</a></li><li><a href="../../../learn/server-browser#authenticate">server browser client/server API tokens + federated identity,</a></li><li><a href="https://app.edgegap.com/user-settings?tab=tokens">custom DIY session management (Edgegap API token)</a>.</li></ul></td></tr><tr><td valign="top">Hosting SDK</td><td><strong>No SDK required!</strong> ServerConfig replaced by <a data-mention href="../../learn/orchestration/application-and-versions">application-and-versions</a>.</td></tr><tr><td valign="top">Create a Build</td><td>Try our quickstart tools - <a data-mention href="../../unity">unity</a> / <a data-mention href="../../unreal-engine">unreal-engine</a>.</td></tr><tr><td valign="top">Build Configuration</td><td>Fully Automated. Optionally <a href="../../../learn/orchestration/application-and-versions#port-mapping">expose additional ports</a> or <a href="../../../learn/orchestration/application-and-versions#injected-variables">variables</a>.</td></tr><tr><td valign="top">Server Query Protocol</td><td><ul><li>DevOps and Testing - <a href="../../api/dedicated-servers#get-v1-status-request_id">Deployment Status API</a>.</li><li>Backend Automation - <a href="../../../learn/orchestration/deployments#webhooks-and-postbacks">Deployment Webhook</a>.</li><li>Client Integration - <a href="../../../learn/server-browser#search-and-browse">Server Browser / Search and Browse</a>.</li></ul></td></tr><tr><td valign="top">Fleet</td><td><a data-mention href="../../learn/orchestration/private-fleets">private-fleets</a> with <a data-mention href="../../learn/orchestration/persistence">persistence</a> and <a href="../../../learn/orchestration/private-fleets#overflow-to-cloud">Cloud Overflow</a>. Optionally add later on, or default to <a data-mention href="../../../learn/orchestration/deployments#match-bound">#match-bound</a> cloud.</td></tr><tr><td valign="top">Test Allocation</td><td>With <a href="https://app.edgegap.com/deployment-management/deployments/list">dashboard web GUI</a>, <a href="../../../learn/orchestration/deployments#id-1.-start-a-deployment">Editor Plugins</a>, or <a href="../../api/dedicated-servers#post-deployments">Deploy API</a>.</td></tr><tr><td valign="top">Lobby</td><td><a href="../../../learn/matchmaking/matchmaker-in-depth#group-up">Group Up for Matchmaking</a> or <a href="../../../learn/server-browser#reserve-seats">Reserve Seat in Server Browser</a>.</td></tr><tr><td valign="top">Matchmaking</td><td><a href="../../learn/matchmaking">No-code matchmaker</a>, <a href="../../../learn/matchmaking/matchmaker-in-depth#hosting-cluster">test for free</a>, <a href="../../../learn/matchmaking#id-5.-game-integration">integrate with lightweight SDKs</a>.<br>Alternatively, <a data-mention href="#start-deployments-from-ugs-matchmaker">#start-deployments-from-ugs-matchmaker</a>.</td></tr><tr><td valign="top">AB testing</td><td>Configurable <a data-mention href="../../../learn/matchmaking/matchmaker-in-depth#matchmaking-profiles">#matchmaking-profiles</a> and <a data-mention href="../../../learn/matchmaking/matchmaker-in-depth#rolling-updates-and-ab-tests">#rolling-updates-and-ab-tests</a>.</td></tr><tr><td valign="top">Cloud Save</td><td><a data-mention href="../../learn/orchestration/persistence">persistence</a> with <a data-mention href="../../learn/advanced-features/managed-clusters">managed-clusters</a>.</td></tr><tr><td valign="top">Server Analytics</td><td><a href="../../../learn/orchestration/deployments#analytics">Deployment Analytics</a> and <a href="../../../learn/matchmaking/matchmaker-in-depth#analytics">Matchmaking Analytics</a>.</td></tr></tbody></table>

## :star: Start Deployments from UGS Matchmaker

If you prefer not to migrate to Edgegap's [matchmaking](https://docs.edgegap.com/learn/matchmaking "mention") and keep your UGS Matchmaker, see our [UGS hosting provider cloud script integration](https://github.com/Unity-Technologies/matchmaker-hosting-providers/blob/main/modules/EdgegapAllocator/CONFIGURATION.md).

### Deployment Placement

[Choosing the right location for your deployment can help reduce latency by up to 58% on average!](https://docs.edgegap.com/learn/orchestration/deployments#server-placement)

To take advantage of low-latency edge deployments you will need to:

1. [include our `EdgegapAllocator`  cloud script module in your UGS matchmaker](https://github.com/Unity-Technologies/matchmaker-hosting-providers/blob/main/modules/EdgegapAllocator/CONFIGURATION.md),
   1. add your `EDGEGAP_API_TOKEN` to UGS Secrets,
   2. paste your Edgegap App name and Version in the cloud script code,
2. include player's public IP address when creating matchmaker tickets:
   1. when creating ticket with `POST- https://matchmaker.services.api.unity.com/v2/tickets` ,
   2. include public IP in custom data:

```json
{
    "queueName": "basic",
    "attributes": {},
    "players": [
        {
            "id": "Player 1",
            "customData": {
                "player_ip": "8.8.8.8"
            }
        },
        {
            "id": "Player 2",
            "customData": {
                "player_ip": "4.4.4.4"
            }
        }
    ]
}
```

<figure><img src="https://3027732442-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2FuQuJVA8cmCdG3I44rlHU%2Fimage.png?alt=media&#x26;token=038a49e9-6a2b-47fe-8808-28b0ef39bea0" alt=""><figcaption><p>Storing Deployment Details for Player Connections</p></figcaption></figure>


# Switch from Hathora

**Take advantage of free integration support for Unity and Unreal projects** and migrate to our reliable hosting easily. If you're relying on Hathora hosting services, the time to switch is now.

{% hint style="success" %}
[orchestration](https://docs.edgegap.com/learn/orchestration "mention") and DevOps are at the core of Edgegap platform. **Focus on your core business** instead of building scaffolding. **Minimize vendor lock-in** with cloud native approach and loose service coupling.
{% endhint %}

## 🚨 Hathora End of Life

{% hint style="danger" %}
Hathora is officially shutting down their Game Hosting service on **May 5th, 2026.**\
**You must choose and complete a transition path before this date.**
{% endhint %}

## 🚀 Getting Started

With Hathora shutting down within weeks, evaluating replacements is an urgent need to keep your business running and prevent negative impact on your player base. Edgegap engineers and our amazing dev community are available for integration support and navigating this stressful situation.

Try one of our quick start guides supported with game engine plugins:

* [unreal-engine](https://docs.edgegap.com/unreal-engine "mention"),
* [unity](https://docs.edgegap.com/unity "mention").

{% hint style="success" %}
[Browse our Game Samples](https://docs.edgegap.com/docs/sample-projects) to get inspired and gain confidence to move forward with your project.
{% endhint %}

{% hint style="info" %}
If you need help, [please reach out to us over Discord](https://discord.gg/MmJf8fWjnt). For live games support see our [ticketing system](https://edgegap.atlassian.net/servicedesk/customer/portal/3).
{% endhint %}

## 🗺️ Replace Features

Review and identify Hathora services and features which you need to replace:

<table><thead><tr><th width="272">Hathora Feature</th><th>Edgegap Feature</th></tr></thead><tbody><tr><td>Authentication</td><td><p></p><p>Optionally, add fine-grained access controls:</p><ul><li><a href="../../../learn/matchmaking/matchmaker-in-depth#authenticate">matchmaker API token,</a></li><li><a href="../../../learn/server-browser#authenticate">server browser API tokens + federated identity,</a></li><li><a href="https://app.edgegap.com/user-settings?tab=tokens">custom DIY session management (Edgegap API token)</a>.</li></ul></td></tr><tr><td>Hosting CLI</td><td><strong>No CLI required!</strong> Use our <a href="https://app.edgegap.com/">Dashboard</a> or automate builds with <a href="../api">API</a>.</td></tr><tr><td>Create a Build</td><td>Try our quickstart tools - <a data-mention href="../../unity">unity</a> / <a data-mention href="../../unreal-engine">unreal-engine</a>.</td></tr><tr><td>Hathora Lobbies</td><td><ul><li>DevOps and Testing - <a href="../../api/dedicated-servers#get-v1-status-request_id">Deployment Status API</a>.</li><li>Backend Automation - <a href="../../../learn/orchestration/deployments#webhooks-and-postbacks">Deployment Webhook</a>.</li><li>Client Integration - <a href="../../../learn/server-browser#search-and-browse">Server Browser - Search and Browse</a>.</li></ul><p><a href="../../../learn/matchmaking/matchmaker-in-depth#group-up">Group Up for Matchmaking</a> or <a href="../../../learn/server-browser#reserve-seats">Reserve Seat in Server Browser</a>.</p></td></tr><tr><td>Fleets</td><td><a data-mention href="../../learn/orchestration/private-fleets">private-fleets</a> with <a data-mention href="../../learn/orchestration/persistence">persistence</a> and <a data-mention href="../../../learn/orchestration/private-fleets#overflow-to-cloud">#overflow-to-cloud</a>.<br>Optionally add later on, or default to <a data-mention href="../../../learn/orchestration/deployments#match-bound">#match-bound</a> cloud.</td></tr><tr><td><p>Eager Caching (Pro, Enterprise)</p><p>- 3s deployments</p></td><td><a data-mention href="../../../learn/orchestration/application-and-versions#active-caching">#active-caching</a> (Pay as You Go)<br>- 0.5s deployments worldwide in 615+ locations</td></tr><tr><td>Ping Service (Regions)</td><td><a data-mention href="../../learn/orchestration/ping-beacons">ping-beacons</a> (automated in engine-specific SDKs)</td></tr><tr><td>Telemetry (Analytics)</td><td><a href="../../../learn/orchestration/deployments#analytics">Deployment Analytics</a> and <a href="../../../learn/matchmaking/matchmaker-in-depth#analytics">Matchmaking Analytics</a>.</td></tr></tbody></table>

## ⭐ Backend Integrations

Ensure your current game backend will be fully supported after migration. Edgegap offers integration support for all game backends currently supported by Hathora platform:

* [Epic Online Services](https://docs.edgegap.com/docs/tools-and-integrations/unreal-eos-lobby-integration), [featured post from Feb 2024](https://onlineservices.epicgames.com/en-US/learning/launch-and-scale-your-multiplayer-game-with-epic-online-services-and-edgegap).
* [playfab-bridge](https://docs.edgegap.com/docs/tools-and-integrations/playfab-bridge "mention").
* [Unity Gaming Services](https://docs.edgegap.com/docs/tools-and-integrations/switch-from-multiplay).
* [Nakama by Heroic Labs.](https://docs.edgegap.com/docs/tools-and-integrations/deploy-from-nakama)
* [Pragma - joint case study.](https://pragma.gg/case-studies/soliton-backend)
* [Beamable.](https://edgegap.com/resources/partners/beamable)
* Bring your own custom backend.

Edgegap additionally supports integrations with platforms (incl. but not limited to) [BrainCloud](https://edgegap.com/resources/partners/braincloud), [Loot Locker](https://edgegap.com/resources/partners/loot-locker), [Invokation Games](https://edgegap.com/resources/partners/invokation-games), [XSOLLA backend](https://edgegap.com/resources/partners/xsolla), [Network Next](https://edgegap.com/resources/partners/network-next) and more.


# Switch From Gamelift

If you are looking to switch from using AWS Gamelift to Edgegap, the following simple steps will get you running in no time. Before getting started, we expect that:

* You currently use AWS Gamelift
* You currently have a working game server build on Gamelift
* You already [created](https://docs.edgegap.com/learn/orchestration/application-and-versions) and [deployed](https://docs.edgegap.com/learn) an application on Edgegap

{% hint style="info" %}
You will benefit from way more locations with the Edgegap solution.
{% endhint %}

### Remove AWS Gamelift SDK

The first step to switch to Edgegap is to remove the code that initilaizes AWS Gamelift within your game server. This is to reduce overhead and prevent errors. The code you are looking to remove probably looks like the following:

#### Unity (C#)

```cs
using UnityEngine;
using Aws.GameLift.Server;
using System.Collections.Generic;

public class GameLiftServerExampleBehavior : MonoBehaviour
{
    //This is an example of a simple integration with GameLift server SDK that will make game server processes go active on GameLift!
    public void Start()
    {
        //Identify port number (hard coded here for simplicity) the game server is listening on for player connections
        var listeningPort = 7777;

        //InitSDK will establish a local connection with GameLift's agent to enable further communication.
        var initSDKOutcome = GameLiftServerAPI.InitSDK();
        if (initSDKOutcome.Success)
        {
            ProcessParameters processParameters = new ProcessParameters(
                (gameSession) => {
                    //When a game session is created, GameLift sends an activation request to the game server and passes along the game session object containing game properties and other settings.
                    //Here is where a game server should take action based on the game session object.
                    //Once the game server is ready to receive incoming player connections, it should invoke GameLiftServerAPI.ActivateGameSession()
                    GameLiftServerAPI.ActivateGameSession();
                },
                (updateGameSession) => {
                    //When a game session is updated (e.g. by FlexMatch backfill), GameLiftsends a request to the game
                    //server containing the updated game session object.  The game server can then examine the provided
                    //matchmakerData and handle new incoming players appropriately.
                    //updateReason is the reason this update is being supplied.
                },
                () => {
                    //OnProcessTerminate callback. GameLift will invoke this callback before shutting down an instance hosting this game server.
                    //It gives this game server a chance to save its state, communicate with services, etc., before being shut down.
                    //In this case, we simply tell GameLift we are indeed going to shutdown.
                    GameLiftServerAPI.ProcessEnding();
                },
                () => {
                    //This is the HealthCheck callback.
                    //GameLift will invoke this callback every 60 seconds or so.
                    //Here, a game server might want to check the health of dependencies and such.
                    //Simply return true if healthy, false otherwise.
                    //The game server has 60 seconds to respond with its health status. GameLift will default to 'false' if the game server doesn't respond in time.
                    //In this case, we're always healthy!
                    return true;
                },
                listeningPort, //This game server tells GameLift that it will listen on port 7777 for incoming player connections.
                new LogParameters(new List<string>()
                {
                    //Here, the game server tells GameLift what set of files to upload when the game session ends.
                    //GameLift will upload everything specified here for the developers to fetch later.
                    "/local/game/logs/myserver.log"
                }));

            //Calling ProcessReady tells GameLift this game server is ready to receive incoming game sessions!
            var processReadyOutcome = GameLiftServerAPI.ProcessReady(processParameters);
            if (processReadyOutcome.Success)
            {
                print("ProcessReady success.");
            }
            else
            {
                print("ProcessReady failure : " + processReadyOutcome.Error.ToString());
            }
        }
        else
        {
            print("InitSDK failure : " + initSDKOutcome.Error.ToString());
        }
    }

    void OnApplicationQuit()
    {
        //Make sure to call GameLiftServerAPI.Destroy() when the application quits. This resets the local connection with GameLift's agent.
        GameLiftServerAPI.Destroy();
    }
}
```

#### Unreal Engine (C++)

```cpp
using UnrealBuildTool;

public class MyAwesomeGame : ModuleRules
{
	public MyAwesomeGame(TargetInfo Target)
	{
		PublicDependencyModuleNames.AddRange(
            // Remove GameLiftServerSDK
            new string[] { "Core", "CoreUObject", "Engine", "InputCore", "GameLiftServerSDK" }
        );
        bEnableExceptions = true;
	}
}
```

```cpp
#include "GameLiftFPS.h"
#include "Engine.h"
#include "EngineGlobals.h"
#include "GameLiftFPSGameMode.h"
#include "GameLiftFPSHUD.h"
#include "GameLiftFPSCharacter.h"
#include "GameLiftServerSDK.h"

AGameLiftFPSGameMode::AGameLiftFPSGameMode()
	: Super()
{

//Let's run this code only if GAMELIFT is enabled. Only with Server targets!
#if WITH_GAMELIFT

	//Getting the module first.
	FGameLiftServerSDKModule* gameLiftSdkModule = &FModuleManager::LoadModuleChecked<FGameLiftServerSDKModule>(FName("GameLiftServerSDK"));

	//InitSDK will establish a local connection with GameLift's agent to enable further communication.
	gameLiftSdkModule->InitSDK();

	//When a game session is created, GameLift sends an activation request to the game server and passes along the game session object containing game properties and other settings.
	//Here is where a game server should take action based on the game session object.
	//Once the game server is ready to receive incoming player connections, it should invoke GameLiftServerAPI.ActivateGameSession()
	auto onGameSession = [=](Aws::GameLift::Server::Model::GameSession gameSession)
	{
		gameLiftSdkModule->ActivateGameSession();
	};

	FProcessParameters* params = new FProcessParameters();
	params->OnStartGameSession.BindLambda(onGameSession);

	//OnProcessTerminate callback. GameLift will invoke this callback before shutting down an instance hosting this game server.
	//It gives this game server a chance to save its state, communicate with services, etc., before being shut down.
	//In this case, we simply tell GameLift we are indeed going to shutdown.
	params->OnTerminate.BindLambda([=](){gameLiftSdkModule->ProcessEnding();});

	//This is the HealthCheck callback.
	//GameLift will invoke this callback every 60 seconds or so.
	//Here, a game server might want to check the health of dependencies and such.
	//Simply return true if healthy, false otherwise.
	//The game server has 60 seconds to respond with its health status. GameLift will default to 'false' if the game server doesn't respond in time.
	//In this case, we're always healthy!
	params->OnHealthCheck.BindLambda([](){return true; });

	//This game server tells GameLift that it will listen on port 7777 for incoming player connections.
	params->port = 7777;

	//Here, the game server tells GameLift what set of files to upload when the game session ends.
	//GameLift will upload everything specified here for the developers to fetch later.
	TArray<FString> logfiles;
	logfiles.Add(TEXT("aLogFile.txt"));
	params->logParameters = logfiles;

	//Calling ProcessReady tells GameLift this game server is ready to receive incoming game sessions!
	gameLiftSdkModule->ProcessReady(*params);
#endif
}
```

### Containerize your game server

Try one of our quick start guides supported with game engine plugins:

* [unreal-engine](https://docs.edgegap.com/unreal-engine "mention"),
* [unity](https://docs.edgegap.com/unity "mention").

### Push your container on a repository

You will have to push your container on a repository. You can use Edgegap's [private repository](https://docs.edgegap.com/learn/advanced-features/edgegap-container-registry) or any other option.

### Create an Application on Edgegap

Now that your container is on a repository, you will have to [create an Application](https://docs.edgegap.com/learn/orchestration/application-and-versions) on Edgegap. This Application will represent your game sever. With this application, you will be able to deploy your server.

You can now [deploy](https://docs.edgegap.com/learn/orchestration/deployments) your server on demand for your players!


# Deploy from Nakama

Players of multiplayer games expect the same high quality online experience from Indies to AAAs, whether they play in New York or Jakarta.

For game developers, this standard requires **scalable backend services that work in sync with their game server hosting** to ensure a seamless end-user experience that instantly helps users get online and play on game servers with real-time performance.

Deploy Dedicated Game Servers for popular game engines or custom engines, fully integrated with Nakama's open-source player data and game services for a convenient turnkey solution.

{% hint style="success" %}
This is a Verified Solution co-maintained with an independent partner - [Heroic Labs](https://heroiclabs.com).
{% endhint %}

## 🚀 Getting Started

The integration between Nakama (by Heroic Labs) and Edgegap is designed to streamline the process of deploying scalable, low-latency game servers. Here’s an overview of how it works:

1. **Matchmaking and Player Management with Nakama**: [Nakama handles user accounts, matchmaking, and player data management](https://heroiclabs.com/docs/nakama/getting-started/index.html), using a robust architecture to support real-time interactions between players. Once Nakama identifies that a match should start, it triggers a game instance on Edgegap.
2. **Dynamic Server Deployment with Edgegap**: Edgegap receives the request from Nakama and [deploys a server instance in the optimal location](https://docs.edgegap.com/learn/orchestration/deployments) based on real-time data, such as the players’ locations and device information. This ensures that game servers are close to players, minimizing latency and creating a smooth in-game experience.
3. **Real-Time Communication**: The integration allows for seamless communication between Nakama’s game backend and Edgegap’s deployment network. Nakama provides the matchmaking, lobby system and general meta game play features, whilst Edgegap ensures that the core game loop (running with a Headless game engine such as Unity) runs as efficiently as possible, no matter where the players are. The connectivity between Edgegap and Nakama mean that players can matchmake better with each other and with existing or new matches running on Edgegap.
4. **Scalability and Load Management**: Edgegap’s system dynamically scales resources up or down depending on player demand, while Nakama scales to accommodate millions of users, even during peak times. This combination allows developers to maintain consistent performance during traffic spikes without over-committing resources.

<figure><img src="https://3027732442-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2FeeqFSOPBIvtytnPI2neT%2Fimage.png?alt=media&#x26;token=96127320-d7bd-4a66-a5df-cea0cf886d25" alt=""><figcaption></figcaption></figure>

## ⚡ Integration

☑️ **Install and Configure Nakama**: [Start by setting up Nakama as your game’s backend](https://heroiclabs.com/docs/nakama/getting-started/install/). Configure it to handle user accounts, matchmaking, multiplayer sessions, and other game logic:

* for [Heroic Cloud](https://heroiclabs.com/heroic-cloud/), [create a new Builder](https://heroiclabs.com/docs/heroic-cloud/concepts/builders/) using the [nakama-edgegap plugin repository](https://github.com/edgegap/nakama-edgegap),
* for [self-hosted Nakama](https://docs.edgegap.com/learn/advanced-features/managed-clusters#nakama-by-heroic-labs), [follow plugin Usage instructions to build your image locally](https://github.com/edgegap/nakama-edgegap?tab=readme-ov-file#usage)

☑️ **Sign up for Edgegap**: [Sign up to Edgegap web platform](https://app.edgegap.com/auth/register) to upload your dedicated server image and retrieve API keys and secrets needed for the next step. Edgegap’s hosting is free during development with its free trial, and its no-commitment, highly competitive pay-per-minute pricing ensures studios only pay when players are active, with no upfront costs or fixed monthly fees:

* [Getting Started with Servers (Unity)](https://docs.edgegap.com/unity),
* [Getting Started with Servers (Unreal Engine)](https://docs.edgegap.com/unreal-engine).

☑️ **Connect Nakama to Edgegap**: Use Nakama’s FleetManager implementation to connect with Edgegap’s deployment service. Follow the [in-depth guide to configure both services](https://github.com/edgegap/nakama-edgegap?tab=readme-ov-file#nakama-setup).

🙌 Congratulations on integrating Nakama with Edgegap deployments!

{% hint style="success" %}
**Automate Game Server integration** using [Edgegap Server Nakama Plugin for Unity](https://github.com/edgegap/edgegap-server-nakama-plugin-unity).
{% endhint %}

## 🚨 Troubleshooting

{% hint style="info" %}
If you need help, [please reach out to us over Discord](https://discord.gg/MmJf8fWjnt). For live games support see our [ticketing system](https://edgegap.atlassian.net/servicedesk/customer/portal/3).
{% endhint %}


# EOS Lobby Integration

This guide will show you how to integrate Edgegap to work with EOS lobbies in your Unreal game project. Some steps will require you to send requests to our API using a token, and the `curl` commands provided below will allow you to preview each of their response so that you may determine how to manage them in your code. When using the token in your requests, make sure to keep the `token` keyword.

You will also need to have an application version already set up on our platform for our project. In this case, we recommend using the Edgegap Unreal plugin to help speed up the testing process. For more information on the plugin, you can read our documentation [here](https://docs.edgegap.com/docs/tools-and-integrations/broken-reference).

{% hint style="warning" %}
As a safety measure, it is not recommended to have the EOS Lobby Owner send requests directly to the Edgegap API in a production environment, due to the client getting access to the API token. You should instead use a separate service to manage these requests.
{% endhint %}

### 1. Get and Store the players' public IP

To begin with, each player that joins a lobby - including the Lobby Owner - needs to get their public IP and store it as a [Lobby Member property](https://dev.epicgames.com/docs/game-services/lobbies#lobby-and-lobby-member-properties).

```
curl --location --request GET 'https://api.edgegap.com/v1/ip' \
--header 'Authorization: [EDGEGAP_API_TOKEN]'
```

### 2. Create a deployment

Once the Lobby Owner decides that the match is ready to begin, a request needs to be sent to create a new deployment on Edgegap, using the stored public IPs.

```
curl --location --request POST 'https://api.edgegap.com/v1/deploy' \
--header 'Content-Type: application/json' \
--header 'Authorization: [EDGEGAP_API_TOKEN]' \
--data-raw '{
    "app_name": "[EDGEGAP_APP_NAME]",
    "version_name": "[EDGEGAP_APP_VERSION]",
    "ip_list": [
        "[LOBBY_MEMBER_IP]"
    ]
}'
```

Afterwards, the Lobby Owner will need to keep polling the deployment, using the request\_id provided in the response of the deployment creation request. Once the reply has the deployment's `current_status` set to `READY`, the Lobby Owner will need to set the deployment's IP and port values as [EOS Lobby Properties](https://dev.epicgames.com/docs/game-services/lobbies#lobby-and-lobby-member-properties).

```
curl --location --request GET 'https://api.edgegap.com/v1/status/[REQUEST_ID]' \
--header 'Authorization: [EDGEGAP_API_TOKEN]'
```

### 3. Connect to the deployment

When the players receive the notification that the IP and port values have been assigned, they can compare them against the client cache and then use them to connect to the server to play the match.

### 4. End the match and deployment

Once the match is finished, the Lobby Owner will unset the IP and port values from the EOS Lobby Properties, which will notify everyone else to disconnect gracefully from the server. If the application has the configuration to inject environment variables, they can be used to terminate the deployment from within at this time.

To terminate the deployment from outside the server, a request like the `curl` command shown below can be used instead.

```
curl --location --request DELETE 'https://api.edgegap.com/v1/stop/[REQUEST_ID]' \
--header 'Authorization: [EDGEGAP_API_TOKEN]'
```

If the players remain in the lobby, the Lobby Owner can then repeat the steps starting at requesting a new deployment in order to initiate a rematch with the same people.


# Playfab Bridge

This guide will show you how to set up a game with PlayFab so as to automatically deploy a server on Edgegap after players have been matched through the PlayFab matchmaker. The clients will access the information to connect to the server via the PlayFab Player Data, which will be updated by the server once it's ready. Before getting started, we expect that:

* You currently use Playfab;
* You have already [created](https://docs.edgegap.com/learn/orchestration/application-and-versions) and [deployed](https://docs.edgegap.com/learn) an application with Edgegap before.

You can find the final sample project on our [GitHub](https://github.com/edgegap/sample-playfab-matchmaker-fishnet). This sample was tested using Unity v2021.3.10 and Fishnet v3.11.14 as its netcode.

### Setting Up PlayFab Cloud Script

#### Create New Function

Log on to your PlayFab account, then navigate to your game's overview page on the dashboard. In the `Automation` tab, create a new Cloud Script function that will send a request to the Edgegap API to deploy a new server.

You will need to pass a list of the players' latitude/longitude locations in the request, so the the server can be deployed in the best possible location for everyone.

You also need to pass some custom environment variables as key-value pairs, namely:

* the `Match ID` generated by PlayFab's matchmaker;
* a PlayFab `Title Secret Key`, which can be found in your title settings;
* a `list` of each player's `Master Player Account Id`.

These variables will be used to update the players' PlayFab `Player Data` with the information needed to connect to the server. Keep track of the keys you use to set these variables; in this sample, they are `"PLAYFAB_MATCH_ID"`, `"PLAYFAB_TITLE_SECRET"`, and `"PLAYFAB_MATCH_PLAYERS_ID_LIST"`.

{% hint style="info" %}
The simplest way to create this function is to deploy a new revision in the `Revisions (Legacy)` tab, adding the following code to it. Make sure to update the `Edgegap_AppName`, `Edgegap_AppVersion`, `Edgegap_ApiToken` and `PlayFab_TitleSecret` variables at the top with your own values first.

The app name and version will be used later on when containerizing the game server on Edgegap.

The list of player IDs is stored here as a single string, with each ID separated by a comma.
{% endhint %}

```javascript
var Edgegap_AppName = "APP_NAME";
var Edgegap_AppVersion = "APP_VERSION";
var Edgegap_ApiToken = "token XXXX"; //include the "token" keyword
var PlayFab_TitleSecret = "TITLE_SECRET";

handlers.StartEdgegapDeployment = function (args, context) {
  var QueueName = context.playStreamEvent.Payload.QueueName;
  var MatchId = context.playStreamEvent.Payload.MatchId;

  var GeoIpList = [];
  var PlayerIds = "";

  var MatchMember = multiplayer.GetMatch({
    QueueName: QueueName,
    MatchId: MatchId,
    EscapeObject: false,
    ReturnMemberAttributes: false,
  }).Members;

  MatchMember.forEach((Member) => {
    var Profile = entity.GetProfile({
      Entity: Member.Entity,
    });

    var Location = server.GetPlayerProfile({
      PlayFabId: Profile.Profile.Lineage.MasterPlayerAccountId,
      ProfileConstraints: {
        ShowLocations: true,
      },
    });

    GeoIpList.push({
      ip: "1.2.3.4",
      latitude: Location.PlayerProfile.Locations[0].Latitude,
      longitude: Location.PlayerProfile.Locations[0].Longitude,
    });

    PlayerIds += Profile.Profile.Lineage.MasterPlayerAccountId + ",";
  });

  PlayerIds = PlayerIds.slice(0, -1);

  var response = JSON.parse(
    http.request(
      "https://api.edgegap.com/v1/deploy",
      "post",
      JSON.stringify({
        app_name: Edgegap_AppName,
        version_name: Edgegap_AppVersion,
        geo_ip_list: [...GeoIpList],
        tags: [MatchId.slice(0, 20)],
        env_vars: [
          {
            key: "PLAYFAB_MATCH_ID",
            value: MatchId,
          },
          {
            key: "PLAYFAB_TITLE_SECRET",
            value: TitleSecret,
          },
          {
            key: "PLAYFAB_MATCH_PLAYERS_ID_LIST",
            value: PlayerIds,
          },
        ],
      }),
      "application/json",
      { authorization: Edgegap_ApiToken }
    )
  );

  log.info("response", response);
};
```

{% hint style="info" %}
This Cloud Script function creates an interface between the game client and the Edgegap API, which keeps your `Edgegap API token` and `PlayFab Title Secret` hidden from the players.
{% endhint %}

### Automation Rule

Still under `Automation`, navigate to the `Rules` tab. Create a new rule with the following settings:

* Set the `Event Type` to `playfab.matchmaking.match_found`;
* Add a new `Action`:
  * Set the `Type` to `Execute Entity Cloud Script`;
  * Set the `Cloud Script Function` to `StartEdgegapDeployment`.

<figure><img src="https://3027732442-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2Fgit-blob-558d1a8ab45a1545c4c7d64d1963a0f1e682645c%2Fautomation-rule.png?alt=media" alt=""><figcaption></figcaption></figure>

### Matchmaker Queue & Players

In the `Multiplayer` tab, under `Matchmaking`, make sure to have a queue available, otherwise create a new one. For quick testing, set it up to simply match any two players together.

You will need enough players registered to your Playfab title to satisfy the matchmaker's rules, so in this case only two will do. You can create new ones under the `Players` tab if needed. For this sample project, make sure to keep track of those players' `Custom ID` and `Title Player Account ID` for testing later.

### Editing The Game

#### Server

After opening the game sample in the Unity editor, we added a new empty gameObject to the `BattleScene` found under `Assets/SpaceEdge/Scenes`. We then attached a new C# script called `PlayerDataUpdateService` to it. It contains a callback function to be executed once the server is ready.

We also created a second script called `PlayfabRestApiService`, which contains the various requests that need to be sent to PlayFab's different APIs.

In `PlayerDataUpdateService.cs`, we retrieve a few of the environment variables injected in the deployment:

* Custom variables:
  * `PLAYFAB_MATCH_ID`;
  * `PLAYFAB_TITLE_SECRET`;
  * `PLAYFAB_MATCH_PLAYERS_ID_LIST`
* Default Edgegap variables:
  * `ARBITRIUM_PUBLIC_IP`;
  * `ARBITRIUM_PORTS_MAPPING`;

In `ARBITRIUM_PORTS_MAPPING`, we need to retrieve the specific external `port` value that will allow the client to connect to the server; in this sample, it is the one named `"Game Port"`.

Using the `PLAYFAB_TITLE_SECRET` as authentification, we send a request to the PlayFab Server API to update the `Player Data` of each corresponding ID in `PLAYFAB_MATCH_PLAYERS_ID_LIST` with the following key-value pair:

* Key: `PLAYFAB_MATCH_ID`;
* Value: `"{ARBITRIUM_PUBLIC_IP}:{port}"`;

#### PlayerDataUpdateService

```cs
public class PlayerDataUpdateService : NetworkBehaviour
{
    private PlayfabRestApiService _playfabService;

    [SerializeField] private string KeyMatchId = "PLAYFAB_MATCH_ID";
    [SerializeField] private string KeyTitleSecret = "PLAYFAB_TITLE_SECRET";
    [SerializeField] private string KeyPlayerIds = "PLAYFAB_MATCH_PLAYERS_ID_LIST";
    [SerializeField] private string ServerPortName = "Game Port";

    private string matchID;
    private string titleSecretKey;
    private string[] playerIdList;

    public override void OnStartServer()
    {
        _playfabService = FindObjectOfType<PlayfabRestApiService>();

        matchID = Environment.GetEnvironmentVariable(KeyMatchId);
        titleSecretKey = Environment.GetEnvironmentVariable(KeyTitleSecret);
        playerIdList = Environment.GetEnvironmentVariable(KeyPlayerIds)?.Split(',');

        string address = Environment.GetEnvironmentVariable("ARBITRIUM_PUBLIC_IP");
        string portsMapping = Environment.GetEnvironmentVariable("ARBITRIUM_PORTS_MAPPING");

        if (!string.IsNullOrEmpty(portsMapping))
        {
            int port = JSON.ParseString(portsMapping).GetJSON("ports").GetJSON(ServerPortName).GetInt("external");

            foreach (string playerId in playerIdList)
            {
                if (!string.IsNullOrEmpty(playerId))
                {
                    _playfabService.UpdatePlayerData(titleSecretKey, playerId, matchID, $"{address}:{port}");
                }
            }
        }
        else
        {
            Debug.Log("Port Mapping Unavailable");
        }
    }

    ...
}
```

#### PlayfabRestApiService

```cs
public class PlayfabRestApiService : MonoBehaviour
{
    ...

    [SerializeField] private string TitleID = "TITLE_ID";

    private const string TypeHeaderValue = "application/json";
    private readonly HttpClient _playfabHttpClient = new();
    private HttpResponseMessage _request;
    private StringContent _requestData;
    private string _response;

    ...

    public async void UpdatePlayerData(string secretKey, string playerID, string key, string value)
    {
        if (!_playfabHttpClient.DefaultRequestHeaders.Contains("X-SecretKey"))
        {
            _playfabHttpClient.DefaultRequestHeaders.Add("X-SecretKey", secretKey);
        }

        var dataProperty = new JSON();
        dataProperty.Add(key, value);

        var requestJson = new JSON();
        requestJson.Add("PlayFabId", playerID);
        requestJson.Add("Data", dataProperty);

        _requestData = new StringContent(requestJson.CreateString(), Encoding.UTF8, TypeHeaderValue);
        _request = await _playfabHttpClient.PostAsync($"https://{TitleID}.playfabapi.com/Server/UpdateUserData", _requestData);
        _response = await _request.Content.ReadAsStringAsync();

        if (!_request.IsSuccessStatusCode)
        {
            Debug.Log($"Could Not Update PlayerData of ID {playerID}, Error {(int)_request.StatusCode} With Message: \n{_response}");
        }
    }
}
```

#### Client

The client-side setup will be managed in the `MainMenu` scene found under `Assets/SpaceEdge/Scenes`. We created a new script called `MainMenuService` to manage the UI of the scene and display various messages to the player, and added new functions to `PlayfabRestApiService.cs`. We attached the `PlayfabRestApiService` script to a new gameObject in this scene as well.

The first thing the player needs to do is login with PlayFab, which will allow them to send additional requests to PlayFab's Client and Multiplayer APIs.

{% hint style="info" %}
We use the `LoginWithCustomID` endpoint for simplicity, however there are more suitable ways to implement the login depending on the situation (e.g.: with mobile games).
{% endhint %}

One the player has logged in and both the `X-Authorization` and `X-EntityToken` headers have been properly set up for later requests, they can create a new matchmaking ticket using the `Start Game` UI button. This will send a request to PlayFab's multiplayer API and store the `ticket ID` for later use.

Afterwards, the game client will periodically check the ticket's status every few seconds until a match has been found or the ticket gets cancelled. Once a match is found, the `match ID` gets stored as a variable.

The client will then periodically send requests to PlayFab's Client API in order to get the player's Title `Player Data`, using the `match ID` as the key for the specific data that needs to be retrieved. Once the data is found, it sets the server's `address` and external `port` value in the netcode's `transport` component, then connects to the server.

Once the client gets connected and started properly, a request gets sent to remove the connection information from that player's PlayFab `Player Data` thanks to a callback function.

{% hint style="info" %}
It is important to make sure these key-value pairs get deleted, preferably before the deployment gets terminated. This is to avoid cluttering the `Player Data` with too many unnecessary entries.
{% endhint %}

#### MainMenuService

```cs
public class MainMenuService : MonoBehaviour
{
    [SerializeField] private Button startGameButton;
    [SerializeField] private TMP_InputField playerNameInput;
    [SerializeField] private TMP_Text serverStatus;

    private PlayfabRestApiService _playfabService;

    private void Start()
    {
        if (!InstanceFinder.ServerManager.GetStartOnHeadless())
        {
            _playfabService = FindObjectOfType<PlayfabRestApiService>();
            _playfabService.OnStatusUpdate += ServerStatusUpdate;
            _playfabService.OnUpdateButton += UpdateButtonState;

            startGameButton.onClick.AddListener(StartGame);
            playerNameInput.onValueChanged.AddListener(NameChanged);
            if (PlayerPrefs.HasKey("PlayerName"))
                playerNameInput.text = PlayerPrefs.GetString("PlayerName");

            _playfabService.LoginPlayer();
        }
    }

    private void OnDestroy()
    {
        if (!InstanceFinder.ServerManager.GetStartOnHeadless())
        {
            _playfabService.OnStatusUpdate -= ServerStatusUpdate;
            _playfabService.OnUpdateButton -= UpdateButtonState;
        }
    }

    private void StartGame()
    {
        startGameButton.interactable = false;
        serverStatus.text = "";
        _playfabService.CreateTicket();
    }

    private void ServerStatusUpdate(string status, bool isError)
    {
        serverStatus.text += "\n" + status;
        serverStatus.color = isError ? Color.red : Color.green;
        Debug.Log(status);
    }

    private void UpdateButtonState(bool state)
    {
        startGameButton.interactable = state;
        serverStatus.text = "";
    }

    private void NameChanged(string text) => PlayerPrefs.SetString("PlayerName", text);
}
```

#### PlayfabRestApiService

```cs
public class PlayfabRestApiService : MonoBehaviour
{
    [SerializeField] private string PlayerCustomID = "PLAYER_CUSTOM_ID";
    [SerializeField] private string PlayerTitleID = "PLAYER_TITLE_ID";
    [SerializeField] private string TitleID = "TITLE_ID";
    [SerializeField] private string QueueName = "QUEUE_NAME";

    private const string TypeHeaderValue = "application/json";
    private readonly HttpClient _playfabHttpClient = new();
    private HttpResponseMessage _request;
    private StringContent _requestData;
    private string _response;
    private string _ticketID = "";
    private string _matchID = "";

    public Action<string, bool> OnStatusUpdate;
    public Action<bool> OnUpdateButton;

    private static PlayfabRestApiService _instance = null;

    private void Awake()
    {
        _playfabHttpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue(TypeHeaderValue));

        if (_instance is null)
        {
            DontDestroyOnLoad(this);
            _instance = this;
        }
        else
        {
            Destroy(this);
        }
    }

    public async void LoginPlayer()
    {
        var requestJson = new JSON();
        requestJson.Add("CustomID", PlayerCustomID);
        requestJson.Add("CreateAccount", false);
        requestJson.Add("TitleID", TitleID);
        _requestData = new StringContent(requestJson.CreateString(), Encoding.UTF8, TypeHeaderValue);

        _request = await _playfabHttpClient.PostAsync($"https://{TitleID}.playfabapi.com/Client/LoginWithCustomID", _requestData);
        _response = await _request.Content.ReadAsStringAsync();

        if (_request.IsSuccessStatusCode)
        {
            var responseJson = JSON.ParseString(_response);

            string token = responseJson.GetJSON("data").GetJSON("EntityToken").GetString("EntityToken");
            _playfabHttpClient.DefaultRequestHeaders.Add("X-EntityToken", token);

            string sessionTicket = responseJson.GetJSON("data").GetString("SessionTicket");
            _playfabHttpClient.DefaultRequestHeaders.Add("X-Authorization", sessionTicket);

            OnUpdateButton?.Invoke(true);
            OnStatusUpdate?.Invoke("Login Successful", false);
        }
        else
        {
            OnStatusUpdate?.Invoke($"Unable To Login Player, Error {(int)_request.StatusCode} With Message: \n{_response}", true);
        }
    }

    public async void CreateTicket()
    {
        var requestJson = new JSON();

        var entityProperty = new JSON();
        entityProperty.Add("Id", PlayerTitleID);
        entityProperty.Add("Type", "title_player_account");

        var creatorProperty = new JSON();
        creatorProperty.Add("Entity", entityProperty);

        requestJson.Add("Creator", creatorProperty);
        requestJson.Add("GiveUpAfterSeconds", 90);
        requestJson.Add("QueueName", QueueName);
        _requestData = new StringContent(requestJson.CreateString(), Encoding.UTF8, TypeHeaderValue);

        _request = await _playfabHttpClient.PostAsync($"https://{TitleID}.playfabapi.com/Match/CreateMatchmakingTicket", _requestData);
        _response = await _request.Content.ReadAsStringAsync();

        if (_request.IsSuccessStatusCode)
        {
            var responseJson = JSON.ParseString(_response);
            _ticketID = responseJson.GetJSON("data").GetString("TicketId");

            OnStatusUpdate?.Invoke($"Ticket Created, ID #{_ticketID}", false);

            GetMatchIdAttempt();
        }
        else
        {
            OnUpdateButton?.Invoke(true);
            OnStatusUpdate?.Invoke($"Unable To Create Ticket, Error {(int)_request.StatusCode} With Message: \n{_response}", true);
        }
    }

    private async void GetMatchIdAttempt()
    {
        bool isMatchFound = false;
        var requestJson = new JSON();
        requestJson.Add("EscapeObject", true);
        requestJson.Add("QueueName", QueueName);
        requestJson.Add("TicketId", _ticketID);
        _requestData = new StringContent(requestJson.CreateString(), Encoding.UTF8, TypeHeaderValue);

        while (!isMatchFound)
        {
            _request = await _playfabHttpClient.PostAsync($"https://{TitleID}.playfabapi.com/Match/GetMatchmakingTicket", _requestData);
            _response = await _request.Content.ReadAsStringAsync();

            if (_request.IsSuccessStatusCode)
            {
                var responseJson = JSON.ParseString(_response);
                string ticketStatus = responseJson.GetJSON("data").GetString("Status");
                isMatchFound = ticketStatus == "Matched";

                if (isMatchFound)
                {
                    _matchID = responseJson.GetJSON("data").GetString("MatchId");
                    OnStatusUpdate?.Invoke($"Ticket Has Been Matched, ID #{_matchID}", false);

                    StartConnectionAttempt();
                }
                else if (ticketStatus == "Canceled")
                {
                    isMatchFound = true;
                    string reason = responseJson.GetJSON("data").GetString("CancellationReason");

                    OnUpdateButton?.Invoke(true);
                    OnStatusUpdate?.Invoke($"Ticket Has Been Cancelled Due To {reason}", false);
                }
                else
                {
                    OnStatusUpdate?.Invoke("Match Not Found, Retrying In 10 Seconds...", false);
                    await Task.Delay(10000);
                }

            }
            else
            {
                isMatchFound = true;
                OnUpdateButton?.Invoke(true);
                OnStatusUpdate?.Invoke($"Could Not Get Ticket Info, Error {(int)_request.StatusCode} With Message: \n{_response}", true);
            }
        }
    }

    private async void StartConnectionAttempt()
    {
        bool gotConnectionInfo = false;

        var requestJson = new JSON();
        requestJson.Add("Keys", new List<string> { _matchID });

        _requestData = new StringContent(requestJson.CreateString(), Encoding.UTF8, TypeHeaderValue);

        while (!gotConnectionInfo)
        {
            _request = await _playfabHttpClient.PostAsync($"https://{TitleID}.playfabapi.com/Client/GetUserData", _requestData);
            _response = await _request.Content.ReadAsStringAsync();

            if (_request.IsSuccessStatusCode)
            {
                var responseJson = JSON.ParseString(_response);
                var dataObject = responseJson.GetJSON("data").GetJSON("Data");

                if (dataObject.Count > 0)
                {
                    gotConnectionInfo = true;
                    string connectionInfo = dataObject.GetJSON(_matchID).GetString("Value");
                    string serverAddress = connectionInfo.Split(':')[0];

                    if (ushort.TryParse(connectionInfo.Split(':')[1], out ushort serverPort))
                    {
                        InstanceFinder.TransportManager.Transport.SetPort(serverPort);
                        InstanceFinder.TransportManager.Transport.SetClientAddress(serverAddress);
                        Debug.Log($"Connecting To Server Using Port {serverPort} And IP {serverAddress}");
                        InstanceFinder.ClientManager.StartConnection();
                    }
                    else
                    {
                        OnUpdateButton?.Invoke(true);
                        OnStatusUpdate?.Invoke($"Error While Parsing Server Port Value", true);
                    }
                }
                else
                {
                    OnStatusUpdate?.Invoke("No Connection Data Found, Retrying In 10 Seconds...", false);
                    await Task.Delay(10000);
                }
            }
            else
            {
                gotConnectionInfo = true;
                OnUpdateButton?.Invoke(true);
                OnStatusUpdate?.Invoke($"Could Not Get Player Data, Error {(int)_request.StatusCode} With Message: \n{_response}", true);
            }
        }
    }

    public async void RemovePlayerData()
    {
        var requestJson = new JSON();
        requestJson.Add("KeysToRemove", new string[] { _matchID });

        _requestData = new StringContent(requestJson.CreateString(), Encoding.UTF8, TypeHeaderValue);
        _request = await _playfabHttpClient.PostAsync($"https://{TitleID}.playfabapi.com/Client/UpdateUserData", _requestData);
        _response = await _request.Content.ReadAsStringAsync();

        if (!_request.IsSuccessStatusCode)
        {
            Debug.Log($"Could Not Update PlayerData, Error {(int)_request.StatusCode} With Message: \n{_response}");
        }
    }

    ...
}
```

#### PlayerDataUpdateService

```cs
public class PlayerDataUpdateService : NetworkBehaviour
{
    private PlayfabRestApiService _playfabService;

    ...

    public override void OnStartClient()
    {
        _playfabService = FindObjectOfType<PlayfabRestApiService>();
        _playfabService.RemovePlayerData();
    }
}
```

### Building Game Server & Containerizing

Before containerizing the server build, make sure to enable the `Start On Headless` option in the `NetworkManager` gameObject.

Open the Edgegap plugin with the `Tools/Edgegap Hosting` toolbar menu. Verify your `Edgegap API Token` and either create or load an application for the game. Make sure the `port` value matches that of the Tugboat component of the `NetworkManager` gameObject. Select the `UDP` protocol, then enter a `New Version Tag`. Make sure that both the app name and version match the values that were used when setting up the Cloud Script.

Once this is properly set up, click on `Build and Push`, which will automatically containerize your game server and create a new application version on the Edgegap dashboard after a short waiting period.

{% hint style="info" %}
When creating the app version, the plugin will name the port \`"Game Port"\` by default.

If you choose to manually containerize and create your app version instead of using the plugin, make sure to use that name when selecting which port to use.
{% endhint %}

### Testing

Make sure to first disable the `Start On Headless` option in the `NetworkManager` gameObject. Set the `PlayfabRestApiService` script with the `Custom ID` and `Title ID` of your first player, along with your game's `Title ID` and `Queue Name`. In the `Build Settings`, create a new client build with these settings.

Once the build is complete, change the `Custom ID` and `Title ID` values to that of your second player. You can create a separate client build if you want, although the Unity editor in play mode should work just as well.

If both clients login properly on launch, click on both instance's `Start Game` button. After a short while, they will be matched through PlayFab's matchmaker, then connect to the same deployment on Edgegap once the server has finished setting up.


# Endpoint Storage

Endpoint Storage allows you to register an S3 Bucket in our system. When you have an Endpoint Storage set in our environment, you will be able to store some data from your deployment like the container's log.

{% hint style="info" %}
If you have already set up an Endpoint Storage and want to know how to save your container logs, please refer to the next section [How to Save Deployment Container Logs](https://docs.edgegap.com/docs/endpoint-storage/save-container-logs).
{% endhint %}

### How to Setup an Endpoint Storage

It is pretty simple to register your S3 Bucket if you follow these quick steps.

To see and set up a new Endpoint Storage, you need to go to the left menu and click on the `Log Storage` menu item.

<figure><img src="https://3027732442-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2Fgit-blob-7d37a725cd5544c43cdc7b917a8875a335ba9cc0%2Fnavbar-menu.png?alt=media" alt=""><figcaption></figcaption></figure>

The first time you land on this page, you will not see any Endpoint storage in the list. Click on the create button in the upper right corner. You will be invited to complete this form. All fields are mandatory.

<figure><img src="https://3027732442-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2Fgit-blob-2e80fecc21d4ff6ae5ff44dbc06872ab59b9e5b1%2Fcreate-form.png?alt=media" alt=""><figcaption></figcaption></figure>

**Name**

The name you want to give to your Endpoint Storage in our platform. It must be unique since you will be able to use it in some API calls.

**Access Key ID**

Pretty straightforward, the Access Key ID from your S3 Bucket.

**Secret Access Key**

The Secret Access Key from your S3 Bucket. This field will be encrypted and you will not be able to modify it once you saved your Endpoint Storage. Don't worry if you put the wrong Access Key, you will be able to completely delete the Endpoint Storage and create a new one.

**Endpoint URL**

Your S3 Bucket URL. Ensure that you include the full link (https\://, http\://, etc). You will be able to test it further in the process.

**Linode**

{% hint style="warning" %}
For Linode, the endpoint URL should NOT include the bucket name. For example: If your S3 bucket URL is <https://my-bucket.some-region.provider-name.com/>, the endpoint URL you should enter is <https://some-region.provider-name.com/>.
{% endhint %}

**AWS**

{% hint style="warning" %}
For AWS, the endpoint URL MUST include the bucket name. For example: If your S3 bucket name is my-test and your bucket URL is <https://my-test.s3.us-east.amazonaws.com>, the endpoint URL you should enter is <https://my-test.s3.us-east.amazonaws.com>.
{% endhint %}

**Bucket**

The name of your Bucket. Make sure to put the right name associated with the credential. Otherwise, we will not be able to access it correctly.

### Manage your Endpoint Storage

You can access all your Endpoint Storage available with the upper right menu. You can remove and test your Endpoint Storage. We are not deleting your S3 Bucket, we only remove the connection information from our system. If you want to update an Endpoint Storage, you must delete it and create a new one.

When you press "Test" button, it will upload a file named "connection\_test" under the "edgegap" directory in your S3 Bucket. You will have an alert box to notify you if it worked or not. If not, you might have something wrong in your Endpoint Storage configuration.

<figure><img src="https://3027732442-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2Fgit-blob-218d863dddff861e4fee9238e08c8411c61389f0%2Fendpoint-storage-list.png?alt=media" alt=""><figcaption></figcaption></figure>


# How to Save Logs

When you create a deployment, your container generates logs. You can save these logs to an S3 Bucket of your choice once you terminate your deployment. By setting up an Endpoint Storage, you will be able to retrieve these logs at any time, even after the deployment has been terminated.

### Link your Endpoint Storage with your Application Version

To accomplish this, you will need to link your App Version to your Endpoint Storage. Navigate to the App Version details page, and look for the **Container Logs Storage** section. Enable the switch box and select your Endpoint Storage in the select box.

<figure><img src="https://3027732442-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2Fgit-blob-a743dbd6e34bc30e7c8881ae156ac48735d59778%2Flink-with-app-version.png?alt=media" alt=""><figcaption></figcaption></figure>

{% hint style="warning" %}
If you enable container logs storage without selecting a valid Endpoint Storage, you will not be able to retrieve your logs. To ensure you have a valid Endpoint Storage, please refer to the [setup documentation](https://docs.edgegap.com/docs/endpoint-storage).
{% endhint %}

That's it! Every deployment with this application version will now store the container logs in your S3 Bucket.

#### Default Directory Path

The path in your S3 Bucket will look like this.

* edgegap/arbitrium
* The first part of your client email, most S3 browsers don't like "@"
* The name of your Endpoint Storage
* app / app version / container\_log
* The date YYYY-MM-DD

<figure><img src="https://3027732442-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2Fgit-blob-9e4b987d5fa8275831d78a21bea097bde8a54008%2Fpath.png?alt=media" alt=""><figcaption></figcaption></figure>

You can create multiple Endpoint Storage with the same S3 Bucket but with a different name. That way, you could have various directories for numerous environments if you wanted.

<figure><img src="https://3027732442-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2Fgit-blob-33963f6333372abb9ace629a150ce6829352779d%2Fdirectory.png?alt=media" alt=""><figcaption></figcaption></figure>

#### Additional Use Cases

{% hint style="success" %}
These use cases can be useful when testing, and you don't want all of your deployments logs sent to storage.
{% endhint %}

**Save container logs with your Deployment request**

When you create a deployment, you can specify if you want to store your container logs with your Deployment request. This independent of the application version settings, meaning that it is not necessary to have previously set up the Endpoint Storage with your application version, but simply to have a functional Endpoint Storage.

You can do this by adding the following JSON to your Deployment request. The `endpoint_storage` is the name of your Endpoint Storage.

```json
{
  "container_log_storage": {
    "enabled": true,
    "endpoint_storage": "demo-bucket"
  }
}
```

{% hint style="info" %}
If the `endpoint_storage` is not provided, we'll attempt to use the app version's endpoint storage. If no endpoint storage is found, container logs won't be stored.
{% endhint %}

**Save container logs with your Stop request**

Another convenient way to use it is when you terminate your deployment. If you have reason to believe something went wrong inside your container, you can request to save the container logs. This option is available with the Deployment stop and Self stop routes.

You can do it by adding the query parameter `container_log_storage` to your request. The param `container_log_storage` is the name of your Endpoint Storage. You can also put `true` to use the app version's endpoint storage.

You can check our [API Documentation](https://docs.edgegap.com/docs/api) for more details on the deployment and stop request parameters.


# Upload File to Deployment

{% hint style="info" %}
This feature is currently only available through the [API](https://docs.edgegap.com/docs/api).
{% endhint %}

It is possible to upload files from your S3 bucket to your deployment. Since the files are only downloaded when a deployment is created, you can modify the files in your bucket and see the changes in the next deployment you create.

### Pull profiles

Pull profiles define what files or folders should be downloaded from your S3 bucket and where to save them in your deployment.

Before creating a pull profile, ensure you have at least one [Endpoint Storage](https://docs.edgegap.com/docs/endpoint-storage) configured.

You will then want to create a pull profile within this bucket with the following information:

* The **name** of the pull profile: This will be used to associate the pull profile to your app versions later on, so it should be unique and descriptive.
* The **source** path: The path to the file or folder in your S3 bucket. It should start with a slash, and its root is the root of your bucket.
* The **source\_type**: This can be either "file" or "folder" and must be set correctly for the download to succeed.
* The **destination** path: The path in your deployment where the file or folder will be saved. It should start with a slash, and its root is the root of your container image.

{% hint style="warning" %}
Make sure to avoid protected destinations, such as `/etc/`, as this will prevent the files from being copied to your deployment and will make your deployment fail. Make sure a normal user can write to the destination folder.
{% endhint %}

For example, if you wanted to copy the file `some-file.txt`, from your bucket, to the `custom-folder` folder in your deployment, with both file structures as described below:

```
s3://my-bucket/
├─ some-folder/
│  ├─ some-file.txt
├─ some-other-folder/
│  ├─ some-other-file.jpg
```

```
/
├─ app/
│  ├─ entrypoint.sh
│  ├─ custom-folder/

```

You would create your pull profile with the following information:

```json
{
  "name": "some-file-pull-profile",
  "source": "/some-folder/some-file.txt",
  "source_type": "file",
  "destination": "/app/custom-folder/"
}
```

For more details, [see the API documentation](https://docs.edgegap.com/docs/api).

### Linking a pull profile to an app version

After creating a pull profile, you must link an app version to it, so the files are downloaded when a deployment is created. That way, you can use multiple pull profiles for a single app version and reuse pull profiles between app versions.

[See the API documentation](https://docs.edgegap.com/docs/api)

### Limitations

The total size of the files downloaded to the deployment cannot exceed 5 MB.

If this limit is reached, you will be notified at deployment time so that you can promptly resolve the issue.


# DDoS Protection

Learn how edge computing prevents [Denial of Service](https://www.cloudflare.com/learning/ddos/what-is-a-ddos-attack/) attacks on your game servers.

**Server outages can easily ruin player experience and seriously harm your game's and studio's reputation.** Aside from dev team accidents, provider outages, or localized ISP issues, malicious Denial of Service attacks are amongst the top threats that every studio has to keep in mind.

Malicious parties attacking your infrastructure often try to flood your network with requests to a point of saturation where legitimate user's network packets can no longer reach your services, or are severely impacted in response times and availability.

{% hint style="success" %}
Edgegap goes beyond traditional measures and **brings protection to the edge instance infrastructure**.
{% endhint %}

To mitigate and recover from DDoS attacks automatically:

1. We detect all the usual attack vectors early - TCP SYN floods, UDP floods, and HTTP floods.
   1. Metrics include Port Connection Rate, Source Connection Rate, Total Connection Rate.
2. We declare the machine Under DoS and steer [deployments](https://docs.edgegap.com/learn/orchestration/deployments "mention") away from the targeted site.
3. To reduce impact on running games we perform upstream scrubbing, and inject routing/firewall policies locally at the edge, adding a null route redirect for suspicious incoming traffic.
   1. Due to traffic filtering at the edge, the wasted upstream bandwidth from server is minimal.
4. Once players conclude their match on the targeted site and disconnect, we recycle the site's IP address to ensure subsequent matches will not be targeted by the same attacker.
   1. New matches will use a fresh server IP address and port assigned randomly.

{% hint style="info" %}
If you have particular questions or concerns don't hesitate to contact us over our [Community Discord](https://discord.gg/NgCnkHbsGp).
{% endhint %}


# Glossary

### A

#### Active User

* **Daily Active Users (DAU)**: a metric that measures the number of unique users who engage with Edgegap within a single day.
* **Monthly Active Users (MAU)**: a metric that measures the number of unique users who engage with Edgegap within a single month.

#### Application

An application serves as the foundational unit for deployments. While it contains only a minimal set of options, it acts as a container where versions can be created and managed. The majority of configurations and settings are not directly associated with the application but are defined in its versions.

#### Application Version

An application version functions as the blueprint for your deployments, dictating their behavior and characteristics. It offers a high degree of flexibility, allowing you to specify various settings and configurations. Any changes made to a version are automatically reflected in the deployments that use that version.

#### API Gateway

A server that acts as an API front-end, receiving API requests, enforcing throttling and security policies, passing requests to the back-end service, and then passing the response back to the requester.

### B

#### Bare-metal server

A type of server that provides dedicated and unshared physical resources, including CPU, RAM, and storage, to a single tenant.

### C

#### Client

A software application or device that requests services or resources from a server. In a client-server architecture, the client initiates communication. Relates to [Host](#host).

#### Client Agent

A software program that acts as a mediator between the gaming client and the edge computing infrastructure. It is responsible for collecting data from the client and transmitting it to the edge server for processing. The purpose of the Client Agent is to improve the performance of the gaming experience by offloading some of the computational load from the client device to the edge server. This allows for faster response times and a more immersive gaming experience for the end-user.

#### Cluster

A group of interconnected servers that work together as a single system to provide high availability, load balancing, and/or parallel processing.

#### Colocation center

A data center that provides a physical location for gaming companies to store their gaming infrastructure, such as servers and network equipment, close to the end-users to ensure low latency and high performance. This type of data center enables gaming companies to efficiently manage their gaming infrastructure and ensure optimal user experience for their players.

#### Containerization

A lightweight form of virtualization that helps to isolate applications from each other and improve their deployment and maintainability.

#### Containers

A technology used in edge computing for gaming that allows for the efficient and isolated deployment of gaming applications and services. They provide a standardized and lightweight solution for deploying and scaling gaming applications, while also ensuring compatibility and consistency in their execution environment. This helps to reduce downtime and improve performance for gamers, ultimately leading to a better gaming experience.

### D

#### Deployment

A deployment is an operational instance of a specific version of your application, encapsulated within an active container. Upon providing a list of IPs or a location, you receive a URL for connecting your players or users. Deployments are designed to be temporary; they are terminated upon request when no longer needed. This model is particularly effective for time-boxed game genres like FPS, fighting games, and MOBA, where the player roster remains constant throughout the server's lifecycle. For more dynamic player interactions, such as MMOs, a different approach like sessions is recommended. Real-time telemetry is collected for each deployment to optimize location and enhance user experience.

#### Distributed Relay Manager

The Distributed Relay Manager is a specialized service within Edgegap's distributed cloud network, designed to optimize relay selection for players. Utilizing Edgegap's patented real-time telemetry decision technology, it ensures that players are connected to the most suitable relay from among hundreds of available locations. The service aims to simplify the complex task of relay implementation and management, allowing for easier integration into games or applications without requiring extensive technical know-how.

#### Docker

A platform that uses containerization technology to package and run applications and their dependencies in isolated environments, ensuring consistency across multiple systems.

#### Dedicated Server

A server that is reserved for the exclusive use of a single tenant or application. Unlike shared servers, all the resources of a dedicated server are available to one user.

### E

#### Edge Computing

A distributed computing paradigm that brings computation and data storage closer to the location where it is needed, to improve response times and save bandwidth.

#### Egress

“the act of going out,” “the right to go out,” or “the means of going out.”

#### Elastic Cloud Computing

ECC is a technology that enables gaming companies to scale their infrastructure resources on-demand, providing high levels of performance and security in the process. ECC provides a comprehensive platform for game developers, delivering centralized storage and computing services, real-time data processing, and dynamic resource allocation for high-end gaming applications.

#### Endpoint

A specific URL where a web service or API can be accessed. Endpoints are the points of interaction between different software entities.

#### Endpoint Storage

A storage solution that uses Amazon S3 (Simple Storage Service) as a remote repository for storing data. This is often used for backup, archiving, or data sharing.

#### Environment Variables

Key-value pairs that are used to configure settings for applications. They can be set and accessed within the operating system or directly within a container.

### F

#### Fleet

A fleet is a management tool designed to automate the creation of session-based deployments. It operates based on configurable settings to ensure optimal server capacity. Fleets can also automatically terminate deployments based on more advanced configurations.

#### Fleet Functions

1. Automatically creates new deployments when existing ones reach a specified capacity threshold.
2. Ensures a minimum number of ready-to-use deployments.
3. Allows setting a maximum limit on simultaneous deployments.
4. Operates within a specific region to control server distribution.

#### Fleet Management

Manage a large number of servers in real-time for multiplayer gaming. It helps the technical product manager monitor and control the resources of these servers, ensuring optimal performance and minimizing downtime.

### H

#### Host

A computer or server that provides resources, services, or data to other computers (known as clients) over a network. Relates to [Client](#client).

#### Hosting Relay

A platform for hosting game servers closer to end-users. This improves the speed and reliability of game play by reducing latency and reducing the load on central servers.

### I

#### Ingress

“the act of entering,” “the right of entering,” or “the means of entering.”

### J

#### Jitter

The variability in the latency of data transmission. It refers to the variations in the delay of data packets that are transmitted over a network and affects the performance of real-time gaming. Jitter can impact the smoothness of the gaming experience and cause lag, delay, and other disruptions.

### K

#### Kubernetes

An open-source platform designed to automate deploying, scaling, and operating application containers.

### L

#### Latency

The amount of time it takes for data to be transmitted from a device to a server and back.

#### Log (Container Log)

A record of events and transactions that occur within a container. These logs are crucial for debugging and monitoring the performance of containerized applications.

### N

#### Netcode

A critical component of the gaming infrastructure that must be designed and optimized to meet the demands of modern gaming, including real-time interactivity, high-resolution graphics, and support for large numbers of simultaneous players. This requires a deep understanding of network protocols, data compression, and other technologies that can be used to optimize gaming performance, and an ability to collaborate with network engineers and other stakeholders to implement effective solutions.

#### Network Status

The quality and availability of the network connection between the gaming device and the edge computing server. This is important because it affects the player's experience with the game. The network status can impact the game's performance such as speed, responsiveness, and reliability. If the network connection is unreliable, players may experience lag, slowdowns, and even disconnections. A good network status is crucial for a seamless gaming experience and should be monitored and optimized for the best performance.

### M

#### Multi-Access Edge Computing (MEC)

A network architecture concept that enables cloud computing capabilities and an IT service environment at the edge of the cellular network.

### P

#### PaaS

A cloud-based platform that provides gaming developers with the necessary infrastructure and tools to build, deploy, and manage their gaming applications at the edge of the network. The Edgegap platform leverages the power of edge computing to deliver low latency and high-speed gaming experiences to users. It also offers scalability, security, and reliability, making it an ideal solution for gaming developers looking to enhance their gaming applications.

#### Packet Loss

The phenomenon of data packets being lost or discarded while being transmitted between different computing devices in a network. Packet loss is caused by various factors including:

1. Overloaded Network: A network can become congested due to high traffic, resulting in data packets being discarded.
2. Network Latency: Delays in the network can cause packets to arrive too late, resulting in their being discarded.
3. Data Corruption: Packets can become corrupted during transmission, making them unreadable and causing them to be discarded.
4. Technical Issues: Issues such as hardware failure, outdated hardware, or software bugs can cause packets to be lost.
5. Distance: Packets traveling long distances are more likely to be lost due to issues such as signal interference.
6. Outdated Protocols: Using outdated protocols can cause packets to be lost, as modern networks are optimized for newer technologies.
7. Routing Errors: Packets can be lost due to incorrect routing, causing them to be sent to the wrong destination."

#### Persistent Storage

The capability of storing game data and information on the edge device itself, instead of relying on the cloud or central servers. This ensures that the game data and progress is not lost, even when there is a temporary loss of connectivity or network disruption. This is essential for providing seamless gaming experiences, particularly for multi-player games where continuous connectivity is crucial.

#### Policy Engine

Managing and regulating the flow of game data and processing, as it directly impacts the overall performance and user experience of the gaming application.

#### Pulse Cloud

A cloud-based platform that provides edge computing solutions for gaming applications. This technology enables real-time processing of gaming data, improving performance, and reducing latency for end-users. Can play a crucial role in providing a seamless gaming experience by processing critical data at the edge of the network, closer to the user. This results in a reduced reliance on central servers, reducing server congestion and improving performance, making it an ideal solution for high-performance gaming applications.

### R

#### Rate Limit

A rate limit is the maximum number of API requests allowed (usually per second) either for a specific HTTP method, a specific HTTP resource, a defined group of HTTP methods or resources with closely related usage patterns, an entire product (such as [matchmaking](https://docs.edgegap.com/learn/matchmaking "mention") or [server-browser](https://docs.edgegap.com/learn/server-browser "mention")), or a global rate limit for an entire organization.

Rate limits help:

1. Prevent abuse, resource starvation, and Denial of Service attacks due to malicious attackers.
2. Distribute available compute and networking capacity across users or API resources fairly.

Once the rate limit for the given time period (usually 1 second) is reached, the user cannot complete any more requests until the next time period begins (next second). Rate limit restrictions are best handled on client side by detecting HTTP response `429 Too Many Requests`  and retrying requests several times after waiting for an [exponentially increasing jittered backoff period](https://dev.to/biomousavi/understanding-jitter-backoff-a-beginners-guide-2gc).

#### Relay

A relay is a network node that acts as an intermediary for routing data packets between the client and server. Edgegap Relays are strategically located across a distributed cloud network to optimize data transmission. They are selected based on real-time telemetry decision technology to ensure the best possible user experience, particularly in gaming scenarios.

#### Relay System

Technology that allows the distribution of computing tasks between different devices and servers in a network, reducing the load on a single device and ensuring smooth and fast performance. The Relay System acts as a bridge between the edge devices and the cloud servers, enabling real-time data exchange and ensuring low latency and high-quality gaming experience for the end-user.

#### Repository

A centralized storage location where code, data, or artifacts are stored and managed, often under version control.

### S

#### Server Image

A snapshot of a server's configuration, including the operating system, installed software, and settings, which can be used to create new server instances.

#### Session

A session functions as a sub-layer within a deployment, specifically designed to manage more dynamic elements like sockets or available space. Sessions are particularly useful in the following scenarios:

1. Managing the hop-in and hop-out of individual players or groups within a deployment, and
2. Facilitating multiple matches or games within a single deployment. Further details on sessions will be discussed separately

#### Session - Match Type

In a match-type session, each session occupies one socket space, regardless of the number of players in that session. For example, three sessions with ten players each would occupy only three out of five available sockets. Deleting a session reduces the used socket count accordingly.

#### Session - Seat Type

In a seat-type session, each player occupies one socket space within a deployment. For instance, if a deployment has ten sockets, a solo player and a party of four would occupy five sockets. Deleting a session frees up the corresponding number of sockets.

#### Serverless FaaS

Gaming applications and services can run without the need for a dedicated server, and can instead be deployed on a cloud platform like Edgegap that offers serverless computing capabilities. This allows for faster and more efficient processing of gaming data, and also eliminates the need for investment in hardware, maintenance, and scaling.

#### Sidecar

Enables games to run on a remote server instead of on a local device, which can reduce lag and improve performance.

#### Single Point of Presence

A single, centralized location in a network where all traffic is routed for specific services or applications. This is often used to simplify network architecture and improve performance.

### T

#### Telemetry

The collection and analysis of real-time data from the gaming environment, devices and players. This data is used to provide valuable insights into the performance and behavior of the game and its players.

#### Tick rate

The number of times per second that a game's server updates the game's state, including player positions, actions, and other events.

While higher tick rate can provide more responsive gameplay to players, it also increases the game server's CPU requirements in order to pack and unpack more messages in the same amount of time.

Ballpark tick rates by game category:

* cooperative and social games (latency tolerant) - 30 Hertz (30 updates per second),
* competitive and PvP games - 60 Hertz,
* tournaments, VR & XR games - 128 Hertz.

### U

#### Usage Parameter Control

The ability to monitor and manage the utilization of computing resources at the edge devices, specifically for gaming purposes. This includes setting and enforcing limits on parameters such as memory, storage, and processing power to optimize the gaming experience and prevent overloading the edge devices.


# SLA Terms

At Edgegap, we support our clients throughout the lifecycle of their games.

## Here is how we will support your game:

* Dedicated Slack/Discord channel support.
* ServiceDesk Tickets support.
* Active monitoring.
* A support representative will be available via email or phone 24/7 for `Priority1` incidents.
* When submitting an error, the client may indicate the severity of the initial response in accordance with the severity guidelines.
* The availability of the service for any given month will be 99.9%.
* Edgegap shall provide notice 72 hours in advance of any scheduled maintenance where downtime is reasonably possible or expected.

| Severity Level | Description                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            | Initial Response & Acknowledgment | Targeted Best Effort Fix Date or Workaround                                                             | Continuous Effort & Updates                                            |
| -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | --------------------------------- | ------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------- |
| 1              | Edgegap service or component thereof is completely inaccessible or the majority of its functionality is unusable and inaccessible.                                                                                                                                                                                                                                                                                                                                                                     | 15 minutes                        | 1 hour for a workaround4 hours for complete resolution of error                                         | Edgegap will commit full-time resources 24/7; updates provided hourly. |
| 2              | One or more key features/components of the Edgegap service are unusable.Unable to perform basic Edgegap service functions or there is a significant degradation in such basic functions or features.                                                                                                                                                                                                                                                                                                   | 15 minutes                        | 2 hours for a workaround1 calendar day for complete resolution of error                                 | Edgegap will commit full-time resources 24/7; updates provided hourly. |
| 3              | An Edgegap service feature/component is not operating in accordance with the documentation which does not fall into an error severity Level 2.Enhancements or defects in the Edgegap service that are targeted for updates, but do not result in the significant loss or degradation in functionality in a major Edgegap service feature/component. Functionality is noticeably impaired or degraded but clients use of the Edgegap service can continue; and in each case, a workaround is available. | 2 hours                           | Next new functionality of Edgegap service or prioritized to be fixed in a mutually agreeable timeframe. | Updates provided weekly.                                               |
| 4              | All enhancement and new functionality requests. Client requires information or assistance on capabilities, installation, or configuration of the Edgegap service.                                                                                                                                                                                                                                                                                                                                      | 1 business day                    | At Edgegap’s reasonable discretion                                                                      | N/A                                                                    |


# Pour commencer

Edgegap vous aide à mettre votre jeu multijoueur en ligne et à exploiter des serveurs de jeu de manière rentable :

<table data-view="cards"><thead><tr><th align="center"></th><th data-hidden data-card-cover data-type="files"></th></tr></thead><tbody><tr><td align="center"><strong>1. Construisez votre serveur</strong></td><td><a href="https://3008966946-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2FkxE7UFjVLfT9Z2LPvaGQ%2Fvlcsnap-2024-05-27-20h30m21s309.png?alt=media&#x26;token=ff1fafdc-a1e0-49f2-af46-b5a1cecdb903">vlcsnap-2024-05-27-20h30m21s309.png</a></td></tr><tr><td align="center"><strong>2. Téléchargez la build</strong></td><td><a href="https://3008966946-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2FKByjuu0ZjRUmuTD4ywVM%2Fvlcsnap-2025-05-01-11h22m45s961.png?alt=media&#x26;token=a2457add-9994-4cd8-b309-b6552ab9770b">vlcsnap-2025-05-01-11h22m45s961.png</a></td></tr><tr><td align="center"><strong>3. Déployez et connectez</strong></td><td><a href="https://3008966946-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2FYu1AvHWaQTeNwvFohVQs%2FScreenshot_86.png?alt=media&#x26;token=6a54006b-df3b-4507-ab5e-afd887776300">Screenshot_86.png</a></td></tr></tbody></table>

{% hint style="success" %}
[Inscrivez-vous gratuitement sur Edgegap et découvrez notre plateforme dès aujourd'hui](https://app.edgegap.com/auth/register), aucune carte de crédit requise.
{% endhint %}

## 🚀 Pour commencer

{% hint style="success" %}
Commencez avec une base solide, en utilisant l'un des [nos projets d'exemple gratuits](https://docs.edgegap.com/docs/sample-projects), facilement adaptés à votre projet.
{% endhint %}

## ❓ Qu'est-ce que l'hébergement et l'orchestration de serveurs de jeu ?

{% embed url="<https://youtu.be/2_vTh9b-mYw>" %}

Pour que les joueurs se connectent et jouent en ligne, vous aurez besoin d'un serveur de jeu chargé de l'autorité, de la logique du jeu et des mécanismes de gameplay. [Il peut s'agir d'un serveur dédié (à distance, cloud ou bare metal) ou d'un hôte joueur (serveur d'écoute avec relais, pair à pair).](https://edgegap.com/blog/explainer-series-authoritative-servers-relays-peer-to-peer-understanding-networking-types-and-their-benefits-for-each-game-types)

Edgegap orchestre des serveurs de jeu dans le monde entier à travers plus de 615 emplacements physiques et plus de 17 fournisseurs de centres de données pour assurer le déploiement à l'emplacement idéal. Notre stratégie brevetée est la solution clé en main de premier ordre pour réduire la latence et minimiser les coûts d'exploitation (hébergement) pour les studios de jeux, grâce à notre tarification à l'usage.

## 🟢 Après votre premier déploiement

Pour tirer le meilleur parti d'Edgegap, consultez des **Bonnes pratiques et insights**:

* [préparez-vous au lancement - checklist pré-lancement, incluant des tests de charge](https://edgegap.com/blog/multiplayer-game-pre-launch-checklist),
* [montez à 14 millions d'utilisateurs simultanés en 60 minutes](https://edgegap.com/resources/performance-benchmark),
* [publiez des mises à jour sans temps d'arrêt et simplifiez le DevOps](https://docs.edgegap.com/docs/gen2-matchmaker#rolling-updates-ab-tests).

## 📣 Communauté Discord

{% hint style="success" %}
[Rejoignez notre Discord communautaire](https://discord.gg/MmJf8fWjnt) pour réseauter avec des studios et obtenir le soutien de notre équipe !
{% endhint %}


# Unreal Engine

Apprenez en pratiquant et déployez votre premier serveur dédié sur Edgegap. À la fin de ce guide, vous aurez déployé un serveur dédié avec Edgegap sans frais.

Construire avec Docker Desktop est la méthode la plus rapide, la plus simple et la plus fiable pour commencer.

{% embed url="<https://youtu.be/q7ljcr9rAWE>" %}

## ✔️ Préparation

<details>

<summary><a href="https://open.docker.com/extensions/marketplace?extensionId=edgegap/docker-extension">Installer l'extension Edgegap Quickstart Docker</a></summary>

* Installer depuis Docker Desktop / Extensions / Parcourir ou [en utilisant le lien](https://open.docker.com/extensions/marketplace?extensionId=edgegap/docker-extension).

<figure><img src="https://3008966946-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2FraFWUCJWPZYvBMLieBUZ%2Fimage.png?alt=media&#x26;token=186886ac-accb-421d-b560-3ccefa7f29cb" alt=""><figcaption></figcaption></figure>

</details>

{% hint style="info" %}
**Confiant dans vos builds de serveur ?** Passer à [#customize-server-image](#customize-server-image "mention") et [advanced-features](https://docs.edgegap.com/learn/advanced-features "mention").
{% endhint %}

## ⚙️ 1. Configurer le projet <a href="#id-1-configure-project" id="id-1-configure-project"></a>

{% hint style="info" %}
Cette méthode ne nécessite pas de télécharger le code source d'Unreal Engine, ni de le compiler depuis les sources !
{% endhint %}

☑️ Commencez par **vérifier votre version d'Unreal Engine** - pré-rempli avec la valeur provenant de vos fichiers de projet.

☑️ **Saisir le nom d'utilisateur GitHub et** [**PAT**](#user-content-fn-1)[^1] depuis [#preparation](#preparation "mention"), pour télécharger des dépendances depuis GitHub.

## 🔧 2. Compiler le serveur de jeu <a href="#id-2-build-game-server" id="id-2-build-game-server"></a>

Nous allons maintenant compiler et cuisiner votre projet, et le empaqueter dans une image docker facilement réutilisable.

☑️ Vous pouvez configurer les options suivantes (ou garder les valeurs par défaut) :

* **Nom de l'image** est un identifiant unique de votre choix, étiquetant votre build de serveur avant l'expédition.
  * Habituellement, cela inclura le nom de votre jeu - par exemple « my-game-server ».
* **Tag de l'image** est un identifiant pointant vers une version spécifique de votre image.
  * Le terme « artefact de build » est parfois utilisé pour désigner une version spécifique de votre image.
  * Les horodatages sont une excellente option pour le marquage, par ex. `2024.01.30-16.23.00-UTC`  (par défaut).

☑️ **Construire le projet** une fois que vous êtes satisfait de votre configuration. Compléter cette étape ajoutera une nouvelle image contenant votre exécutable serveur linux dans votre client Docker local.

✅ Vous pouvez maintenant passer à l'étape suivante.

## 🧪 3. Tester le serveur localement <a href="#id-3-test-server-locally" id="id-3-test-server-locally"></a>

☑️ **Sélectionnez le tag d'image que vous souhaitez exécuter localement** (les images distantes seront téléchargées). Optionnellement, davantage [arguments docker run](https://docs.docker.com/reference/cli/docker/image/build/#options) peuvent être fournis pour personnaliser votre test local :

* `-p 7777:7777/udp` - il s'agit du [mappage de ports](https://docs.edgegap.com/learn/orchestration/application-and-versions#port-mapping),
* `-e ARBITRIUM_PORT_GAMEPORT_INTERNAL=7777`  est une [variable d'environnement](#environment-variables) simulant un véritable déploiement Edgegap, indiquant à votre serveur de jeu le port interne sur lequel écouter les connexions des joueurs.

☑️ Une fois que vous êtes satisfait de votre configuration cliquez sur **Démarrer le serveur local**. L'achèvement de cette étape entraînera le **démarrage d'un nouveau conteneur** sur votre machine de développement.

☑️ Il est maintenant temps de connecter votre client de jeu de l'éditeur Unreal Engine (PIE) à votre conteneur serveur local. Ouvrez la console Unreal PIE avec `~`  (tilde) et connectez-vous avec `open <ip>:<port>`:

* `ip`  = `localhost`  ou `127.0.0.1`  (équivalent dans la plupart des cas),
* `port`  = valeur de port externe randomisée du conteneur dans l'interface Docker.

✅ Vous pouvez maintenant passer à l'étape suivante.

<details>

<summary>Dépannage et FAQ</summary>

Impossible de connecter des clients au serveur - `La requête a expiré.` , `请求超时` , `ConnectionFailed` , ou `La vérification du port a échoué`

* Tout d'abord, assurez-vous que le conteneur est en marche et qu'il n'y a pas d'erreurs d'exécution dans vos logs.
* Veuillez vérifier que les valeurs de ports dans la `commande docker run` correspondent.
* Veuillez vous assurer que votre client de jeu se connecte au **port externe** indiqué sur la page de détails de votre conteneur, cette valeur sera toujours randomisée pour des raisons de sécurité.
* Veuillez vous assurer d'avoir renommé votre fichier cible et configuré les builds du jeu comme décrit à l'étape [#id-1-configure-project](#id-1-configure-project "mention").

***

Mon conteneur est en marche mais je ne peux pas me connecter pendant plusieurs minutes après.

* Une fois qu'un conteneur est lancé, l'initialisation de votre moteur de jeu commence. Ce processus peut prendre de quelques secondes à plusieurs minutes, et le serveur n'accepte pas les connexions de joueurs pendant cette période.
* Envisagez d'optimiser l'initialisation de votre serveur pour réduire cette durée.
* Les clients de jeu doivent réessayer la connexion par intervalles d'une seconde pendant un temps limité (selon la durée d'initialisation), après quoi ils devraient revenir au matchmaking.
* Envisagez d'ajouter une scène de chargement afin que le serveur puisse effectuer l'initialisation (et le travel dans le cas d'Unreal Engine) en même temps que les clients, tout en synchronisant l'état des deux.

***

`Attention : Impossible de créer une socket pour l'adresse de liaison`

* Veuillez installer le plugin Steam Subsystem d'Epic via la boutique d'assets Fab.
* Lors de l'utilisation de Edgegap Integration Kit (EGIK) avec la version source de SteamCore téléchargée depuis GitHub, le plugin Steam Subsystem d'Epic n'est pas inclus en raison des politiques de distribution des plugins d'Epic Games.

***

Je me suis connecté mais mon écran est complètement noir.

* Vérifiez que vous avez la bonne **Carte par défaut du jeu** définie sous **Édition / Paramètres du projet / Cartes & Modes**.

</details>

## ☁️ 4. Publier sur Edgegap <a href="#id-4-publish-to-edgegap" id="id-4-publish-to-edgegap"></a>

☑️ **Choisissez un nom d'application** pour étiqueter et regrouper des images similaires sur Edgegap.

☑️ **Sélectionnez le tag d'image que vous souhaitez publier** et **Télécharger l'image**. L'achèvement de cette étape entraînera le téléchargement de votre image serveur vers le registre Edgegap et la création d'une nouvelle [version d'application](https://docs.edgegap.com/learn/orchestration/application-and-versions) dans votre navigateur web. **Assurez-vous de créer votre** [**mappage de ports**](https://docs.edgegap.com/learn/orchestration/application-and-versions#port-mapping) **lorsqu'on vous le demande,** avec les valeurs par défau&#x74;**.**

{% hint style="success" %}
Trouvé un bug et besoin de reconstruire/pubier à nouveau ? Utilisez **Reconstruire depuis la source** pour [#id-2.-build-game-server](#id-2.-build-game-server "mention") et [#id-4.-publish-to-edgegap](#id-4.-publish-to-edgegap "mention") **avec les valeurs d'entrée actuelles de l'extension rapidement.**
{% endhint %}

✅ Vous pouvez maintenant passer à l'étape suivante.

## 🚀 5. Déployer dans le cloud <a href="#id-5-deploy-to-cloud" id="id-5-deploy-to-cloud"></a>

☑️ Nous allons maintenant effectuer le test final et **connecter votre éditeur Unreal Engine à votre déploiement cloud**. Récupérez votre **Hôte du déploiement** à la place de l'IP du serveur et le **port externe**du déploiement, ouvrez la console Unreal dans le client de jeu (tilde `~`) et tapez `open {host}:{port}` .

<details>

<summary>Dépannage et FAQ</summary>

Impossible de connecter des clients au serveur - `La requête a expiré.` , `请求超时` , `ConnectionFailed` , ou `La vérification du port a échoué`

* Tout d'abord, assurez-vous que le déploiement est Prêt et qu'il n'y a pas d'exceptions ou d'erreurs d'exécution dans le journal de votre déploiement. Si votre déploiement s'est arrêté, inspectez les logs dans notre [Tableau de bord](https://app.edgegap.com/deployment-management/deployments/list).
* Veuillez vérifier que le paramètre de port dans les réglages netcode de votre build serveur correspond au port interne dans votre [version d'app](https://app.edgegap.com/application-management/applications/list). Pour les builds utilisant un plugin, le port est défini automatiquement pour vous. Vous pouvez changer le mappage de port en modifiant le [version d'app](https://app.edgegap.com/application-management/applications/list) sans reconstruire. Trouvez votre protocole dans votre intégration netcode.
* Veuillez vous assurer que votre client de jeu se connecte au **port externe** affiché sur la page de détails de votre déploiement, cette valeur sera toujours randomisée pour des raisons de sécurité.
* Veuillez vous assurer d'avoir renommé votre fichier cible et configuré les builds du jeu comme décrit à l'étape [#id-1.-configure-project](#id-1.-configure-project "mention").
* Êtes-vous situé en Chine et utilisez-vous [Smart Fleets](https://docs.edgegap.com/docs/deployment/session/fleet-manager/fleet)? Votre connexion peut être bloquée par la Grande Muraille (Great Firewall). Envisagez d'ajouter un serveur situé en Chine à votre flotte, ou d'utiliser un VPN pour vous connecter.

***

Mon déploiement est prêt mais je ne peux pas me connecter pendant plusieurs minutes après.

* Une fois qu'un déploiement est Prêt, l'initialisation de votre moteur de jeu commence. Ce processus peut prendre de quelques secondes à plusieurs minutes, et le serveur n'accepte pas les connexions de joueurs pendant cette période.
* Envisagez d'optimiser l'initialisation de votre serveur pour réduire cette durée.
* Les clients de jeu doivent réessayer la connexion par intervalles d'une seconde pendant un temps limité (selon la durée d'initialisation), après quoi ils devraient revenir au matchmaking.
* Envisagez d'ajouter une scène de chargement afin que le serveur puisse effectuer l'initialisation (et le travel dans le cas d'Unreal Engine) en même temps que les clients, tout en synchronisant l'état des deux.

***

`Attention : Impossible de créer une socket pour l'adresse de liaison`

* Veuillez installer le plugin Steam Subsystem d'Epic via la boutique d'assets Fab.
* Lors de l'utilisation de Edgegap Integration Kit (EGIK) avec la version source de SteamCore Integration Kit (SIK) téléchargée depuis GitHub, le plugin Steam Subsystem d'Epic n'est pas inclus en raison des politiques de distribution des plugins d'Epic Games.

***

Je me suis connecté mais mon écran est complètement noir.

* Vérifiez que vous avez la bonne **Carte par défaut du jeu** définie sous **Édition / Paramètres du projet / Cartes & Modes**.
* Vérifiez que la [vérification de compatibilité de la version d'Unreal Engine a été désactivée](#id-2.-configure-game-server-builds) dans `DefaultEngine.ini`.

***

Mon déploiement s'est arrêté/redémarré et je ne peux plus accéder à ses logs.

* Dans le cas où le processus serveur plante à cause d'une exception, notre système tentera de redémarrer automatiquement le serveur. Envisagez de tester votre serveur localement pour découvrir la cause racine.
* Nous ne conservons les logs que pendant la durée du déploiement, si vous souhaitez inspecter les logs après l'arrêt du déploiement, veuillez [intégrer un stockage de logs tiers](https://docs.edgegap.com/docs/deployment/endpoint-storage).
* Voir [#id-5.-deployment-stopped](https://docs.edgegap.com/learn/orchestration/deployments#id-5.-deployment-stopped "mention") pour découvrir toutes les causes d'arrêt de votre déploiement.

***

Mon déploiement s'est arrêté automatiquement après X minutes.

* Les déploiements du niveau gratuit ont une limite de 60 minutes, veuillez envisager de mettre à niveau votre compte.
* Tous les déploiements seront terminés après 24 heures d'exécution conformément à notre politique de nettoyage des serveurs, pour la maintenance de l'infrastructure, et pour éviter l'accumulation de coûts inattendus lorsque le déploiement n'a pas été correctement arrêté. Pour les serveurs fonctionnant longtemps, envisagez d'utiliser [flottes-privees](https://docs.edgegap.com/learn/orchestration/flottes-privees "mention") avec [persistance](https://docs.edgegap.com/learn/orchestration/persistance "mention").
* Voir [#id-5.-deployment-stopped](https://docs.edgegap.com/learn/orchestration/deployments#id-5.-deployment-stopped "mention") pour découvrir toutes les causes d'arrêt de votre déploiement.

***

Que se passe-t-il si un joueur quitte mon déploiement ?

* Par défaut, les serveurs n'acceptent pas le rejet des connexions des joueurs. L'authentification des joueurs relève de vos développeurs, car de nombreuses méthodes et fournisseurs d'authentification peuvent être utilisés.
* Les clients de jeu peuvent stocker localement les informations de connexion pour tenter une reconnexion en cas de crash inattendu du client.
* Pour permettre aux joueurs de rejoindre des parties en cours, envisagez d'utiliser [#backfill](https://docs.edgegap.com/learn/matchmaking/matchmaker-in-depth#backfill "mention") ou [Sessions](https://docs.edgegap.com/docs/deployment/session).

***

Mon serveur affiche une utilisation CPU à 100% après être devenu prêt.

* Cela peut ne pas être un problème, car les moteurs de jeu ont tendance à effectuer des opérations lourdes en CPU pendant les initialisations serveur. Si l'utilisation du CPU ne diminue pas après 2-3 minutes depuis le démarrage du déploiement, vous devrez peut-être optimiser votre serveur ou augmenter les ressources de la version d'app.
* Réduire le tick rate peut aider à contrôler l'utilisation du CPU en traitant moins de messages.
* Vous êtes limité à 1,5 vCPU et 3 Go de mémoire (RAM) dans le niveau gratuit.
* Vous pouvez augmenter les ressources allouées lors de la création d'une nouvelle version d'app. Vous pouvez dupliquer votre version d'app dans notre Tableau de bord et ajuster ces valeurs selon vos besoins, sans reconstruire votre serveur ou image.

***

Mon déploiement redémarre de manière répétée et affiche l'erreur `OOM kill`

* Ceci est causé par le dépassement de la quantité de mémoire allouée. Envisagez d'optimiser l'utilisation de la mémoire avec du pooling d'objets, de la compression, ou en supprimant les objets inutiles de votre scène.
* Vous êtes limité à 1,5 vCPU et 3 Go de mémoire (RAM) dans le niveau gratuit.
* Vous pouvez augmenter les ressources allouées lors de la création d'une nouvelle version d'app. Vous pouvez dupliquer votre version d'app dans notre Tableau de bord et ajuster ces valeurs selon vos besoins, sans reconstruire votre serveur ou image.

***

Parfois, l'utilisation de mémoire (RAM) de mon serveur monte brutalement à une valeur élevée, est-ce un problème ?

* Tant que vous restez dans la quantité de mémoire allouée à la version d'app, ce n'est pas un problème.
* Le dépassement de la quantité de mémoire allouée à la version d'app provoquera `OOM kill` (voir ci-dessus).

***

Les performances de mon serveur seront-elles affectées par d'autres serveurs exécutés sur la même machine ?

* Non, notre plateforme garantit que les ressources allouées ne seront pas utilisées par d'autres studios ou d'autres serveurs sur l'infrastructure partagée. Avec Edgegap, il n'y a pas de voisins bruyants.

</details>

## 👉 Prochaines étapes

### Arrêter les déploiements

En savoir plus sur les différentes méthodes pour [arrêter les déploiements](https://docs.edgegap.com/learn/orchestration/deployments#id-5.-deployment-stopped) une fois le match terminé et les joueurs partis.

Si vous avez suivi ce guide et construit avec notre extension Docker, vous pouvez simplement appeler la méthode `FGenericPlatformMisc::RequestExit` . Nous avons ajouté un script gérant votre processus serveur dans l'image empaquetée, qui effectuera automatiquement un arrêt gracieux du déploiement.

Pour personnaliser la gestion du cycle de vie du serveur, modifiez notre [exemple `StartServer.sh`](https://github.com/edgegap/edgegap-unreal-buildutils/blob/main/StartServer.sh)  script.

{% hint style="info" %}
Vous préférez gérer le cycle de vie depuis Unreal ? Voir [#integration-kit](https://docs.edgegap.com/developer-tools#integration-kit "mention") pour le blueprint d'API d'arrêt autonome.
{% endhint %}

{% hint style="warning" %}
Connectez votre [endpoint-storage](https://docs.edgegap.com/docs/endpoint-storage "mention") pour obtenir les logs de votre déploiement, sinon ils seront supprimés !
{% endhint %}

### Variables injectées

Lisez des informations utiles comme l'ID du déploiement, l'adresse IP du serveur, l'emplacement du serveur, et plus encore ; en accédant aux variables d'environnement injectées. Chaque déploiement inclut automatiquement :

* [Variables de déploiement](https://docs.edgegap.com/learn/orchestration/deployments#injected-environment-variables) - automatiquement fournies par Edgegap,
* [Variables de matchmaking](https://docs.edgegap.com/learn/matchmaking/matchmaker-in-depth#injected-environment-variables) - automatiquement fournies par Edgegap lors de l'utilisation de [Matchmaker](https://docs.edgegap.com/broken-reference),
* [Variables de la version d'app](https://docs.edgegap.com/learn/orchestration/application-and-versions#injected-variables) - paires clé-valeur personnalisées configurables par vous.

**Vérifier si l'instance actuelle est un client de jeu ou un serveur** en vérifiant si la variable Edgegap est définie :

```cpp
if (
  FPlatformMisc::GetEnvironmentVariable(TEXT("ARBITRIUM_REQUEST_ID")).empty()
)
{
  // code client
} else {
  // code serveur
}
```

### Profilage des serveurs

Pour comprendre et optimiser les problèmes de performance des serveurs sur Edgegap, explorez [#container-logs](https://docs.edgegap.com/learn/orchestration/deployments#container-logs "mention"), [#container-metrics](https://docs.edgegap.com/learn/orchestration/deployments#container-metrics "mention"), et plus [#dashboard-monitoring](https://docs.edgegap.com/learn/orchestration/deployments#dashboard-monitoring "mention") d'outils à votre disposition.

Vous pouvez également utiliser les outils de profilage existants d'Unreal Engine avec Edgegap :

* [Configurer le tracing dans votre serveur Unreal Engine](https://dev.epicgames.com/documentation/en-us/unreal-engine/developer-guide-to-tracing-in-unreal-engine) (événements intégrés et personnalisés) :
  * enregistrer la trace sur le disque du serveur avec `-tracefile`, téléverser vers un stockage tiers et analyser hors ligne,
  * ou diffuser les données de trace avec [#port-mapping](https://docs.edgegap.com/learn/orchestration/deployments#port-mapping "mention") pour le port interne `1981` sur le protocole UDP.
* Analyser [Aperçus mémoire](https://dev.epicgames.com/documentation/en-us/unreal-engine/memory-insights-in-unreal-engine) et [Aperçus réseau](https://dev.epicgames.com/documentation/en-us/unreal-engine/networking-insights-in-unreal-engine) et [#optimize-server-builds](#optimize-server-builds "mention").

### Matchmaking

Démarrer vos déploiements manuellement, coller l'URL et les ports ne suffira pas pour un jeu en ligne.

{% hint style="success" %}
[**En savoir plus sur le matchmaking**](https://docs.edgegap.com/learn/matchmaking) **pour déployer automatiquement, au bon moment**, lorsque les joueurs se connectent.
{% endhint %}

### Optimiser les builds serveur

**Configurer le découpage des assets pour isoler les assets réservés au client des assets serveur.**

* Explorer [Techniques et recommandations de découpage d'assets](https://dev.epicgames.com/documentation/en-us/unreal-engine/preparing-assets-for-chunking-in-unreal-engine) par Epic.

**Exclure les assets et plugins qui sont uniquement client et non nécessaires pour l'exécution du serveur.**

* En savoir plus sur [l'exclusion d'assets et de plugins au moment de la compilation](https://dev.epicgames.com/community/learning/tutorials/Kp1k/unreal-engine-build-time-asset-and-plugin-exclusion).

**Révisez votre stratégie de cuisson du contenu.**

* Envisagez [Cooking on the Fly (COTF)](https://dev.epicgames.com/documentation/en-us/unreal-engine/build-operations-cooking-packaging-deploying-and-running-projects-in-unreal-engine#cookonthefly) pour retarder la cuisson des assets clients et accélérer les builds serveur.

**Implémentez le Level Streaming pour réduire la charge mémoire à l'exécution.**

* Si votre conception maintient principalement les joueurs ensemble dans la même zone de la carte, [le level streaming peut réduire l'utilisation mémoire de votre serveur](https://dev.epicgames.com/documentation/en-us/unreal-engine/level-streaming-in-unreal-engine) de plus de 60 %, et améliorer les performances du client !

**N'incluez que ce dont votre serveur a absolument besoin pour fonctionner.**

* Copier des fichiers inutilisés dans vos images entraîne un gonflement de l'image, des uploads plus longs, des vitesses de cache plus lentes et un démarrage global du serveur plus lent. [Consultez les suggestions d'optimisation des images Docker](https://docs.docker.com/build-cloud/optimization/#dockerignore-files).

<details>

<summary>Exemple <code>.dockerignore</code> fichier pour supprimer les fichiers supplémentaires.</summary>

```docker
# Fichiers objets compilés
*.slo
*.lo
*.o
*.obj

# En-têtes précompilés
*.gch
*.pch

# Bibliothèques dynamiques compilées
*.so
*.dylib
*.dll

# Fichiers de module Fortran
*.mod

# Bibliothèques statiques compilées
*.lai
*.la
*.a
*.lib

# Exécutables
*.exe
*.out
*.app
*.ipa

# Ces fichiers de projet peuvent être générés par le moteur
*.xcodeproj
*.xcworkspace
*.sln
*.suo
*.opensdf
*.sdf
*.VC.db
*.VC.opendb

# Assets précompilés
**/SourceArt/**/*.png
**/SourceArt/**/*.tga

# Builds
**/Build/*

# Mettre en liste blanche les fichiers PakBlacklist-<BuildConfiguration>.txt
!**/Build/*/
**/Build/*/**
!**/Build/*/PakBlacklist*.txt

# Ne pas ignorer les fichiers d'icône dans Build
!**/Build/**/*.ico

# Fichiers de configuration générés par l'éditeur
**/Saved/*
**/Intermediate/*
**/DerivedDataCache/*
**/Binaries/*
**/Build/*
**/Releases/*
**/Packaged/*
```

</details>

**Envisagez d'utiliser** [**les builds Docker multi-étapes (lien)**](https://docs.docker.com/build/building/multi-stage/)**.**

* Séparez les grandes dépendances serveur dans une image séparée à réutiliser dans des builds multi-étapes. Docker mettra en cache chaque couche et réutilisera simplement la version précédente et évitera de téléverser cette partie sauf instruction contraire, vous faisant ainsi économiser de la bande passante et du temps d'attente pour la fin du téléversement.
* Si vous ne comprenez pas pourquoi l'une de vos commandes Dockerfile renvoie une erreur, essayez de déboguer localement. Créez une nouvelle étape juste avant que le problème ne se produise (ajoutez une seconde `FROM` commande), utilisez `--target` pour demander au processus de build de s'arrêter à l'étape problématique, puis `docker exec -it {container} /bin/bash` pour entrer dans un terminal interactif à l'intérieur de votre conteneur. Ensuite, vous pouvez utiliser des commandes shell dans votre image de base pour enquêter davantage (par ex. `top` sur ubuntu).

### Personnaliser l'image serveur

Nous prenons également en charge l'ajout de votre propre Dockerfile pour les utilisateurs qui ont besoin de plus de contrôle sur leurs images en raison de l'optimisation de la taille de build, de dépendances superflues, ou nécessitant un processus de démarrage plus complexe. Nous allons maintenant partager quelques conseils et bonnes pratiques "faites-le vous-même".

[^1]: Token d'accès personnel


# Plus de méthodes de build

Ces approches sont généralement plus lentes et nécessitent une compréhension approfondie d'Unreal Engine.

{% hint style="success" %}
Voir [](https://docs.edgegap.com/unreal-engine "mention") pour vos premiers pas avec l'hébergement de serveurs de jeu Unreal Engine sur Edgegap.
{% endhint %}

Explorez des méthodes de build alternatives adaptées aux utilisateurs plus avancés d'Unreal Engine et d'Edgegap :

1. [#build-from-containers](#build-from-containers "mention") est une méthode rapide et automatisée adaptée à l'intégration continue.
2. [#build-from-plugin](#build-from-plugin "mention") est une méthode de build héritée nécessitant la construction d'Unreal Engine à partir des sources.

## ⚡ Construire avec des scripts

Construire avec des scripts est une méthode rapide, entièrement automatisée et facile, adaptée à l'intégration continue.

### Préparation <a href="#scripts-before-starting" id="scripts-before-starting"></a>

### 1. Configurer le projet <a href="#scripts-configure-game-builds" id="scripts-configure-game-builds"></a>

### 2. Construire et publier <a href="#scripts-build-and-upload-to-edgegap" id="scripts-build-and-upload-to-edgegap"></a>

☑️ **Vérifiez que Docker est installé et en cours d'exécution.**

{% embed url="<https://github.com/edgegap/edgegap-unreal-buildutils>" %}

☑️ **Téléchargez nos Edgegap Build Utils** archive incluant :

* scripts de build spécifiques à la plateforme :
  * `BuildAndUpload.ps1`  pour Windows,
  * `BuildAndUpload.sh`  pour macOS et Linux,
* `Dockerfile`  - recette pour construire vos images Docker,
* `dockerignore`  - liste de fichiers non critiques à supprimer pour accélérer les builds,
* `StartServer.sh`  - script utilitaire gérant le cycle de vie d'Unreal Engine à l'exécution.

☑️ **Déplacez le `edgegap-unreal-buildutils` dossier vers le répertoire racine de votre projet.**

☑️ **Éditez le `BuildAndUpload`  script pour votre plateforme** pour configurer :

* identifiants GitHub utilisés pour récupérer des images Unreal Engine préconstruites pour les serveurs Linux,
* détails du projet - version du moteur, configuration du serveur, nom du fichier .uproject,
* [Registre Edgegap](https://app.edgegap.com/registry-management/repositories/list) identifiants utilisés pour téléverser vos builds terminés.

☑️ **Exécutez le script modifié** pour démarrer le processus de build et de téléversement. L'achèvement de cette étape ajoutera une nouvelle **image dans votre** [page du tableau de bord Edgegap Container Registry dans votre dépôt](https://app.edgegap.com/registry-management/repositories/list).

☑️ Vous serez automatiquement redirigé vers **créer un nouveau** [#app-versions](https://docs.edgegap.com/learn/orchestration/application-and-versions#app-versions "mention") dans [tableau de bord](https://app.edgegap.com/application-management/applications/list)**.**

✅ Vous pouvez maintenant passer à l'étape suivante, ou aller directement à [#test-your-server-locally](#test-your-server-locally "mention").

## ⚡ Construire depuis le plugin <a href="#build-from-plugin" id="build-from-plugin"></a>

Notre plugin hérité inclut des utilitaires avancés et nécessite la construction d'Unreal Engine à partir des sources.

### Préparation <a href="#plugin-before-starting" id="plugin-before-starting"></a>

<details>

<summary>Configurez votre environnement de développement</summary>

* [Téléchargez le code source d'Unreal Engine](https://dev.epicgames.com/documentation/en-us/unreal-engine/downloading-unreal-engine-source-code#downloadingthesourcecode).
* [Installez Visual Studio](https://dev.epicgames.com/documentation/en-us/unreal-engine/setting-up-visual-studio-development-environment-for-cplusplus-projects-in-unreal-engine).

</details>

<details>

<summary>Installez un plugin officiel Edgegap pour Unreal Engine</summary>

Choisissez l'un des plugins officiels :

* télécharger [#integration-kit](https://docs.edgegap.com/developer-tools#integration-kit "mention"),
* ou télécharger [#legacy-plugin](https://docs.edgegap.com/developer-tools#legacy-plugin "mention").

</details>

### 1. Configurer le projet <a href="#scripts-configure-game-builds" id="scripts-configure-game-builds"></a>

☑️ [Construisez votre version d'Unreal Engine à partir des sources](https://dev.epicgames.com/documentation/en-us/unreal-engine/building-unreal-engine-from-source) sur votre machine de développement,

* installez [branche de version spécifique (par ex. ](https://github.com/EpicGames/UnrealEngine/tree/5.5)[`5.5`](https://github.com/EpicGames/UnrealEngine/tree/5.5)[)](https://github.com/EpicGames/UnrealEngine/tree/5.5) pour construire sur une base stable,
* **utilisez un disque SSD (Solid State Drive)** pour accélérer les builds (de \~12+ heures à \~2+ heures),
* cela n'est requis que la première fois et à chaque mise à niveau de votre version d'Unreal Engine.

{% hint style="warning" %}
**Téléchargez la branche avec un client git !** L'utilisation de l'interface GitHub téléchargera toujours la branche instable `de version` .
{% endhint %}

☑️ [Installez la chaîne d'outils de cross-compilation Unreal](https://dev.epicgames.com/documentation/en-us/unreal-engine/linux-development-requirements-for-unreal-engine) pour construire des serveurs de jeu pour Linux.

☑️ **Redémarrez votre machine de développement**, sinon vous rencontrerez des erreurs plus tard !

### 2. Construire et publier <a href="#plugin-build-and-upload-to-edgegap" id="plugin-build-and-upload-to-edgegap"></a>

☑️ **Vérifiez que Docker est installé et en cours d'exécution.**

☑️ [Reconstruisez notre plugin](https://dev.epicgames.com/community/learning/tutorials/qz93/unreal-engine-building-plugins) pour votre version personnalisée d'Unreal Engine construite à partir des sources.

☑️ **Copiez le plugin compilé** dans votre `Plugins` dossier **à la racine de votre projet Unreal** (pas dans le moteur).

☑️ **Lancez votre nouvel Unreal Engine** depuis Visual Studio et **ouvrez l'élément de la barre d'outils Édition / Plugins**.

☑️ **Activez notre plugin** dans la section **INSTALLÉ / Autre**.

☑️ **Configurez notre plugin** en ouvrant l'élément de la barre d'outils **Édition / Paramètres du projet / Edgegap**:

{% hint style="warning" %}
Appuyez toujours sur Entrée après avoir modifié les valeurs saisies pour **vous assurer qu'elles sont correctement enregistrées**.
{% endhint %}

* **Jeton API** est nécessaire pour téléverser votre serveur sur Edgegap, obtenez-en un en cliquant sur Obtenir le jeton.
* **Nom de l'application** sur Edgegap peut correspondre au nom de votre projet ou être personnalisé, assurez-vous d'utiliser uniquement des lettres minuscules, des chiffres ou les caractères tiret `-` et underscore `_`.
* **Chemin de l'image** fournit éventuellement une icône personnalisée pour votre serveur de jeu sur Edgegap, passez pour l'instant.
* **Nom de la version** est utile pour suivre la compatibilité client/serveur et revenir en arrière en cas de problème.
  * Les horodatages sont une excellente option pour les noms de version d'application, par ex. `2024.01.30-16.50.20-UTC` .
  * Plusieurs versions d'application peuvent pointer vers le même tag d'image, tel que `v1.1.0` et `dev` .
  * En savoir plus sur [application-and-versions](https://docs.edgegap.com/learn/orchestration/application-and-versions "mention") plus tard.

{% hint style="warning" %}
**Ne réutilisez pas `latest` version** pour empêcher notre système de déployer une image obsolète (mise en cache).
{% endhint %}

☑️ Cliquez sur **Créer l'application.** L'achèvement de cette étape entraînera l'apparition d'une **nouvelle application apparaissant** dans [Tableau de bord Edgegap](https://app.edgegap.com/application-management/applications/list).

☑️ Ignorez les paramètres de registre de conteneurs personnalisés pour l'instant, vous pourrez utiliser un registre tiers plus tard si vous le souhaitez.

☑️ Une fois satisfait de votre configuration, appuyez sur **Construire et pousser**, attendez que le processus se termine et vérifiez qu'il n'y a pas de nouvelles erreurs dans votre console Unreal. L'achèvement de cette étape entraînera la création d'un **nouveau dossier apparaissant à la racine de votre projet** - `Saved/LinuxServer`. De plus, une **nouvelle image apparaît maintenant dans votre** [page du tableau de bord Edgegap Container Registry sous votre dépôt](https://app.edgegap.com/registry-management/repositories/list), et un nouveau [#app-versions](https://docs.edgegap.com/learn/orchestration/application-and-versions#app-versions "mention") **apparaît dans votre** [tableau de bord sous votre application](https://app.edgegap.com/application-management/applications/list)**.**

☑️ Dans la nouvelle version de votre application, définissez la variable d'environnement `TARGET_FILE_NAME`  pour correspondre à votre `DefaultServerTarget`  valeur de l'étape [#id-2.-configure-game-server-builds-1](#id-2.-configure-game-server-builds-1 "mention").

✅ Vous pouvez maintenant passer à l'étape suivante.

## 👉 Prochaines étapes

Continuez vers [#id-5.-deploy-to-cloud](https://docs.edgegap.com/unreal-engine/..#id-5.-deploy-to-cloud "mention") avec notre [Déploiement via le tableau de bord](https://app.edgegap.com/deployment-management/deployments/list) et découvrez-en davantage sur l'arrêt de vos déploiements, les variables injectées et la paramétrisation, ainsi que la découvrabilité des serveurs.


# Outils pour développeurs

Nous construisons ces outils pour vous avec un mantra simple : « les clés des équipes performantes sont l'itération rapide et les tests fréquents ». Si vous voyez une opportunité d'amélioration, veuillez nous le faire savoir dans notre [Discord Communautaire](https://discord.gg/NgCnkHbsGp). Nous espérons que vous apprécierez une expérience fluide. :rocket:

{% hint style="info" %}
Voir notre [Exemples Unreal Engine](https://docs.edgegap.com/docs/sample-projects/unreal-engine) à utiliser comme point de départ de projet ou source d'inspiration.
{% endhint %}

## 🐋 Extension Docker

Vérifiez les paramètres de votre projet, configurez des serveurs de build pour Linux, testez localement ou déployez dans le cloud, le tout depuis l'interface graphique conviviale de Docker Desktop :

* [installer depuis le Marketplace des extensions Docker](https://open.docker.com/extensions/marketplace?extensionId=edgegap/docker-extension) (gratuit).

{% hint style="success" %}
**Suivez notre guide facile pour** [](https://docs.edgegap.com/unreal-engine "mention") **développeurs (comprend un tutoriel vidéo).**
{% endhint %}

## ⚡ Kit d'intégration

Ce plugin prend en charge Unreal Engine 4.27, 5.0 et toutes les versions mineures suivantes (5.1, 5.2, etc.) :

{% hint style="success" %}
Ce plugin est une solution vérifiée maintenue par un partenaire indépendant - Betide Studio.
{% endhint %}

### ⭐ SDK de matchmaking

Le Kit d'intégration Edgegap étend [#legacy-plugin](#legacy-plugin "mention") avec plus de configurabilité et [matchmaking](https://docs.edgegap.com/learn/matchmaking "mention") d'intégration. [Voir la documentation officielle](https://egik.betide.studio/).

## ⚡ Plugin héritage

Construisez et lancez votre serveur de jeu dédié dans le cloud directement depuis votre éditeur Unreal !

* [Dedicated Servers for Unreal plugin - solution clé en main, code source et notes de version complètes.](https://github.com/edgegap/edgegap-unreal-plugin)

Ce plugin prend en charge Unreal Engine 4.27, 5.0 et toutes les versions mineures suivantes (5.1, 5.2, etc.).

{% hint style="success" %}
Ce plugin est fourni 100 % gratuitement, sous les conditions générales du niveau gratuit.
{% endhint %}


# Unity

Apprenez en pratiquant et déployez votre premier serveur dédié sur Edgegap. À la fin de ce guide, vous aurez déployé un serveur dédié avec Edgegap sans frais.

{% embed url="<https://youtu.be/4FR04V4YEUk>" %}

## ✔️ Préparation

<details>

<summary><a href="https://github.com/edgegap/edgegap-unity-plugin">Installer le plugin Quickstart des serveurs dédiés Unity d'Edgegap</a></summary>

</details>

{% hint style="info" %}
**Confiant dans vos builds de serveur ?** Passer à [#customize-server-image](#customize-server-image "mention") ou [advanced-features](https://docs.edgegap.com/learn/advanced-features "mention") pour en savoir plus.
{% endhint %}

## ⚙️ 1. Connecter le compte

☑️ Connectez-vous et vérifiez qu'il n'y a pas de nouvelles erreurs dans votre console Unity liées au plugin d'Edgegap.

✅ Vous pouvez maintenant passer à l'étape suivante.

<details>

<summary>Dépannage et FAQ</summary>

`!Succès : 400 BAD REQUEST - POST | https://api.edgegap.com/v1/wizard/init-quick-start - {"message": "Le navigateur (ou le proxy) a envoyé une requête que ce serveur n'a pas pu comprendre."}`

* Si vous l’avez installé en copiant le fichier ZIP ou utilisé un projet d'exemple avec une copie du plugin installée ainsi, vous devrez installer manuellement les dépendances du package y compris la bibliothèque Newtonsoft JSON, voir [le dépôt officiel du plugin](https://github.com/edgegap/edgegap-unity-plugin/tree/main?tab=readme-ov-file#instructions-1).
* Veuillez nous contacter sur [Discord communautaire](https://discord.gg/NgCnkHbsGp) pour obtenir de l'aide si ce n'est pas le cas.

</details>

## 🔧 2. Construire le serveur de jeu

Que vous utilisiez une machine Windows, Mac ou Linux, vous allez **devoir construire votre serveur pour l'exécution Linux**, car la plupart des fournisseurs cloud aujourd'hui (y compris Edgegap) fonctionnent sous Linux. Ne vous inquiétez pas, aucune connaissance Linux n'est requise pour accomplir cela avec notre plugin.

☑️ **Vérifiez que vous avez installé les outils de build Linux Unity requis.**

☑️ Modifier les paramètres de build pour **s'assurer que toutes vos scènes de jeu requises sont incluses**.

{% hint style="info" %}
**Utilisateurs avancés d'Unity** - changer éventuellement [Paramètres de build Unity](https://docs.unity3d.com/Manual/BuildSettings.html). Attention ! Cela peut casser votre build.
{% endhint %}

☑️ Optionnel : ajoutez un script spécifique au netcode pour la vérification des ports et le bootstrap de l'environnement à votre scène serveur initiale depuis le menu Edgegap Server Hosting (clic droit / :heavy\_plus\_sign: dans votre fenêtre Hiérarchie).

<figure><img src="https://3008966946-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2FZ8dV9ERoV3rczrXXUdV9%2Fimage.png?alt=media&#x26;token=f7c44a27-7521-4392-9d11-276c48410ed0" alt="" width="360"><figcaption></figcaption></figure>

{% hint style="info" %}
Une fois que vous avez complété l'étape [#id-6.-deploy-a-server-on-edgegap](#id-6.-deploy-a-server-on-edgegap "mention"), le script de vérification des ports enregistrera un avertissement si votre adresse ou vos ports netcode ne correspondent pas à votre [Mappage de ports de la version de l'application](https://docs.edgegap.com/learn/orchestration/application-and-versions#other-parameters-optional) de configuration.
{% endhint %}

{% hint style="success" %}
Les builds serveur doivent utiliser l'adresse `0.0.0.0`  et le port `7777`  dans votre transport netcode. Si vous personnalisez votre port, veuillez spécifier le même dans votre [#port-mapping](https://docs.edgegap.com/learn/orchestration/application-and-versions#port-mapping "mention") une fois que vous [#id-5.-upload-to-edgegap](#id-5.-upload-to-edgegap "mention").
{% endhint %}

☑️ Une fois satisfait de votre configuration, cliquez sur **Construire le serveur**, attendez la fin du processus et vérifiez qu'il n'y a pas de nouvelles erreurs dans votre console Unity. L'achèvement de cette étape aboutira à un **nouveau dossier apparaissant à la racine de votre projet** - `Builds/EdgegapServer/ServerBuild` .

✅ Vous pouvez maintenant passer à l'étape suivante.

<details>

<summary>Dépannage et FAQ</summary>

Unity : les seules cibles standalone prises en charge sont Windows x64 et OSX avec OpenXR.

* Ouvrez vos Packages et désactivez OpenXR avant de construire votre serveur.
* Le plugin OpenXR n'est requis que pour les clients et n'est pas compatible avec les builds serveur Linux. En l'excluant de vos builds serveur, vous ne perdez aucune fonctionnalité.

</details>

## 🐋 3. Conteneuriser le serveur

Travailler en équipe de développeurs signifie partager votre code. Quand les choses tournent mal, la dernière chose que vous voulez entendre est “ça fonctionne sur ma machine”. Les serveurs de jeu doivent fonctionner de manière fiable sur n'importe quelle machine, car les serveurs d'un jeu à succès fonctionneront sur des milliers de machines serveurs à travers le monde.

Pour aider à rendre votre serveur fiable, nous utilisons Docker - un logiciel de virtualisation garantissant que toutes les dépendances de votre code serveur jusqu'au niveau du système d'exploitation seront toujours exactement les mêmes, peu importe comment ou où le serveur est lancé.

☑️ Pour l'instant, commencez par cliquer sur le bouton **Valider** pour vous assurer que vous avez complété [#usage-requirements](https://docs.edgegap.com/developer-tools#usage-requirements "mention").

☑️ Vous pouvez configurer les options suivantes (ou conserver les valeurs par défaut) :

* **Chemin de build** est le chemin relatif vers votre artefact de build serveur, gardons la valeur par défaut pour l'instant.

{% hint style="warning" %}
Docker n'accepte que des chemins de build relatifs au dossier racine de votre projet, **gardez les builds à l'intérieur de votre dossier de projet**.
{% endhint %}

* **Nom de l'image** est un identifiant unique de votre choix, étiquetant votre build serveur avant l'envoi.
  * Habituellement, cela inclura le nom de votre jeu - par exemple “mon-serveur-de-jeu”.
* **Tag de l'image** est un identifiant pointant vers une version spécifique de votre image.
  * Le terme “artefact de build” est parfois utilisé pour désigner une version spécifique de votre image.
  * Les horodatages sont une excellente option pour le marquage, par ex., `2024.01.30-16.23.00-UTC` .
* **Chemin vers le Dockerfile** peut être utilisé pour personnaliser la recette de vos images.
  * Nous recommandons de conserver le paramètre par défaut pour l'instant, vous pouvez en lire davantage plus tard dans la section [#customize-server-image](#customize-server-image "mention").
* **Paramètres de build Docker optionnels** peuvent être utilisés pour donner des instructions supplémentaires à Docker sur des nuances plus fines.
  * Nous recommandons de conserver le paramètre par défaut pour l'instant, vous pouvez [lire plus tard dans la documentation Docker](https://docs.docker.com/reference/cli/docker/image/build/#options).

☑️ Une fois satisfait de votre configuration, cliquez sur **Conteneuriser avec Docker**, attendez la fin du processus et vérifiez qu'il n'y a pas de nouvelles erreurs dans votre console Unity. L'achèvement de cette étape aboutira à un **nouvelle image apparaissant sur votre machine locale**. Vous pouvez vérifier cela soit dans Docker Desktop, dans l'onglet Images sous Local (par défaut), soit dans le CLI docker en exécutant `docker images` .

✅ Vous pouvez maintenant passer à l'étape suivante.

<details>

<summary>Dépannage et FAQ</summary>

`/bin/bash : docker : commande introuvable` , ou `n'a pas pu trouver Packages\com.edgegap.unity-servers-plugin\Editor`

* Tout d'abord, assurez-vous d'avoir complété [#usage-requirements](https://docs.edgegap.com/developer-tools#usage-requirements "mention").
* Confirmez que vous avez vérifié votre compte Edgegap, vous devriez avoir reçu un lien de vérification par e-mail.
* Certaines configurations peuvent avoir été réinitialisées après la mise à jour de Docker Desktop. Essayez de naviguer dans Paramètres / Avancé de Docker Desktop et pour “Choisir comment configurer l'installation des outils CLI de Docker :” sélectionnez “Système (nécessite mot de passe)”.

***

`docker build nécessite exactement 1 argument`

* Veuillez vérifier que votre tag d'image ne contient pas de caractères d'espacement (espaces, tabulations). Retaper la valeur du tag d'image garantira que vous n'avez pas accidentellement copié de tels caractères.

***

`(code HTTP 400) inattendu - format de tag invalide`

* Ceci est un [problème connu avec la version 4.33 de Docker sur macOS](https://github.com/docker/for-win/issues/14258), veuillez envisager de revenir à la version 4.32 ou de mettre à niveau vers la 4.35.

***

`ERREUR : échec de la résolution : ubuntu:22.04 : échec pour résoudre les métadonnées source pour http://docker.io/library/ubuntu:22.04 : échec d'autorisation : échec de la récupération du token oauth`

* Êtes-vous situé en Chine ? Votre connexion peut être interrompue par la Grande Muraille (pare-feu). Essayez d'exécuter `docker pull ubuntu:22.04` dans votre ligne de commande manuellement (ouvrez la ligne de commande en appuyant sur Win+R, puis tapez `cmd` et Entrée).

***

`System.IndexOutOfRangeException : L'index était en dehors des limites du tableau.`

* Si vous avez installé notre plugin quickstart Unity en téléchargeant le ZIP, le cache de votre éditeur Unity pourrait être corrompu. Essayez de supprimer votre copie du plugin et d'installer en utilisant l'URL git ou depuis l'Asset Store Unity. Vous ne devriez plus avoir besoin du package Newtonsoft.JSON car il est automatiquement inclus avec les autres sources.

***

La taille de mon image docker est massive (plus de 1 Go) / minuscule (moins de 100 Mo), est-ce normal ?

* Cela peut être acceptable dans certains cas, tant que vous pouvez exécuter le serveur et vous connecter avec succès (voir [#id-4.-test-your-server-locally](#id-4.-test-your-server-locally "mention")). Si ce n'est pas le cas, envisagez de revoir vos options de build, de les réinitialiser aux valeurs par défaut, et d'ajouter progressivement des options pour voir comment elles impactent la taille de votre build. Voir aussi [#optimize-server-build-size](#optimize-server-build-size "mention").

***

Je rencontre un autre problème non mentionné nulle part dans cette documentation.

* D'abord, veuillez essayer [de mettre à jour votre plugin Edgegap](https://github.com/edgegap/edgegap-unity-plugin?tab=readme-ov-file#update-the-plugin-in-unity) car nous avons peut-être livré un correctif. Si cela n'aide pas, veuillez nous contacter sur notre [Discord communautaire](https://discord.gg/NgCnkHbsGp) et nous enquêterons rapidement avec vous.

</details>

## 🧪 4. Tester le serveur localement

☑️ Vous pouvez configurer les options suivantes (ou conserver les valeurs par défaut) :

* **Tag d'image du serveur** de l'étape précédente.
  * Par défaut au dernier tag que vous avez construit avec le plugin.
* **Paramètres optionnels docker run** peuvent être fournis pour exposer plusieurs ports, ou exécuter votre image sur des machines macOS.
  * Vous pouvez publier plusieurs ports pour votre conteneur si nécessaire, ajoutez simplement le paramètre `-p {port interne}/{protocole}` pour chacun, par exemple `-p 8080/tcp -p 7770/udp` pour publier et mapper votre port serveur `8080` vers un port externe aléatoire pour la connexion TCP et le port serveur `7777` vers un port externe aléatoire pour la connexion UDP en même temps.
  * **Trouvez la configuration du port serveur dans votre Transport ou les paramètres spécifiques au netcode.**
  * Si vous utilisez une machine avec une architecture ARM (macOS M1, M2, M3, etc..) vous devriez inclure ce paramètre optionnel dans vos paramètres de build Docker optionnels : `--platform=linux/amd64` .

☑️ Une fois satisfait de votre configuration, cliquez sur **Déployer le conteneur local**, attendez la fin du processus, et vérifiez qu'il n'y a pas de nouvelles erreurs dans votre console Unity. L'achèvement de cette étape aboutira à un **nouveau conteneur démarré** sur votre machine de développement.

{% hint style="info" %}
Pour plus de détails, voir Docker Desktop / Containers, ou la commande CLI Docker `docker ps` .
{% endhint %}

☑️ Il est maintenant temps de **connecter votre client de jeu Unity Editor à votre conteneur docker local** pour vérifier que votre image serveur fonctionne correctement. Trouvez vos paramètres client netcode et saisissez :

* `localhost` ou `127.0.0.1` (équivalent dans la plupart des cas) à la place de l'IP du serveur,
* valeur de port externe aléatoire trouvée dans Docker Desktop / Containers / edgegap-server-test.

✅ Vous pouvez maintenant passer à l'étape suivante.

<details>

<summary>Dépannage et FAQ</summary>

Je ne parviens pas à me connecter au conteneur docker local en utilisant mon client de jeu Unity Editor.

* D'abord, assurez-vous que le statut du conteneur est Up et qu'il n'est pas Restarting ou Exited, ce qui indiquerait une exception d'exécution. Si votre conteneur ne fonctionne pas, inspectez ses logs via l'onglet Containers de Docker Desktop (cliquez sur votre conteneur) ou en utilisant `docker logs {container_id} --timestamps` via le CLI docker.
* Ensuite, veuillez vérifier que le paramètre de port du Network Manager de votre build serveur correspond au port publié dans **Paramètres optionnels docker run**. Si ce n'est pas le cas, essayez de réinitialiser ou de changer manuellement la valeur de ce champ pour qu'elle corresponde au `{container}` port à votre paramètre Network Manager. Trouvez votre protocole dans vos paramètres netcode.
* Enfin, confirmez que les paramètres netcode du client de jeu dans votre Unity Editor utilisent le port publié dans **Paramètres optionnels docker run** (voir la capture d'écran ci-dessus).

***

`(Erreur de segmentation) - vidage du core`

* Si vous utilisez une machine avec une architecture ARM (macOS M1, M2, M3, etc..) vous devriez inclure ce paramètre optionnel dans vos paramètres de build Docker optionnels : `--platform=linux/amd64` . Si ce n'est pas le cas, essayez de réinitialiser la valeur de ce champ.

***

`SceneId de 9120233082191360994 introuvable dans SceneObjects.`

* Cela pourrait signifier que la scène que vous tentez de charger n'a pas été correctement incluse dans le build, un problème connu dans les anciennes versions du plugin. Pour remédier à cela, essayez de mettre à jour votre version d'intégration netcode ou [de mettre à jour votre plugin Edgegap](https://github.com/edgegap/edgegap-unity-plugin?tab=readme-ov-file#update-the-plugin-in-unity).

***

`http2 : server : erreur de lecture du preface depuis le client //./pipe/docker_engine : le fichier a déjà été fermé`

* Ceci est un [problème connu avec les anciennes versions de Docker Desktop pour Windows](https://github.com/docker/for-win/issues/13611). Veuillez mettre à jour votre application Docker Desktop et réessayer la conteneurisation.

***

`Erreur Curl 35 : échec de la poignée de main du certificat. Erreur fatale. Code d'erreur UnityTls : 7`

* Cette erreur indique un problème de validation du certificat racine SSL, un problème connu dans les anciennes versions du plugin. Pour y remédier, veuillez essayer [de mettre à jour votre plugin Edgegap](https://github.com/edgegap/edgegap-unity-plugin?tab=readme-ov-file#update-the-plugin-in-unity).

</details>

## ☁️ 5. Téléverser sur Edgegap

☑️ Vous pouvez configurer les options suivantes (ou conserver les valeurs par défaut) :

* **Nom de l'application** sur Edgegap peut correspondre à votre nom d'image ou être personnalisé.
  * Nous avons choisi de copier votre nom d'image pour l'instant.
* **Version de l'application** sur Edgegap peut correspondre à votre tag ou être personnalisée.
  * Les horodatages sont une excellente option pour les noms de versions d'application, par ex., `2024.01.30-16.50.20-UTC` .
  * Plusieurs versions d'application peuvent pointer vers le même tag d'image, comme `v1.1.0` et `dev` .
  * En savoir plus sur [application-and-versions](https://docs.edgegap.com/learn/orchestration/application-and-versions "mention") plus tard.
* **Nom de l'image du serveur** de l'étape [#id-3.-containerize-your-game-server](#id-3.-containerize-your-game-server "mention").
* **Tag d'image du serveur** de l'étape [#id-3.-containerize-your-game-server](#id-3.-containerize-your-game-server "mention").

{% hint style="success" %}
Trouvez n'importe quel nom d'image et tag stocké sur votre machine dans **Docker Desktop / Images**.
{% endhint %}

☑️ Une fois satisfait de votre configuration, cliquez sur **Téléverser l'image et créer une version d'application**, attendez la fin du processus et vérifiez qu'il n'y a pas de nouvelles erreurs dans votre console Unity.

☑️ Vous serez redirigé vers notre [Tableau de bord](https://app.edgegap.com/), où vous pouvez configurer des paramètres optionnels. L'achèvement de cette étape aboutira à une [nouvelle version d'application créée](https://app.edgegap.com/application-management/applications/list), et votre [artefact de build étant étiqueté et téléversé dans le registre de conteneurs d'Edgegap](https://app.edgegap.com/registry-management/repositories/list).

☑️ Il vous sera maintenant demandé de définir un Port pour votre nouvelle version d'application. Assurez-vous de définir la même valeur de port serveur que dans l'étape [#id-4.-test-your-server-locally](#id-4.-test-your-server-locally "mention") de vos paramètres Transport ou spécifiques au netcode.

✅ Vous pouvez maintenant passer à l'étape suivante.

## 🚀 6. Déployer sur le cloud

☑️ Maintenant nous effectuerons le test final et **connecterons votre client de jeu Unity Editor à votre déploiement cloud**. Saisissez les détails de connexion du client de jeu depuis le :

* **Hôte** **URL** pointant vers l'IP du serveur, généralement dans `NetworkManager` composant.
* **Port externe** mappant vers le [port d'écoute interne du serveur](https://docs.edgegap.com/learn/orchestration/application-and-versions#port-mapping), généralement dans le composant Transport.

<details>

<summary>Dépannage et FAQ</summary>

Impossible de connecter les clients au serveur - `La requête a expiré.` , `请求超时` , `ConnexionÉchouée` , ou `Échec de la vérification du port`

* Tout d'abord, assurez-vous que le déploiement est Prêt, et qu'il n'y a pas d'exceptions d'exécution ou d'erreurs dans le journal de votre déploiement. Si votre déploiement s'est arrêté, inspectez les logs dans notre [Tableau de bord](https://app.edgegap.com/deployment-management/deployments/list).
* Si vous utilisez le netcode Mirror, vous devez avoir ["Démarrage automatique du serveur"](https://mirror-networking.gitbook.io/docs/hosting/edgegap-hosting-plugin-guide#build-and-push) sélectionné dans votre `NetworkManager` , reconstruisez, poussez et redéployez votre serveur.
* Si vous utilisez le netcode FishNet, vous devez activer [« Démarrer en mode headless »](https://fish-networking.gitbook.io/docs/manual/components/managers/server-manager#settings-are-general-settings-related-to-the-servermanager) dans votre `ServerManager`, reconstruisez, poussez et redéployez votre serveur.
* Si vous utilisez Photon Fusion 2 netcode, assurez-vous que votre serveur transmet l'IP publique de déploiement, le port externe et le `roomCode` sur le serveur, et le même code de salle dans le client dans le [paramètre « NeworkRunner.StartGame »](https://doc.photonengine.com/fusion/current/manual/network-runner#creating-or-joining-a-room) paramètre `StartGameArgs`. L'ID de déploiement (par ex. `b63e6003b19f`) est un excellent choix car il est unique au niveau mondial et facilement accessible au client par [Matchmaker](https://docs.edgegap.com/learn/matchmaking/matchmaker-in-depth) et [#injected-environment-variables](https://docs.edgegap.com/learn/matchmaking/matchmaker-in-depth#injected-environment-variables "mention").
* Ensuite, vérifiez que votre réglage de port dans les paramètres netcode de la build serveur correspond au port interne de votre [version d'application](https://app.edgegap.com/application-management/applications/list). Vous pouvez changer le mappage de ports en éditant le [version d'application](https://app.edgegap.com/application-management/applications/list) sans reconstruire. Trouvez votre protocole dans votre intégration netcode.
* Veuillez vous assurer que votre client de jeu se connecte au **port externe** affiché sur la page de détails de votre déploiement, cette valeur est toujours aléatoire pour des raisons de sécurité.
* Si vous utilisez le protocole Secure Websocket (WSS) dans votre intégration netcode, assurez-vous que votre [version d'application](https://app.edgegap.com/application-management/applications/list) configuration de port pour le port WSS a l'option TLS Upgrade activée.
* Êtes-vous situé en Chine et utilisez-vous [Smart Fleets](https://docs.edgegap.com/docs/deployment/session/fleet-manager/fleet) ? Votre connexion peut être bloquée par le Grand Firewall. Envisagez d'ajouter un serveur situé en Chine à votre flotte, ou d'utiliser un VPN pour vous connecter.

***

Mon déploiement s'est arrêté/redémarré et je ne peux plus accéder à ses logs.

* Dans le cas où le processus serveur plante à cause d'une exception, notre système tentera de redémarrer automatiquement le serveur. Envisagez de [tester votre serveur localement](#id-4.-test-your-server-locally) pour découvrir la cause principale.
* Nous ne conservons les logs que pendant la durée du déploiement ; si vous souhaitez inspecter les logs après l'arrêt du déploiement, veuillez [intégrer un stockage de logs tiers](https://docs.edgegap.com/docs/deployment/endpoint-storage).
* Voir [#id-5.-deployment-stopped](https://docs.edgegap.com/learn/orchestration/deployments#id-5.-deployment-stopped "mention") pour découvrir toutes les causes d'arrêt de votre déploiement.

***

Mon déploiement s'est arrêté automatiquement après X minutes.

* Les déploiements du niveau gratuit ont une limite de 60 minutes, envisagez de mettre à niveau votre compte.
* Tous les déploiements seront terminés après 24 heures d'exécution conformément à notre politique de sanitation des serveurs, pour la maintenance de l'infrastructure et pour éviter des coûts imprévus lorsque le déploiement n'a pas été correctement arrêté. Pour les serveurs de longue durée, envisagez d'utiliser [flottes-privees](https://docs.edgegap.com/learn/orchestration/flottes-privees "mention") avec [persistance](https://docs.edgegap.com/learn/orchestration/persistance "mention").
* Voir [#id-5.-deployment-stopped](https://docs.edgegap.com/learn/orchestration/deployments#id-5.-deployment-stopped "mention") pour découvrir toutes les causes d'arrêt de votre déploiement.

***

Mon déploiement est prêt mais je ne peux pas me connecter pendant plusieurs minutes après.

* Une fois qu'un déploiement est prêt, l'initialisation de votre moteur de jeu commence. Ce processus peut prendre de quelques secondes à plusieurs minutes, et le serveur n'accepte pas les connexions de joueurs pendant cette période.
* Envisagez d'optimiser l'initialisation de votre serveur pour réduire cette durée.
* Les clients de jeu devraient retenter la connexion toutes les 1 seconde pendant un temps limité (selon la durée d'initialisation), après quoi ils devraient revenir au matchmaking.
* Envisagez d'ajouter une scène de chargement afin que le serveur puisse effectuer l'initialisation (et le travel dans le cas d'Unreal Engine) en même temps que les clients, tout en synchronisant l'état des deux.

***

Mon appareil Meta Quest renvoie `HTTP 0 : Impossible de résoudre l'hôte de destination` .

* Lors de la compilation d'applications Unity pour la plateforme Android, l'autorisation d'accès Internet peut être supprimée automatiquement de l'APK client généré.
* Rajoutez les permissions dans (nécessite de reconstruire le client ensuite) :
  * Project Settings / OpenXR / :gear: Meta Quest Support / Forcer la suppression des permissions Internet (décocher).
  * Player Settings / Internet Access (définir sur require).

***

Que se passe-t-il si un joueur quitte mon déploiement ?

* Par défaut, les serveurs n'interdisent pas les connexions des joueurs. L'authentification des joueurs dépend de vos développeurs, car de nombreuses méthodes et fournisseurs d'authentification peuvent être utilisés.
* Les clients de jeu peuvent stocker localement les informations de connexion pour tenter une reconnexion en cas de plantage inattendu du client.
* Pour permettre aux joueurs de rejoindre des parties en cours, envisagez d'utiliser [#backfill](https://docs.edgegap.com/learn/matchmaking/matchmaker-in-depth#backfill "mention") ou [Sessions](https://docs.edgegap.com/docs/deployment/session).

***

Mon serveur affiche 100% d'utilisation CPU après être devenu prêt.

* Cela peut ne pas être un problème, car les moteurs de jeu ont tendance à effectuer des opérations lourdes en CPU pendant l'initialisation du serveur. Si l'utilisation du CPU ne baisse pas après 2-3 minutes depuis le démarrage du déploiement, vous devrez peut-être optimiser votre serveur ou augmenter les ressources de la version d'application.
* Réduire le tick rate peut impacter l'utilisation du CPU car le serveur effectue moins d'opérations de messagerie.
* Si vous utilisez le netcode Mirror, vous devez avoir ["Démarrage automatique du serveur"](https://mirror-networking.gitbook.io/docs/hosting/edgegap-hosting-plugin-guide#build-and-push) sélectionné dans votre `NetworkManager` , reconstruisez, poussez et redéployez votre serveur.
* Si vous utilisez le netcode FishNet, vous devez activer [« Démarrer en mode headless »](https://fish-networking.gitbook.io/docs/manual/components/managers/server-manager#settings-are-general-settings-related-to-the-servermanager) dans votre `ServerManager`, reconstruisez, poussez et redéployez votre serveur.
* Vous êtes limité à 1,5 vCPU et 3 Go de mémoire (RAM) dans le niveau gratuit.
* Vous pouvez augmenter les ressources allouées lors de la création d'une nouvelle version d'application. Vous pouvez dupliquer votre version d'application dans notre tableau de bord et ajuster ces valeurs selon vos besoins, sans reconstruire votre serveur ou image.

***

Mon déploiement redémarre en boucle et affiche l'erreur `OOM kill`

* Ceci est causé par le dépassement de la quantité de mémoire allouée. Envisagez d'optimiser l'utilisation de la mémoire avec du pooling d'objets, de la compression, ou en supprimant les objets inutiles dans votre scène.
* Assurez-vous que votre projet charge la scène par défaut contenant votre `NetworkManager` et que la scène est incluse dans les paramètres de Build de Unity.
* Vous êtes limité à 1,5 vCPU et 3 Go de mémoire (RAM) dans le niveau gratuit.
* Vous pouvez augmenter les ressources allouées lors de la création d'une nouvelle version d'application. Vous pouvez dupliquer votre version d'application dans notre tableau de bord et ajuster ces valeurs selon vos besoins, sans reconstruire votre serveur ou image.

***

Parfois, l'utilisation de la mémoire (RAM) de mon serveur monte brusquement à une valeur élevée — est-ce un problème ?

* Tant que vous restez dans la quantité de mémoire allouée à la version d'application, ce n'est pas un problème.
* Dépasser la quantité de mémoire allouée à la version d'application provoquera `OOM kill` (voir ci-dessus).

***

Les performances de mon serveur seront-elles impactées par d'autres serveurs fonctionnant sur la même machine ?

* Non, notre plateforme garantit que les ressources allouées ne seront pas utilisées par d'autres studios ou d'autres serveurs sur l'infrastructure partagée. Avec Edgegap, il n'y a pas de voisins bruyants.

</details>

## 👉 Étapes suivantes

### Arrêter les déploiements

En savoir plus sur les différentes méthodes pour [arrêter les déploiements](https://docs.edgegap.com/learn/orchestration/deployments#id-5.-deployment-stopped) une fois que la partie est terminée et que les joueurs partent.

Pour des arrêts en douceur, nous recommandons fortement d'implémenter l'API d'auto-arrêt dans votre jeu :

<details>

<summary>Exemple de snippet de code Unity C# pour l'API d'auto-arrêt</summary>

```csharp
using System;
using System.Collections;
using UnityEngine;
using UnityEngine.Networking;

public class EdgegapSelfStop : MonoBehaviour
{
    private const int MaxRetries = 2;
    private const int TimeoutSeconds = 30;
    private string url = Environment.GetEnvironmentVariable("ARBITRIUM_DELETE_URL");
    private string token = Environment.GetEnvironmentVariable("ARBITRIUM_DELETE_TOKEN");

    public void Run()
    {
        StartCoroutine(SendDeleteWithRetry());
    }

    private IEnumerator SendDeleteWithRetry()
    {
        if (string.IsNullOrEmpty(url))
        {
            Debug.LogError("Edgegap | ARBITRIUM_DELETE_URL n'est pas défini.");
            yield break;
        }

        if (string.IsNullOrEmpty(token))
        {
            Debug.LogError("Edgegap | ARBITRIUM_DELETE_TOKEN n'est pas défini.");
            yield break;
        }

        int attempt = 0;

        while (attempt <= MaxRetries)
        {
            attempt++;

            using (UnityWebRequest request = UnityWebRequest.Delete(url))
            {
                request.timeout = TimeoutSeconds;
                request.SetRequestHeader("Authorization", token);

                yield return request.SendWebRequest();

                if (request.result == UnityWebRequest.Result.Success)
                {
                    Debug.Log("Edgegap | requête DELETE réussie.");
                    yield break;
                }

                Debug.LogWarning(
                    $"Edgegap | tentative DELETE {attempt} échouée.\n" +
                    $"Résultat : {request.result}, Erreur : {request.error}"
                );

                if (attempt == MaxRetries)
                {
                    Debug.LogError("Edgegap | la requête DELETE a échoué après toutes les tentatives.");
                    yield break;
                }
            }
        }
    }
}
```

</details>

{% hint style="info" %}
Votre serveur Unity sera redémarré automatiquement en cas de crash ou d'épuisement de la mémoire.
{% endhint %}

### Variables injectées

Lisez des informations utiles comme l'ID de déploiement, l'adresse IP du serveur, l'emplacement du serveur, et plus encore ; en accédant aux variables d'environnement injectées. Chaque déploiement inclut automatiquement :

* [Variables de déploiement](https://docs.edgegap.com/learn/orchestration/deployments#injected-environment-variables) - fournies automatiquement par Edgegap,
* [Variables de matchmaking](https://docs.edgegap.com/learn/matchmaking/matchmaker-in-depth#injected-environment-variables) - fournies automatiquement par Edgegap lors de l'utilisation de [Matchmaker](https://docs.edgegap.com/broken-reference),
* [Variables de la version d'application](https://docs.edgegap.com/learn/orchestration/application-and-versions#injected-variables) - paires clé-valeur personnalisées configurables par vous.

**Vérifier si l'instance actuelle est un client de jeu ou un serveur** en vérifiant si la variable Edgegap est définie :

```csharp
if (
  string.IsNullOrEmpty(Environment.GetEnvironmentVariable("ARBITRIUM_REQUEST_ID"))
)
{
  // code client
} else {
  // code serveur
}
```

### Matchmaking

Démarrer vos déploiements manuellement en collant l'URL et les ports ne suffira pas pour un jeu en ligne.

{% hint style="success" %}
[**En savoir plus sur le matchmaking**](https://docs.edgegap.com/learn/matchmaking) **pour déployer automatiquement, juste à temps**, lorsque les joueurs se connectent.
{% endhint %}

### Optimiser les builds serveur

**Reconstruisez uniquement les assets qui ont changé depuis la dernière build.**

Envisagez d'utiliser [les builds incrémentales de Unity](https://docs.unity3d.com/Manual/incremental-build-pipeline.html) pour accélérer votre temps de build.

* Envisagez d'utiliser [les builds incrémentales de Unity](https://docs.unity3d.com/Manual/incremental-build-pipeline.html) pour accélérer votre temps de build.

**N'incluez que ce dont votre serveur a absolument besoin pour fonctionner.**

* Copier des fichiers inutilisés dans vos images entraîne un gonflement de l'image, des uploads plus longs, des vitesses de cache plus lentes et un démarrage global du serveur plus lent. [Consultez les suggestions d'optimisation d'image Docker](https://docs.docker.com/build-cloud/optimization/#dockerignore-files).

**Désactivez le batching statique des maillages pour réduire la taille de l'image.**

* [Désactivez le batching statique pour des builds, uploads et déploiements plus rapides.](https://docs.unity3d.com/Manual/DrawCallBatching.html)

**Compressez les maillages pour réduire la taille de l'image.**

* [Réglez la compression des maillages sur Élevée pour des builds, uploads et déploiements plus rapides.](https://docs.unity3d.com/6000.0/Documentation/Manual/compressing-mesh-data-optimization.html)
* La compression des sommets n'impacte pas la taille de l'image.

**Implémentez le chargement paresseux conditionnel des ressources.**

* Excluez les assets uniquement pour le client en [désactivant la lecture/écriture CPU des textures et des maillages](https://docs.unity3d.com/6000.0/Documentation/Manual/dedicated-server-optimizations.html).
* Envisagez d'utiliser [Unity Addressables](https://docs.unity3d.com/Packages/com.unity.addressables@2.1/manual/index.html) pour vos builds clients afin d'accélérer les builds et déploiements en [chargeant les assets juste à temps](https://docs.unity3d.com/Packages/com.unity.addressables@1.19/manual/LoadingAddressableAssets.html), ou en sautant le chargement de certains assets dans les builds serveurs en vérifiant la présence de [#injected-environment-variables](https://docs.edgegap.com/learn/orchestration/deployments#injected-environment-variables "mention").

**Envisagez d'utiliser** [**builds Docker multi-étapes (lien)**](https://docs.docker.com/build/building/multi-stage/)**.**

* Séparez les dépendances serveur volumineuses dans une image séparée pour les réutiliser dans des builds multi-étapes. Docker mettra en cache chaque couche et réutilisera simplement la version précédente en évitant de télécharger cette partie sauf indication contraire, vous faisant économiser de la bande passante et du temps d'attente pour la fin de l'upload.
* Si vous ne savez pas pourquoi une de vos commandes Dockerfile génère une erreur, essayez de déboguer localement. Créez une nouvelle étape juste avant que le problème n'arrive (ajoutez une seconde `FROM` commande), utilisez `--target` pour indiquer au processus de build de s'arrêter à l'étape problématique, puis `docker exec -it {container} /bin/bash` pour entrer dans un terminal interactif à l'intérieur de votre conteneur. Ensuite, vous pouvez utiliser des commandes shell dans votre image de base pour enquêter davantage (par ex. `top` sur ubuntu).

### Personnaliser l'image serveur

Nous supportons également l'ajout de votre propre Dockerfile pour les utilisateurs qui ont besoin de plus de contrôle sur leurs images en raison de l'optimisation de la taille de build, de dépendances superflues ou d'un processus de démarrage plus complexe. Vous pouvez optionnellement fournir un chemin vers votre Dockerfile personnalisé à l'étape [#id-3.-containerize-your-game-server](#id-3.-containerize-your-game-server "mention"). Nous allons maintenant partager quelques conseils et bonnes pratiques « faites-le vous-même ».&#x20;

**Des problèmes lors de l'utilisation de Websockets ou de requêtes HTTPS ?**

* Si vous obtenez `Erreur Curl 35 : échec de la poignée de main du certificat. Erreur fatale. Code d'erreur UnityTls : 7` ne désespérez pas, c'est un problème connu avec de vieilles images de base (`FROM`) incluant un certificat d'autorité racine expiré. Vous pouvez corriger cela en mettant à jour vers une version d'image de base plus récente (par ex. `ubuntu:22.04`), et en exécutant `update-ca-certificates` , ajoutez ceci à votre Dockerfile :

  ```docker
  FROM ubuntu:22.04

  RUN apt-get install -y ca-certificates && \
      apt-get clean && \
      update-ca-certificates
  ```

{% hint style="info" %}
Vous butez contre un mur ? Nous sommes disponibles dans notre [Discord communautaire](https://discord.gg/MmJf8fWjnt) et heureux de vous aider.
{% endhint %}


# Outils pour développeurs

Nous construisons ces outils pour vous avec un mantra simple : « les clés des équipes performantes sont l'itération rapide et les tests fréquents ». Si vous voyez une opportunité d'amélioration, veuillez nous le faire savoir dans notre [Discord Communautaire](https://discord.gg/NgCnkHbsGp). Nous espérons que vous apprécierez une expérience fluide. 🚀

{% hint style="info" %}
[Trouver des exemples concrets](https://docs.edgegap.com/docs/sample-projects/unity-netcodes) que vous pouvez utiliser comme point de départ de projet et modifier ensuite.
{% endhint %}

## ⚡ Plugin Quickstart pour serveurs dédiés

Construisez et lancez votre serveur de jeu dédié dans le cloud directement depuis votre éditeur Unity !

* [Plugin Dedicated Servers pour Unity - solution clé en main, code source et notes de version complètes.](https://github.com/edgegap/edgegap-unity-plugin)

{% hint style="success" %}
Ce plugin est fourni 100 % gratuitement, sous les conditions générales du niveau gratuit.
{% endhint %}

Toutes les versions Long Term Support (LTS) de Unity3D après 2021.3+ sont officiellement prises en charge.

Ce plugin contient des fonctionnalités destinées à vous aider à :

* connecter votre projet Unity à votre compte Edgegap,
* construire votre serveur de jeu dédié,
* containeriser votre serveur de jeu dédié,
* tester localement l'image docker de votre serveur,
* configurer la version de votre application Edgegap,
* déployer une instance de test de votre serveur sur le cloud Edgegap.

{% hint style="info" %}
Ce plugin ne modifie aucun comportement du jeu, c’est simplement un outil de développement pratique pour les tâches Edgegap. Le plugin n'est pas inclus dans vos builds, car il n'est utilisé que pendant la préparation de la construction du serveur.
{% endhint %}

#### Installation

{% hint style="success" %}
Voir [](https://docs.edgegap.com/unity "mention") pour commencer et pour des instructions détaillées sur l'utilisation du plugin.
{% endhint %}

<details>

<summary>Dépannage et FAQ</summary>

Erreur Unity : `[Package Manager Window] Erreur lors de l'ajout du package : https://github.com/edgegap/edgegap-unity-plugin.git`

* Pour ajouter notre plugin via une URL git, vous aurez besoin du client git installé ([#installation](#installation "mention")).

***

Erreur Unity : `Support de build Linux manquant`

* Voir [#usage-requirements](#usage-requirements "mention"), il est très probable que les modules de support de build Linux vous manquent, que vous pouvez installer via Unity Hub. Assurez-vous de choisir la même version de Unity que celle de votre projet.

</details>

{% hint style="info" %}
**Pour les développeurs de plugins** - si vous souhaitez détecter la présence de ce plugin dans l'Éditeur des utilisateurs, vous pouvez le faire en utilisant une directive du compilateur `#if EDGEGAP_PLUGIN_SERVERS {votre code} #endif` .
{% endhint %}

## ⭐ SDK de matchmaking

{% hint style="success" %}
Ce plugin est fourni 100 % gratuitement, sous les conditions générales du niveau gratuit.
{% endhint %}

Toutes les versions Long Term Support (LTS) de Unity3D après 2021.3+ sont officiellement prises en charge.

Ce plugin contient des fonctionnalités destinées à vous aider à :

* démarrer et arrêter le matchmaking avec un ticket individuel,
* reprendre le matchmaking à partir d'une affectation de serveur mise en cache,
* démarrer le matchmaking avec un groupe,
* utiliser [ping-beacons](https://docs.edgegap.com/learn/orchestration/ping-beacons "mention") pour la mesure de latence,
* surveiller la santé du matchmaker.

{% hint style="success" %}
Utilisez notre [script d'exemple Simple Example Unity](https://github.com/edgegap/edgegap-unity-gen2-sdk?tab=readme-ov-file#import-simple-example) pour tester le matchmaking en 5 minutes.
{% endhint %}

#### Installation

Veuillez vous référer à [le dépôt officiel du plugin](https://github.com/edgegap/edgegap-unity-gen2-sdk?tab=readme-ov-file#install-with-git-recommended) pour des instructions détaillées sur l'installation.

{% hint style="success" %}
[Ajouter des packages directement depuis l'éditeur Unity avec Git (tutoriel vidéo)](https://www.youtube.com/watch?v=ODL0DpEOiIE\&pp=ygUHZWRnZWdhcA%3D%3D).
{% endhint %}

<details>

<summary>Dépannage et FAQ</summary>

Unity : `[Package Manager Window] Erreur lors de l'ajout du package : https://github.com/edgegap/edgegap-unity-gen2-sdk.git`

* Pour ajouter notre plugin via une URL git, vous aurez besoin du client git installé ([#installation-1](#installation-1 "mention")).

***

Unity : `échec de la résolution de l'assembly : 'Edgegap.Gen2.SDK...`

* Ceci est un problème connu causé par [le compilateur Burst de Unity](https://docs.unity3d.com/6000.0/Documentation/Manual/com.unity.burst.html).
* Installer le plugin [via une archive ZIP](https://github.com/edgegap/edgegap-unity-gen2-sdk/edit/main/README.md#install-via-zip-archive) et supprimez .asmdef dans le dossier du plugin pour résoudre cela.

***

Visual Studio : `le nom de type ou d'espace de noms est introuvable` pour l'espace de noms Edgegap.

1. Dans l'éditeur Unity, naviguez vers **Edit / Preferences / External Tools / Generate .csproj files**.
2. Assurez-vous d'avoir activé **les packages Git**.
3. Cliquez sur **Regenerate project files**.

</details>

## 📫 Bibliothèque Distributed Relay Transports

Trouvez un Transport personnalisé pour votre bibliothèque de netcode afin d'utiliser les relais distribués dans les jeux pair-à-pair.

[Voir la documentation](https://docs.edgegap.com/docs/relay-transports-samples):

* Télécharger les exemples Edgegap Relay :
  * [exemple Mirror](https://github.com/edgegap/unity-mirror-relay-sample),
  * [exemple FishNet](https://github.com/edgegap/unity-fishnet-relay-sample),
  * [exemple Unity NGO](https://github.com/edgegap/unity-ngo-relay-sample).
* [Edgegap Relay Transport Library - code source et notes de version pour les netcodes pris en charge.](https://github.com/edgegap/distributed-relay-examples)


# Orchestration

Orchestration et DevOps[^1] sont au cœur de la plateforme Edgegap. Mettre en place des processus solides basés sur les meilleures pratiques est essentiel pour tirer parti efficacement des nouvelles technologies et services pour des équipes de toutes tailles.

Configurer votre projet de la bonne manière est primordial pour un succès à long terme :

1. **Concentrez-vous sur votre cœur de métier** au lieu de construire une infrastructure hyper-réutilisable autour.
2. **Minimisez l'enfermement fournisseur** avec une approche cloud native et un couplage lâche des services.
3. **Rendez votre expérience de développement agréable** et itérez plus rapidement grâce à l'automatisation.

{% hint style="success" %}
Optimisez votre utilisation des ressources et [profitez de l'allocation fractionnée de vCPU](https://docs.edgegap.com/learn/application-and-versions#resource-requirements) pour réduire le coût global des serveurs.
{% endhint %}

**Évitez la phase douloureuse d'essais et d'erreurs et commencez avec une base solide :**

* Créer un modèle [application-and-versions](https://docs.edgegap.com/learn/orchestration/application-and-versions "mention") pour démarrer un nouveau serveur [deployments](https://docs.edgegap.com/learn/orchestration/deployments "mention") en quelques secondes.
  * Montez en charge rapidement avec [#match-bound](https://docs.edgegap.com/learn/deployments#match-bound "mention") des sessions de courte durée,
  * ou pré-dimensionnez manuellement avec [#regional-standby](https://docs.edgegap.com/learn/deployments#regional-standby "mention") pour un trafic prévisible.
* Établissez des sessions utilisateur avec [appariement](https://docs.edgegap.com/learn/appariement "mention"), [navigateur-de-serveurs](https://docs.edgegap.com/learn/navigateur-de-serveurs "mention"), ou avec une solution personnalisée.
  * Choisissez coéquipiers, adversaires et serveurs avec [ping-beacons](https://docs.edgegap.com/learn/orchestration/ping-beacons "mention") pour une faible latence.
* Gérez l'état des serveurs [persistance](https://docs.edgegap.com/learn/orchestration/persistance "mention") de manière fiable pour atténuer les pannes et les retours en arrière.
  * Réservez de la capacité de calcul en veille avec [flottes-privees](https://docs.edgegap.com/learn/orchestration/flottes-privees "mention") pour des serveurs persistants 24h/24 et 7j/7.
  * Configurez et personnalisez [managed-clusters](https://docs.edgegap.com/learn/advanced-features/managed-clusters "mention") pour des applications Kubernetes hautement disponibles.
* Téléversez de nouvelles constructions de serveurs et gérez facilement le versioning avec notre [edgegap-container-registry](https://docs.edgegap.com/learn/advanced-features/edgegap-container-registry "mention").

Continuez à lire pour en savoir plus sur les meilleures pratiques et recommandations pour votre configuration.

[^1]: Opérations Développeur


# Applications et versions

Découvrez la gestion des versions et des applications - concepts et bonnes pratiques pour une compréhension approfondie.

## 📦 Applications

Les applications encapsulent les projets serveur. Cette séparation de contexte est particulièrement utile si vous :

* travaillez sur plusieurs jeux ou projets non liés au jeu (facturation consolidée),
* travaillez sur des projets externes en tant que co-développeur (transférer la propriété plus tard),
* dépendrez de plusieurs types de serveurs faiblement couplés avec des modèles ou exigences d'échelle différents.

Vous pouvez gérer vos Applications sur Edgegap en utilisant nos plugins, [tableau de bord](https://app.edgegap.com/application-management/applications/list), ou notre API.

{% hint style="success" %}
Explorez notre [référence de l’API Applications](https://docs.edgegap.com/api/#tag/Applications), ou lisez-en plus sur notre [API de gestion](https://docs.edgegap.com/api/).
{% endhint %}

## 🏷️ Versions d’application

Au fur et à mesure que vous développez votre application et produisez continuellement de nouvelles builds, vous devrez stocker chaque build comme une version séparée afin de :

* **maintenir la compatibilité** entre vos clients et le serveur,
* comparer divers aspects de vos **versions incrémentales** (performance, ressenti des utilisateurs),
* tester **plusieurs versions d’application simultanément** (développement, assurance qualité, préproduction, bêta).

{% hint style="info" %}
Chaque version d’App pointe vers un artefact de build de votre choix. Plusieurs versions peuvent pointer vers la même build.
{% endhint %}

Vous pouvez gérer vos versions d’App sur Edgegap en utilisant notre [tableau de bord](https://app.edgegap.com/application-management/applications/list), ou notre API.

{% hint style="success" %}
Explorez notre [référence de l’API des versions d’App](https://docs.edgegap.com/api/#tag/Applications/operation/app-version-post), ou lire plus sur [API](https://docs.edgegap.com/api/).
{% endhint %}

Chaque version est identifiée de manière unique au sein de son Application parente par **nom de la version d’App**. Vous êtes libre de définir votre propre convention de nommage. Voici quelques exemples populaires pour inspirer votre choix :

* `2024.01.30-16.23.00-UTC` - les horodatages sont transparents pour conserver de nombreuses versions passées,
* `1.1.0` - [versionnage sémantique](https://semver.org/) est un excellent choix pour communiquer l’étendue des changements,
* `dev` , `staging`, `qa`, `prod` - ne conserver que la dernière version par environnement est très simple,
* `blue`, `green` - les versions peuvent être utilisées comme alias pour une stratégie de mise à jour continue.

{% hint style="success" %}
Vous pouvez changer d’approche à tout moment, tant que vous maintenez la compatibilité client/serveur.
{% endhint %}

{% hint style="info" %}
Vous pouvez désactiver toute App ou Version dans notre [tableau de bord](https://app.edgegap.com/application-management/applications/list) vers **filet de sécurité contre les erreurs humaines (dev)**.
{% endhint %}

{% hint style="info" %}
Le palier Gratuit est limité à 2 Applications, 2 versions et 5 Go de stockage du registre de conteneurs.
{% endhint %}

### Combiner des stratégies de versionnage

Souvent, la meilleure solution est un mélange de stratégies de versionnage, par exemple :

* utiliser des horodatages ou le versionnage sémantique pour les builds dev, pour un suivi plus granulaire ;
* conserver `staging`, `qa` et `prod` des versions avec des paramètres spécifiques à l’environnement ;
* alterner `blue` et `green` les versions comme alias pour [mises à jour sans temps d’arrêt du matchmaking](https://docs.edgegap.com/docs/gen2-matchmaker#rolling-updates-ab-tests).

## 🧱 Paramètres requis

Ces paramètres fondamentaux doivent toujours être définis.

### Exigences en ressources

En plus du **nom de la version**, plusieurs paramètres sont requis pour créer une nouvelle version :

* **vCPU** - combien d’unités CPU virtuelles votre application nécessite pour fonctionner (1024 unités = 1 vCPU),
  * **la quantité minimale de vCPU autorisée est de 0,25 vCPU (256 unités),**
  * ce paramètre ne peut pas être modifié sur une version d’App existante, vous devez créer une nouvelle version.
* **Mémoire** - combien de mégaoctets de RAM votre application nécessite pour fonctionner (1024Mo = 1Go),
  * ce paramètre ne peut pas être modifié sur une version d’App existante, vous devez créer une nouvelle version.
* **GPU** - combien d’unités de traitement graphique votre application nécessite pour fonctionner,
  * cette fonctionnalité n’est pas encore disponible, veuillez nous contacter si vous êtes intéressé.

{% hint style="success" %}
Les versions incluent automatiquement la RAM selon un ratio RAM-vCPU de 2:1, **autorisant jusqu’à 512 Mo de RAM par 0,25 vCPU**.
{% endhint %}

{% hint style="info" %}
Nos serveurs utilisent des CPU AMD/Intel avec une fréquence de 2,4 - 3,2 GHz, variable selon l’emplacement. Pour garantir que votre serveur dispose de ressources suffisantes, contactez-nous sur [Discord Communautaire](https://discord.gg/MmJf8fWjnt).
{% endhint %}

### Détails de l’image

Ces paramètres aideront notre système à décider quelle build de votre serveur doit être démarrée ultérieurement :

* **Registre** - `registry.edgegap.com` si vous utilisez notre [Registre de conteneurs](https://docs.edgegap.com/docs/container/edgegap-container-registry),
  * pour utiliser un registre tiers, saisissez vos identifiants docker du registre tiers,
  * le registre sert de service de stockage partagé pour vos dépôts et ceux d’autres utilisateurs.
* **Dépôt d’images** - fait référence au dépôt dédié de votre Application,
  * trouvez tous vos dépôts sur notre [page Registre de conteneurs du tableau de bord](https://app.edgegap.com/registry-management/repositories/list),
  * chaque dépôt peut inclure plusieurs tags de votre image serveur.
* **Tag** - fait référence à un artefact de build (version) spécifique de votre image serveur,
  * nos plugins copient par défaut les valeurs de tag à partir des noms de version d’App,
  * vous pouvez afficher les tags stockés localement dans Docker Desktop Images ou en utilisant le CLI docker.

{% hint style="danger" %}
:x: **NE PAS - écraser des tags existants ni utiliser `latest` tag** pour éviter de déployer des builds obsolètes (en cache).\
:white\_check\_mark: **FAITES - incrémentez toujours le tag de votre version** pour déployer la build prévue et éviter des problèmes de release.
{% endhint %}

* **Registre privé** - si l’accès à votre dépôt est protégé (dépôt privé), nous aurons également besoin de :
  * **Jeton d’utilisateur** - votre nom d’utilisateur pour l’accès programmatique au registre,
  * **Jeton de mot de passe** - votre mot de passe pour l’accès programmatique au registre,
  * pour Edgegap [Registre de conteneurs](https://docs.edgegap.com/docs/container/edgegap-container-registry), vous pouvez [copier ces valeurs depuis notre tableau de bord](https://app.edgegap.com/registry-management/repositories/list),
  * ces éléments ne sont pas requis pour les dépôts publics.

<details>

<summary>Dépannage et FAQ</summary>

J’ai reçu l’erreur `401 Non autorisé` lorsque je pousse mon image serveur.

* Cela signifie que vous n’êtes pas connecté à votre registre de conteneurs. Voir Registre de conteneurs pour [instructions du Registre de conteneurs Edgegap](https://docs.edgegap.com/docs/container/edgegap-container-registry#getting-your-credentials), ou l’équivalent pour votre fournisseur de registre. Répéter votre dernière opération ne résoudra pas l’erreur.

***

J’ai reçu l’erreur `403 Interdit` lorsque je pousse mon image serveur.

* Cela signifie soit que l’utilisateur enregistré actuellement sur le registre n’a pas les permissions suffisantes (typiquement pour pousser une nouvelle image), soit que vous êtes connecté au mauvais fournisseur de registre. Essayez de vous déconnecter et de vous reconnecter avec le fournisseur et l’utilisateur correct ayant des permissions suffisantes. Répéter votre dernière opération ne résoudra pas l’erreur.

***

Quelle est la différence entre un registre, un dépôt et un projet ?

* Considérez le registre comme une installation de stockage, le dépôt comme une unité de stockage, et le projet comme le numéro de l’unité de stockage. Chaque registre comprend typiquement de nombreux dépôts, certains publics, d’autres privés pour des organisations et des utilisateurs.
* Exemple de registre : `registry.edgegap.com` .
* Exemple de dépôt : `registry.edgegap.com/my-edgegap-org/my-game-server`.
* Exemple de nom de projet : `mon-serveur-de-jeu` .

***

Lorsque je pousse de nouveaux tags / builds, mes modifications ne se rechargent pas correctement.

* Assurez-vous qu’à chaque reconstruction vous poussez avec un nouveau tag d’image. Le système de cache interne d’Edgegap utilise les noms de tag et si vous écrasez une valeur de tag (par ex. `latest`) il ne détectera pas la nouvelle build.

***

Puis-je taguer le même artefact de build plusieurs fois ?

* Oui, vous pouvez taguer le même artefact plusieurs fois sans problème, servant de multiples alias vers la même build. Continuez à lire pour apprendre comment supprimer les tags plus tard.

***

Que se passe-t-il lorsque je supprime un tag ? Pourquoi ne puis-je pas supprimer un artefact spécifique en utilisant un hash ?

* La suppression d’un tag entraînera également la suppression de l’artefact de build associé, s’il n’y a pas d’autres tags associés à l’artefact au moment de [la requête API](https://docs.edgegap.com/api/#tag/Container-Registry/operation/image-tag-delete).
* En raison des normes de l’API docker et pour garantir la meilleure expérience utilisateur possible, nous fournissons uniquement une interface pour supprimer des tags. Voir le point ci‑dessus concernant la suppression d’artefacts de build.

</details>

## ⚙️ Paramètres optionnels

Ces paramètres peuvent être configurés pour personnaliser davantage vos déploiements.

### Variables injectées

Des variables d’environnement personnalisées seront injectées pour tous les déploiements sur cette version :

* exemples courants : arguments du moteur, secrets et points de terminaison tiers,
* voir [#injected-environment-variables](https://docs.edgegap.com/learn/deployments#injected-environment-variables "mention") pour comprendre les différentes manières dont les variables d’environnement peuvent être injectées selon le contexte du déploiement, en plus des variables de version d’app,
* chaque variable d’environnement peut contenir jusqu’à 4 Ko (kilooctets) de données de chaîne.

{% hint style="warning" %}
Assurez-vous de **définir vos variables sensibles (secrets, jetons) comme cachées** pour plus de sécurité !
{% endhint %}

### Mise en cache active

:star2: [**Passez au niveau Pay as You Go**](https://app.edgegap.com/user-settings?tab=memberships) **pour débloquer un temps de déploiement de 0,5 seconde dans le monde entier !**

**Accélérez les déploiements et démarrez les serveurs en quelques secondes, sans serveurs en veille requis.** L’image serveur associée à cette version d’app sera préchargée automatiquement dans tous nos emplacements mondiaux.

La mise en cache prendra pleinement effet une fois que le niveau de cache de votre version d’app atteindra 🟢 Bon.

{% hint style="success" %}
Plusieurs versions d’app peuvent réutiliser le même tag d’image. **Activer le cache pour une version l’activera automatiquement pour toutes les versions liées au même tag d’image**, facilitant les déploiements paramétrés.
{% endhint %}

{% hint style="info" %}
L’image est également mise en cache de manière passive lors du déploiement, uniquement sur la machine hôte où elle a été déployée.
{% endhint %}

{% hint style="warning" %}
**Les images sont retirées du cache si elles ne sont pas déployées pendant 72 heures consécutives.**
{% endhint %}

### Mappage de ports

Chaque serveur nécessite au moins un port pour accepter les connexions entrantes des clients :

* **Port** la valeur fait référence au **port interne** valeur, généralement depuis votre intégration netcode,
* **Protocole** dépendra du transport de votre intégration netcode,
* **Nom** est un identifiant lisible par l’humain pour vos besoins propres, peut être identique au Port,
* **Vérifications** peuvent être activées pour s’assurer que votre conteneur est initialisé avant d’être marqué READY.

{% hint style="success" %}
La plupart des jeux ne nécessiteront qu’un seul mappage de port UDP pour le port `7777`.
{% endhint %}

Alors que les ports internes pour le processus serveur sont définis comme faisant partie de la version d’app, **les ports externes sont attribués au hasard une fois qu’un déploiement est créé**, afin qu’une partie potentiellement malveillante (pirate) soit ralentie et détectée avant qu’elle ne puisse causer des dommages.

<figure><img src="https://3008966946-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2FXfDDoCk7J4O9qtkkjurh%2Fimage.png?alt=media&#x26;token=a509cc92-a410-4658-9dcd-b032497debb5" alt=""><figcaption></figcaption></figure>

{% hint style="info" %}
Ajoutez plus de ports dans votre mappage de ports si votre serveur communique via plusieurs protocoles.
{% endhint %}

### Garde-fous de sécurité

Ces paramètres aident pour divers cas limites et le dépannage général des serveurs :

* **Contraintes temporelles** - ces fonctionnalités peuvent vous aider à gérer le cycle de vie des ressources des déploiements :
  * **Durée maximale du jeu** peuvent être définies pour arrêter gracieusement vos serveurs après une période donnée, ou être définies à `-1`  avec [création/édition de l’API de version d’app](https://docs.edgegap.com/docs/api/gestion-des-versions#post-v1-app-app_name-version) pour [persistance](https://docs.edgegap.com/learn/orchestration/persistance "mention") avec [flottes-privees](https://docs.edgegap.com/learn/orchestration/flottes-privees "mention").
  * **Temps maximum de déploiement** peut vous aider à nettoyer les déploiements qui prennent trop de temps à démarrer.
* **Stockage des logs de conteneur** - pour exporter les logs du serveur après l’arrêt du déploiement, spécifiez un bucket compatible S3 préconfiguré pour exporter vos logs de conteneur,
  * voir [Stockage des points de terminaison](https://docs.edgegap.com/docs/deployment/endpoint-storage) pour des détails sur la configuration et l’utilisation.

{% hint style="warning" %}
Les logs des versions sans Stockage externe seront supprimés à la terminaison du déploiement.
{% endhint %}

{% hint style="info" %}
Le palier Gratuit est limité à 2 Applications, 2 versions et 5 Go de stockage du registre de conteneurs.
{% endhint %}

## ⏩ Cohérence des mises à jour

Afin de garantir qu’aucun paramètre ne change lorsque vous créez une nouvelle version d’App via notre [tableau de bord](https://app.edgegap.com/application-management/applications/list), nous recommandons d’utiliser la **Dupliquer** fonction en haut à droite de la page du tableau de bord de votre version d’App précédente. Lors de la duplication, vous pouvez modifier n’importe quel paramètre avant d’enregistrer.

{% hint style="success" %}
**Dupliquer ou modifier vos versions d’App ne nécessite pas de reconstruire votre image serveur.**
{% endhint %}

{% hint style="info" %}
Voir [Mises à jour progressives du matchmaker](https://docs.edgegap.com/docs/gen2-matchmaker#rolling-updates-ab-tests) pour davantage **d’automatisation des releases**.
{% endhint %}


# Déploiements

En savoir plus sur les déploiements et leur cycle de vie - concepts et bonnes pratiques pour une compréhension approfondie.

## 🗺️ Orchestration

Démarrez de nouveaux serveurs en quelques secondes pour répondre aux demandes de capacité grâce à notre approche cloud native d'edge computing. Nous traitons les serveurs comme [du bétail plutôt que des animaux de compagnie](https://cloudscaling.com/blog/cloud-computing/the-history-of-pets-vs-cattle/) - remplaçant entièrement les instances défectueuses au lieu de soigner chacune manuellement.

{% hint style="info" %}
Votre choix d'orchestration va **impacter le coût de vos devops, le coût des serveurs et la scalabilité**.
{% endhint %}

{% hint style="success" %}
[Contactez-nous sur Discord](https://discord.gg/MmJf8fWjnt) pour en savoir plus sur les options d'orchestration hybride et l'optimisation du coût d'hébergement.
{% endhint %}

Pour comprendre pleinement tous les avantages et inconvénients, comparons différentes méthodes d'orchestration.

### Lié au match

Standard d'or pour les studios modernes offrant la **intégration la plus simple avec la meilleure efficacité de coût**.

👍 **Avantages**

* Meilleure efficacité de coût - montée en charge en temps réel pour répondre à la demande des joueurs minute par minute.
* Coût de devops le plus bas grâce à l'hébergement sans région, Edgegap automatisant 99 % des tâches.
* Ping le plus bas grâce à plus de 615 sites dans l'infrastructure cloud publique d'Edgegap.
* Montée en charge la plus rapide (capacité d'explosion) en cas de pic de trafic inattendu.
* Plus haut niveau de sécurité et de prévention de la triche des joueurs (autorité serveur).
* Impact minimal d'un crash serveur inattendu sur les joueurs, n'affectant qu'un seul match.

👎 **Inconvénients**

* Adopter un nouveau modèle mental d'orchestration nécessite un certain temps d'adaptation initial.
* Les serveurs fonctionnant plus de 24 heures seront automatiquement terminés.

🧩 **Le mieux adapté pour**

* Jeux sensibles à la latence - **lorsque l'optimisation du netcode ne peut pas compenser un ping élevé :**
  * Jeux de tir à la première personne, jeux de combat, VR & XR (réalité virtuelle et étendue), …
* Jeux avec une **limite supérieure de la durée des matchs par conception**,
  * Battle Royale, PvPvE[^1], Coop Shooters, MOBA, jeux de sport, ARPGs & Dungeon Crawlers, …

🔎 **Découvrabilité**

* Démarrez de nouvelles parties lorsque suffisamment de joueurs rejoignent [matchmaking](https://docs.edgegap.com/learn/matchmaking "mention").
  * Ajouter des joueurs pour [remplacer les départs dans les matchs existants avec du backfill](https://docs.edgegap.com/matchmaking/matchmaker-in-depth#backfill).
* Permettre aux joueurs de parcourir les serveurs et d'en choisir un dans une liste avec [navigateur-de-serveurs](https://docs.edgegap.com/learn/navigateur-de-serveurs "mention").
* [Implémenter un backend de jeu personnalisé ou tiers pour découvrir les serveurs](https://docs.edgegap.com/advanced-features/managed-clusters#nakama-by-heroic-labs).

{% hint style="info" %}
Edgegap met automatiquement à l'échelle tous les emplacements de serveurs (plus de 615) en fonction de l'activité des joueurs dans chaque région. Préparez-vous au succès - [montez en capacité jusqu'à 14 millions d'utilisateurs simultanés en 60 minutes](https://edgegap.com/resources/performance-benchmark).
{% endhint %}

### Standby régional

Modèle traditionnel pour **mondes persistants avec contenu généré par les utilisateurs et jeux sociaux MMO**.

👍 **Avantages**

* Approche familière et facile à comprendre, méthode à l'ancienne pour vétérans aguerris.
* Plus haut niveau de sécurité et de prévention de la triche des joueurs (autorité serveur).
* Coût facilement prévisible sur la base d'un engagement mensuel.

👎 **Inconvénients**

* Coût d'hébergement plus élevé - chaque région nécessite un ou plusieurs serveurs de veille inactifs (capacité d'explosion).
* Coût de devops plus élevé - mise à l'échelle, opérations et maintenance dupliquées par région.
* Les régions avec une base de joueurs plus petite subissent un ping élevé en raison de la jonction sur des serveurs éloignés.

🧩 **Le mieux adapté pour**

* Mondes persistants avec contenu généré par les utilisateurs stocké sur le serveur même lorsque les joueurs sont hors ligne.
  * MMO, sandboxes avec construction de bases ou placement d'objets, shooters d'extraction, ...
* jeux tolérants à la latence - **lorsque la physique en temps réel autoritaire côté serveur n'est pas requise**:
  * jeux mobiles, jeux coopératifs, TCG/CCG, stratégies au tour par tour, …
* Multijoueur asynchrone, **où les crashs serveurs ont un impact minimal sur l'expérience du joueur :**
  * course contre des fantômes, piller une base ennemie, jeux de construction/agriculture basés sur un minuteur, …
* applications avec un lourd processus d'initialisation - lorsque la préparation des serveurs prend des minutes.

🔎 **Découvrabilité**

* Permettre aux joueurs de parcourir les serveurs et d'en choisir un dans une liste avec [navigateur-de-serveurs](https://docs.edgegap.com/learn/navigateur-de-serveurs "mention").
* [Implémenter un backend de jeu personnalisé ou tiers pour découvrir les serveurs](https://docs.edgegap.com/advanced-features/managed-clusters#nakama-by-heroic-labs).

{% hint style="info" %}
Voir [managed-clusters](https://docs.edgegap.com/learn/advanced-features/managed-clusters "mention") pour **auto-héberger vos microservices et services backend** sur Edgegap.
{% endhint %}

### Peer to Peer

Déplacez les efforts de développement de ~~serveurs dédiés~~ vers **relay netcode pour les jeux non compétitifs**.

Sujets connexes : listen servers, autorité du joueur-hôte, punch-through NAT.

👍 **Avantages**

* Coût d'hébergement le plus bas, nécessitant uniquement des serveurs Relay pour résoudre le punch-through NAT.
* Coût de devops le plus bas - maintenance requise uniquement pour les builds clients et les canaux de distribution.
* Impact minimal d'un crash serveur inattendu sur les joueurs, n'affectant qu'un seul match.
* Facile à implémenter et rapide pour prototyper, sans développement backend requis.

👎 **Inconvénients**

* Augmentation de l'effort de développement du netcode peer-to-peer nécessitant des compétences en programmation concurrente.
* Pires temps de ping et plus sensible aux conditions réseau défavorables (p. ex. Internet mobile).
* Sécurité la plus faible, vulnérable aux attaques de type homme du milieu et au détournement de session.
* Risque de perte de sessions lorsque l'hôte part, sauf si vous implémentez une migration d'hôte personnalisée.

🧩 **Le mieux adapté pour**

* Jeux coopératifs et occasionnels - **lorsque la triche n'enlève pas le plaisir ou ne détruit pas le jeu**,
  * Jeux pour enfants, jeux d'exploration, aventures, …

🔎 **Découvrabilité**

* [Implémenter un backend de jeu personnalisé ou tiers pour découvrir les serveurs](https://docs.edgegap.com/advanced-features/managed-clusters#nakama-by-heroic-labs).

{% hint style="success" %}
Voir nos [Relais distribués](https://docs.edgegap.com/docs/distributed-relay-manager) pour le service permettant le peer-to-peer avec une latence et une sécurité de classe mondiale.
{% endhint %}

## 📍 Placement des serveurs

Quel que soit le mode d'orchestration choisi, choisir le bon emplacement de serveur pour un groupe de joueurs est essentiel pour garantir le meilleur ping possible et une expérience joueur optimale. Découvrez différentes stratégies de placement des serveurs et comment elles impactent vos joueurs.

{% hint style="info" %}
Votre stratégie de placement des serveurs va **impacter l'expérience de vos joueurs, la rétention et les avis sur votre jeu**.
{% endhint %}

{% hint style="success" %}
**Edgegap déploie dans le** [**meilleur emplacement possible**](#server-score) **avec une capacité disponible**, pour des matchs rapides et à faible latence.
{% endhint %}

<figure><img src="https://3008966946-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2FjiPRa6gGEku2oGm3qW5s%2Fimage.png?alt=media&#x26;token=306897d4-8ab1-4766-bc90-5d02882b573c" alt=""><figcaption></figcaption></figure>

{% hint style="info" %}
Voir [#deployment-balance-points](#deployment-balance-points "mention") vers **analyser le placement des serveurs en temps réel**, à grande échelle.
{% endhint %}

### Score serveur

La stratégie de score serveur utilise la méthodologie brevetée d'Edgegap, qui **optimise le placement des serveurs pour chaque match individuellement**. Effectue une télémétrie non intrusive pour approximer la proximité réseau de chaque joueur par rapport à nos emplacements de serveurs et choisir le serveur qui offre le meilleur :

* **réactivité** - fournit le ping le plus bas pour tous les joueurs en moyenne,
* **équité** - fournit un ping équilibré et équitable pour tous les joueurs.

{% hint style="success" %}
Notre [Matchmaker](https://docs.edgegap.com/learn/matchmaking) utilise **la stratégie de score serveur par défaut, pour assurer la meilleure expérience possible**. Pour utiliser cette stratégie avec [Deploy APIs](https://docs.edgegap.com/api/#tag/Deployments), fournissez les IP publiques ou les coordonnées géographiques des joueurs dans votre requête de déploiement.
{% endhint %}

**Placement non réactif** - le serveur est loin, ping élevé pour tous les joueurs :

<figure><img src="https://3008966946-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2FNszxk3uRY78L7V6nLPlp%2Fimage.png?alt=media&#x26;token=904b9b3d-7499-45d3-81c6-cc2b5cb6dd32" alt=""><figcaption></figcaption></figure>

**Placement injuste** - ping inégal, un joueur est désavantagé :

<figure><img src="https://3008966946-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2FxjsD6ijYWHljBAVuV57w%2Fimage.png?alt=media&#x26;token=ab477e89-4afe-4203-9b7f-b85b035dc9eb" alt=""><figcaption></figcaption></figure>

**Exemple de bon placement** - ping réactif et équitable pour tous les joueurs :

<figure><img src="https://3008966946-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2FQfSd4uo9twyxEWCkPLqu%2Fimage.png?alt=media&#x26;token=8d3cd64b-9527-48fe-886b-96393c15449d" alt=""><figcaption></figcaption></figure>

{% hint style="info" %}
Cette stratégie est **particulièrement efficace pour héberger un groupe de joueurs éloignés les uns des autres** (Amérique du Nord vs Europe, ou côte Ouest vs côte Est), cas fréquent avec des lobbies préfabriqués.
{% endhint %}

### Géolocalisation

Alternativement, **fournissez les coordonnées de latitude et longitude des joueurs ou les coordonnées d'un emplacement de serveur préféré** au lieu d'utiliser la télémétrie automatisée. Cette approche nécessite une implémentation supplémentaire de recherche géographique côté client, en s'appuyant entièrement sur la solution du développeur du jeu.

{% hint style="warning" %}
La stratégie de géolocalisation n'est pas recommandée pour [#match-bound](#match-bound "mention") l'orchestration, sauf pour les applications avec des exigences réglementaires strictes pour les transferts de données interrégionaux, ou lorsque l'IP du joueur n'est pas disponible.
{% endhint %}

{% hint style="success" %}
Pour utiliser cette stratégie avec [Deploy APIs](https://docs.edgegap.com/api/#tag/Deployments), listez les IP publiques ou les coordonnées géographiques des joueurs dans votre requête de déploiement.
{% endhint %}

### Verrouillage régional

Les serveurs peuvent être placés en utilisant un paramètre de région grossièrement généralisé, soit :

* choisi automatiquement pour le joueur, en fonction de leurs métadonnées (base de données des comptes joueurs), ou
* sélectionné par le joueur lors du matchmaking, permettant un placement avec une latence client-serveur élevée.

{% hint style="danger" %}
**Utiliser cette stratégie seule n'est pas recommandé car cela peut entraîner de mauvaises performances réseau.**
{% endhint %}

{% hint style="success" %}
Utiliser **la sélection de région comme pré-filtre en combinaison avec une autre stratégie** est une meilleure alternative.
{% endhint %}

## 🟢 Qualité de la connexion

Certains jeux (et certains joueurs) sont plus sensibles à la latence ou au lag que d'autres. Bien que les rapports des joueurs soient un excellent indicateur d'incidents ou de bugs de régression à grande échelle, **les joueurs peuvent manquer d'une compréhension approfondie des concepts réseau** et sont prompts à attribuer la faute aux studios, au netcode ou aux serveurs.

La cause première de certains problèmes peut être cachée aux joueurs, la coopération entre le studio et le fournisseur d'hébergement peut donc être cruciale. **La priorité d'Edgegap est toujours de fournir le meilleur service possible.**

Si vous recevez de nombreux rapports de joueurs, si vous subissez des pannes généralisées ou des problèmes répétés, veuillez nous contacter immédiatement via un ticket de support sur notre plateforme.

#### Faible latence

La latence du joueur est une combinaison de la latence due au transfert de données entre :

* **appareils physiques -** le signal physique voyageant à travers [la topologie du réseau Internet](https://en.wikipedia.org/wiki/Internet#Routing),
* **hôte à hôte** - résultant des protocoles, du transport et des mesures de sécurité,
* **processus à processus** - résultant de (dé)sérialisation et du traitement des données dans le client/serveur.

Edgegap réduit la latence physique en plaçant des serveurs plus proches de vos joueurs pour des réponses plus courtes et un nombre réduit de sauts réseau. Avec des emplacements chez 17 fournisseurs cloud et bare metal, vous obtenez **un ping de classe mondiale pour les joueurs partout dans le monde**.

La couverture serveur et Internet au niveau mondial (pas seulement avec Edgegap) est limitée en raison de facteurs tels que :

* **disponibilité de l'infrastructure** - la qualité de la connexion Internet dans une région donnée peut ne pas être suffisante,
* **facteurs naturels** - des racks de serveurs très complexes nécessitent un environnement principalement stable.

#### Haute disponibilité

La disponibilité des serveurs dans divers emplacements du monde varie au fil du temps, changeant plusieurs fois au cours de la journée. Edgegap **met à l'échelle automatiquement** les emplacements **à la demande**, en tenant compte de :

* **trafic d'explosion** - déploiements effectués sur une période de 15 minutes,
* **exigences vCPU** - plus de vCPU par déploiement augmente la demande globale pour un emplacement spécifique,
* **offre du fournisseur** - certains emplacements distants ont moins d'options de fournisseurs disponibles,
* **disponibilité des machines** - certains emplacements peuvent n'offrir que des machines 4 vCPU ou 8 vCPU,
* **demandes du studio** pour les tests, assurance qualité, accès anticipé, bêtas fermées ou tournois.

Toutes les requêtes de déploiement des applications sont combinées pour évaluer la demande par emplacement. Toutes les organisations ont une priorité d'allocation égale par défaut, avec la **possibilité d'ajouter des pools de serveurs privés pour les clients entreprise nécessitant du matériel ou des emplacements spécifiques**.

{% hint style="success" %}
Veuillez **nous contacter pour planifier une sortie**, ou si vous avez des demandes concernant la disponibilité des emplacements.
{% endhint %}

#### Résolution des problèmes des joueurs

Les problèmes des joueurs peuvent provenir de bogues serveurs ou d'incidents chez le fournisseur, mais peuvent aussi provenir de tiers tels que des FAI locaux, des services de jeu, des bugs dans des bibliothèques bas niveau, des fournisseurs d'infrastructure ou d'autres sources.

Lors du dépannage des rapports de joueurs ou des incidents, considérez les facteurs :

* **qualité du matchmaking** - les joueurs devraient être proches les uns des autres (même région) pour [#server-placement](#server-placement "mention") obtenir les meilleurs résultats :
  * voir [matchmaking](https://docs.edgegap.com/learn/matchmaking "mention") et [ping-beacons](https://docs.edgegap.com/learn/orchestration/ping-beacons "mention") pour nos recommandations,
  * voir [#player-tracing](https://docs.edgegap.com/matchmaking/matchmaker-in-depth#player-tracing "mention") pour apprendre comment trouver les logs serveur liés aux rapports des joueurs,
* **problèmes régionaux :**
  * des fournisseurs d'accès Internet (FAI) locaux peuvent résoudre un incident momentanément,
  * certaines régions (p. ex. Chine, Russie) peuvent être restreintes en raison de sanctions localisées,
* **niveau de mise en cache** - Edgegap priorisera les déploiements rapides dans les emplacements mis en cache :
  * [activez la mise en cache pour déployer vos serveurs en quelques secondes](https://docs.edgegap.com/learn/application-and-versions#other-parameters-optional),
* **temps maximal de déploiement** - les déploiements peuvent échouer en raison d'un processus d'initialisation lent et lourd :
  * voir [#safety-guardrails](https://docs.edgegap.com/learn/application-and-versions#safety-guardrails "mention") pour augmenter la période de timeout,
  * retarder les étapes d'initialisation jusqu'à ce qu'elles soient absolument nécessaires,
* **problèmes d'image serveur ou d'intégration**.

{% hint style="success" %}
**Afficher les IDs de déploiement dans l'interface d'historique des matchs du client** pour tracer les rapports des joueurs lors du dépannage.
{% endhint %}

{% hint style="info" %}
Informez les utilisateurs des bugs généralisés, des problèmes temporaires et des pannes pour atténuer le sentiment négatif.
{% endhint %}

## 🔄 Cycle de vie du déploiement

Les déploiements Edgegap passent par plusieurs étapes de cycle de vie, indiquées par le statut du déploiement.

#### 1. Démarrer un déploiement

Un déploiement à des fins **de test** peut être démarré avec :

* [unreal-engine](https://docs.edgegap.com/unreal-engine "mention") - Extension Docker ou plugin pour projets Unreal Engine,
* [unity](https://docs.edgegap.com/unity "mention") - plugin pour projets Unity,
* [Interface Web du tableau de bord](https://app.edgegap.com/deployment-management/deployments/list) - interface web facile à utiliser pour tester l'intégration serveur.

Un déploiement à des fins **l'environnement de production en direct** devrait être démarré avec :

* [matchmaking](https://docs.edgegap.com/learn/matchmaking "mention") - trouver d'autres joueurs et démarrer des serveurs à la demande ([#match-bound](#match-bound "mention")).
* [navigateur-de-serveurs](https://docs.edgegap.com/learn/navigateur-de-serveurs "mention") - pré-chauffer les serveurs avec une initialisation longue ([#regional-standby](#regional-standby "mention")).
* [Deploy API](https://docs.edgegap.com/api/#tag/Deployments/operation/deploy) - intégration personnalisée serveur-à-serveur (mise à l'échelle personnalisée).

{% hint style="success" %}
**Enregistrer** `request_id`  **(ID de déploiement) et taguer les déploiements** pour identifier et dépanner les problèmes plus tard.
{% endhint %}

{% hint style="info" %}
Lors des tests avec [Deploy API](https://docs.edgegap.com/api/#tag/Deployments/operation/deploy), vous pouvez remplacer la Dockerfile par défaut `CMD` par une commande personnalisée.
{% endhint %}

#### 2. Déploiement en cours

Une fois un déploiement démarré, notre système effectuera un certain nombre d'étapes en rapide succession :

* Télémétrie - nous mesurons la réactivité réseau depuis les centres de données disponibles vers chaque joueur,
* Déploiement - nous réservons la capacité et préparons le démarrage de votre conteneur serveur,
* Démarrage du conteneur - nous démarrons le conteneur, installons les dépendances et initialisons,
* Post-traitement - nous ajoutons le stockage des logs, la surveillance et finalisons le déploiement.

{% hint style="warning" %}
**Trop de requêtes 429** - pour assurer la stabilité et prévenir des factures surprises, nous limitons le débit de votre organisation à **40 req/s**. [Contactez-nous](mailto:info@edgegap.com) pour planifier des sorties, estimer le trafic de lancement et préparer le succès.
{% endhint %}

#### 3. Déploiement prêt

Votre conteneur est entièrement initialisé et votre serveur démarre maintenant. Pendant quelques secondes à une minute, votre serveur peut encore s'initialiser et peut ne pas répondre aux demandes des joueurs jusqu'à ce que votre moteur de jeu (ou runtime personnalisé) soit entièrement prêt à accepter les connexions des joueurs.

{% hint style="success" %}
Une fois le déploiement prêt, **réessayez la connexion du joueur jusqu'à réussite**, ou jusqu'au timeout client prédéfini.
{% endhint %}

#### 4. Erreur de déploiement

Votre déploiement peut passer en état Erreur à tout moment, pour des raisons inattendues. Cela est plus susceptible de se produire lors des tests de votre intégration ou de nouvelles builds serveur.

**Vous n'êtes pas facturé pour les déploiements en Erreur, qui sont automatiquement arrêtés après 24 heures.**

Étapes de dépannage :

* Vérifiez le statut du service Edgegap avec [notre page de surveillance de disponibilité](https://status.edgegap.com/).
* Essayez de tester votre conteneur serveur localement en utilisant Docker Desktop pour exclure les problèmes Edgegap.

{% hint style="success" %}
**Lorsque vous demandez de l'aide,** **incluez votre ID de déploiement et tous les détails utiles** afin que nous puissions enquêter rapidement !
{% endhint %}

#### 5. Déploiement arrêté

**Nous n'arrêtons jamais vos serveurs sans votre directive**, pour éviter d'impacter négativement l'expérience de vos joueurs. Votre déploiement peut être arrêté pour ces raisons :

* **Arrêt automatique via** [**DELETE\_URL**](#injected-environment-variables) - déploiement arrêté de lui-même après le départ des joueurs et la fin du match,
  * voir [Unreal Engine](https://docs.edgegap.com/unreal-engine#stop-deployments) et [Unity](https://docs.edgegap.com/unity#stop-deployments) guides pour arrêter correctement les déploiements,
* **Arrêt depuis votre backend** - votre backend a arrêté ce déploiement en utilisant [l'API Deployments](https://docs.edgegap.com/api/#tag/Deployments/operation/deployment-delete),
* **Durée maximale du jeu** - le temps alloué dans votre [#safety-guardrails](https://docs.edgegap.com/learn/application-and-versions#safety-guardrails "mention") a expiré,
* [flottes-privees](https://docs.edgegap.com/learn/orchestration/flottes-privees "mention") L'hôte exécutant votre déploiement a été supprimé via une action planifiée.

{% hint style="info" %}
Une fois un déploiement arrêté, **nous déclenchons une terminaison en douceur** en envoyant `SIGTERM` signal à votre processus principal, permettant une courte période de terminaison. Une fois expirée, un `SIGKILL` signal est envoyé pour arrêter le déploiement.
{% endhint %}

## 👀 Observabilité

Permettez aux serveurs de jeu d'interopérer avec des tiers et obtenez des informations opérationnelles.

### Découvrabilité

Une fois prêt, le déploiement se voit attribuer une URL ([fqdn](https://en.wikipedia.org/wiki/Fully_qualified_domain_name)) et un port externe pour chaque port interne.

{% hint style="success" %}
Utilisez **les tags de déploiement pour marquer facilement vos déploiements** et [#filter-deployments](#filter-deployments "mention").
{% endhint %}

{% hint style="info" %}
**Le trafic sortant (vers les clients ou le backend) depuis vos serveurs de jeu n'est jamais bloqué** ou filtré.
{% endhint %}

#### **Websockets (WS) et Websockets sécurisés (WSS)**

Pour utiliser un netcode basé sur websocket avec Edgegap, vous avez deux options :

* **certificat géré**, configuré en 1 minute sans écrire de code :
  * configurez votre [application-and-versions](https://docs.edgegap.com/learn/orchestration/application-and-versions "mention") vers **utilisez Websocket (WS) et activez la montée en TLS,**
  * utilisez l'URL Edgegap pour connecter les clients (p. ex. `https://5fa53fa00a57.pr.edgegap.net/`)
* **certificat auto-géré**, si vous souhaitez utiliser votre propre domaine personnalisé :
  * configurez votre [application-and-versions](https://docs.edgegap.com/learn/orchestration/application-and-versions "mention") vers **utilisez Secure Websocket (WSS)**,
  * configurez votre propre flux de certificat TLS avec un enregistrement DNS personnalisé (p. ex. sur [Cloudflare](https://www.cloudflare.com/application-services/products/ssl/)).

{% hint style="danger" %}
Les exceptions serveur non interceptées provoqueront le redémarrage du conteneur du déploiement et invalideront la sécurité TLS. Dans ce cas, [arrêtez votre serveur](#id-5.-deployment-stopped) et [réaffectez les joueurs à un nouveau déploiement](https://docs.edgegap.com/matchmaking#custom-lobby). [L'état du serveur peut être perdu](https://docs.edgegap.com/learn/persistance#state-management).
{% endhint %}

### Variables injectées <a href="#injected-environment-variables" id="injected-environment-variables"></a>

Les serveurs de jeu ont souvent besoin d'informations supplémentaires, telles que l'IP du serveur, les valeurs de ports internes ou autres. Injecter des variables d'environnement en lecture seule est un moyen fiable et agnostique au cloud de transmettre des paramètres.

{% hint style="success" %}
Obtenez les valeurs des variables en utilisant [GetEnvironmentVariable en C#](https://learn.microsoft.com/en-us/dotnet/api/system.environment.getenvironmentvariable?view=net-8.0) ou [GetEnvironmentVariable en C++](https://dev.epicgames.com/documentation/en-us/unreal-engine/API/Runtime/Core/GenericPlatform/FGenericPlatformMisc/GetEnvironmentVariable).
{% endhint %}

{% hint style="info" %}
Voir [Variables de version d'app](https://docs.edgegap.com/learn/application-and-versions#injected-variables) et [Variables du Matchmaker](https://docs.edgegap.com/matchmaking/matchmaker-in-depth#injected-variables) en plus des variables de déploiement ci-dessous.
{% endhint %}

#### **Variables personnalisées**

Définissez jusqu'à 20 variables personnalisées pour chaque déploiement, chacune contenant jusqu'à 4 Ko de données string.

{% hint style="warning" %}
**Évitez d'utiliser les noms réservés (ci-dessous), vos variables personnalisées seront autrement écrasées !**
{% endhint %}

Accédez aux informations importantes en lisant les variables injectées dans vos serveurs par Edgegap :

#### **Identifiants**

* **`ARBITRIUM_REQUEST_ID`**  - p. ex. `f68e011bfb01` .
  * ID de déploiement unique, également appelé ID de requête. Utilisé pour récupérer plus d'informations.
  * Les URL de déploiement ont toujours le format `{ARBITRIUM_REQUEST_ID}.pr.edgegap.net`.
* **`ARBITRIUM_PUBLIC_IP`**  - p. ex. `162.254.141.66` .
  * Adresse IP publique de cet hôte, peut être utilisée pour se connecter à la place de l'URL.
* **`ARBITRIUM_HOST_ID`**  - p. ex. `alpha-north-america-70364ef8` .
  * Identifiant unique de la machine hébergeant votre déploiement, partagé avec d'autres déploiements.
* **`ARBITRIUM_DEPLOYMENT_TAGS`**  - p. ex. `tag1,tag2` .
  * Tags de déploiement définis par l'utilisateur, délimités par des virgules, [utiles pour une recherche et un filtrage faciles](#filter-deployments).
* **`ARBITRIUM_PRIVATE_FLEET_ID`** - p. ex. `PUBLIC_CLOUD` , ou ID de flotte si hébergé sur [flottes-privees](https://docs.edgegap.com/learn/orchestration/flottes-privees "mention").

#### Spécifications des ressources

* **`ARBITRIUM_HOST_IN_PRIVATE_FLEET`** - p. ex. `false` , indiquant si hébergé sur [flottes-privees](https://docs.edgegap.com/learn/orchestration/flottes-privees "mention").
* **`ARBITRIUM_HOST_BASE_CLOCK_FREQUENCY`**  - p. ex. `2000` , fréquence du processeur en MHz.
* **`ARBITRIUM_DEPLOYMENT_VCPU_UNITS`**  - p. ex. `256`, unités vCPU allouées (1024 = 1 vCPU).
* **`ARBITRIUM_DEPLOYMENT_MEMORY_MB`**  - p. ex. `512`, RAM allouée en Mo (1024 = 1 Go).

#### **Gestion du cycle de vie**

* **`ARBITRIUM_DELETE_URL`**  - p. ex. `https://api.edgegap.com/v1/self/stop/9f511e17/660`.
  * Appelable depuis le déploiement, [le déploiement sera arrêté proprement](#id-5.-deployment-stopped).
  * Nécessite un `jeton de suppression ARBITRIUM_DELETE_TOKEN unique et à usage unique` dans `l'en-tête` Authorization
* **`jeton de suppression ARBITRIUM_DELETE_TOKEN unique et à usage unique`**  - p. ex. `7df4cd933df87084b34ae80d8abde293`.
* **`ARBITRIUM_CONTEXT_URL`**  - p. ex. `https://api.edgegap.com/v1/context/9170f5211e17/17`.
  * Appelable uniquement depuis le déploiement, renvoie plus de détails sur le déploiement.
  * Nécessite un `jeton de contexte ARBITRIUM_CONTEXT_TOKEN unique` dans `l'en-tête` Authorization
* **`jeton de contexte ARBITRIUM_CONTEXT_TOKEN unique`**  - p. ex. `dfaf50b9333b9ee07b22ed247e4a17e6`.

#### **Découvrabilité**

* **`ARBITRIUM_PORT_GAMEPORT_INTERNAL`**  - p. ex. `7777` , port interne pour l'écoute du serveur.
* **`ARBITRIUM_PORT_GAMEPORT_EXTERNAL`**  - p. ex. `31504` , port externe pour les connexions clients.
  * Les valeurs des ports externes sont randomisées pour chaque déploiement pour des raisons de sécurité.
* **`ARBITRIUM_PORT_GAMEPORT_PROTOCOL`**  - p. ex. `UDP` , protocole de votre transport netcode.

{% hint style="success" %}
Les exemples supposent que vous avez nommé votre port `gameport` (par défaut). **Chaque port ajoute un ensemble supplémentaire de** [#port-mapping](https://docs.edgegap.com/learn/application-and-versions#port-mapping "mention") **variables assainies :** `@Super Port!` ⇒ `ARBITRIUM_PORT_SUPER_PORT_INTERNAL` .
{% endhint %}

* **`ARBITRIUM_BEACON_ENABLED`**  - p. ex. `true`, si déployé sur [flottes-privees](https://docs.edgegap.com/learn/orchestration/flottes-privees "mention") avec [ping-beacons](https://docs.edgegap.com/learn/orchestration/ping-beacons "mention").
* **`ARBITRIUM_HOST_BEACON_PUBLIC_IP`**  - p. ex. `139.177.198.69` , IP publique du beacon le plus proche.
* **`ARBITRIUM_HOST_BEACON_PORT_UDP_EXTERNAL`**  - p. ex. `30199`, pour la mesure du ping via UDP.
* **`ARBITRIUM_HOST_BEACON_PORT_TCP_EXTERNAL`**  - p. ex. `30456`, pour la mesure du ping via TCP.

#### **Information structurée (JSON en tant que chaîne)**

{% hint style="info" %}
Les variables d'environnement sont **stockées comme des JSON stringifiés**, analysez-les en utilisant un SDK ou une méthode personnalisée.
{% endhint %}

<details>

<summary><strong>ARBITRIUM_DEPLOYMENT_LOCATION</strong>:<br>- Informations détaillées sur l'emplacement du déploiement.</summary>

```json
ARBITRIUM_DEPLOYMENT_LOCATION="{
  "city": "Montréal",
  "country": "Canada",
  "continent": "Amérique du Nord",
  "administrative_division": "Québec",
  "timezone": "Heure de l'Est",
  "latitude": 45.513707,
  "longitude": -73.619073
}"
```

</details>

<details>

<summary><strong>ARBITRIUM_PORTS_MAPPING</strong>:<br>- Informations détaillées sur vos ports internes et externes.</summary>

```json
ARBITRIUM_PORTS_MAPPING="{
  "ports": {
    "gameport": {
      "name": "Port de jeu",
      "internal": 7777,
      "external": 31504,
      "protocol": "UDP"
    },
    "webport": {
      "name": "Port Web",
      "internal": 8888,
      "external": 31553,
      "protocol": "TCP"
    }
  }
}"
```

</details>

### Surveillance du tableau de bord

Notre [Tableau de bord](https://app.edgegap.com/) fournit des outils pour surveiller l'évolutivité de votre serveur et aider aux opérations.

#### Analytique

{% hint style="success" %}
Trouvez [des tableaux de bord analytiques dans le menu latéral](https://app.edgegap.com/analytics/dashboards/list) sous la catégorie Hébergement et orchestration de serveur.
{% endhint %}

:star2: [**Passez au niveau Paiement à l'utilisation**](https://app.edgegap.com/user-settings?tab=memberships) **pour débloquer des métriques et des informations détaillées sur les performances du serveur :**

* **Aperçus généraux :** surveillez les versions avec le nombre de serveurs en direct par version + aperçu de l'utilisation des ressources,
* **Aperçu CPU** : dépannez les serveurs ralentis par des opérations intensives du processeur,
* **Aperçu Mémoire** : atténuez les redémarrages de serveur dus au dépassement de la mémoire allouée,
* **Aperçus Réseau :** détectez les modèles réseau inefficaces et optimisez le netcode.

<figure><img src="https://3008966946-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2FLxDp1yFvkj5kB6AC4xVb%2Fimage.png?alt=media&#x26;token=c0eff5f1-a374-41e0-a49a-9b3ecf0bfd1b" alt=""><figcaption></figcaption></figure>

#### Carte de déploiement

{% hint style="success" %}
Trouvez la carte de déploiement dans [la page de détails de votre déploiement sur le tableau de bord](https://app.edgegap.com/deployment-management/deployments/list).
{% endhint %}

Aperçu de l'emplacement du déploiement, des emplacements disponibles et des emplacements estimés des joueurs sur la carte :

<figure><img src="https://3008966946-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2FM4h0itPU5ntPaV5N5ZlW%2Fimage.png?alt=media&#x26;token=98028901-9a40-4a2d-969e-db5f990e334f" alt=""><figcaption></figcaption></figure>

#### Points d'équilibre de déploiement

{% hint style="success" %}
Trouvez la carte thermique des points d'équilibre de déploiement dans [la page de détails de votre application sur le tableau de bord](https://app.edgegap.com/application-management/applications/list).
{% endhint %}

Aperçu de la carte thermique des points d'équilibre de déploiement et filtrage par [application-and-versions](https://docs.edgegap.com/learn/orchestration/application-and-versions "mention"). Les points d'équilibre sont des emplacements approximatifs ayant une proximité réseau égale à chaque joueur dans un déploiement donné :

<figure><img src="https://3008966946-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2FfDpIQxoFUJZNE77LJIwZ%2Fimage.png?alt=media&#x26;token=94e730ad-3907-486b-8a06-0f469acd19ea" alt=""><figcaption></figcaption></figure>

{% hint style="warning" %}
Des points d'équilibre fréquents dans des emplacements étranges (par ex. le Groenland) indiquent un matchmaking de joueurs éloignés les uns des autres. En savoir plus sur [#connection-quality](#connection-quality "mention") et [ping-beacons](https://docs.edgegap.com/learn/orchestration/ping-beacons "mention") pour optimiser votre matchmaking.
{% endhint %}

#### Journaux de déploiement

{% hint style="success" %}
Trouvez les journaux de déploiement dans [la page de détails de votre déploiement sur le tableau de bord](https://app.edgegap.com/deployment-management/deployments/list).
{% endhint %}

Les journaux de déploiement affichent des informations sur [#deployment-lifecycle](#deployment-lifecycle "mention"):

<figure><img src="https://3008966946-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2FfkyAYtylnOFmSp3yyiId%2Fimage.png?alt=media&#x26;token=6a4f6ac4-5780-46a7-bcdd-1d8829c4abd7" alt=""><figcaption></figcaption></figure>

#### Journaux de conteneur

{% hint style="success" %}
Trouvez les journaux de conteneur dans [la page de détails de votre déploiement sur le tableau de bord](https://app.edgegap.com/deployment-management/deployments/list).
{% endhint %}

Inspectez les journaux de votre serveur de jeu en cas de problèmes ou lors du débogage :

<figure><img src="https://3008966946-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2FTiaARmb6aAZfm0rjQmiT%2Fimage.png?alt=media&#x26;token=7eb49138-954d-44a1-a025-1f88ed855366" alt=""><figcaption></figcaption></figure>

{% hint style="warning" %}
**Une fois le déploiement arrêté, les journaux de conteneur sont supprimés.** Configurez [un stockage S3 tiers pour les journaux](https://docs.edgegap.com/docs/endpoint-storage) pour sauvegarder les journaux.
{% endhint %}

#### Métriques de conteneur

{% hint style="success" %}
Trouvez les métriques de conteneur dans [la page de détails de votre déploiement sur le tableau de bord](https://app.edgegap.com/deployment-management/deployments/list).
{% endhint %}

Examinez les métriques de conteneur (processeur, mémoire, réseau) pour :

* identifier les problèmes de connexion courants lorsque [#troubleshooting](#troubleshooting "mention"),
* détecter des schémas d'implémentation inefficaces causant des pics d'utilisation des ressources,
* localiser une utilisation inefficace des ressources dans des scénarios particuliers,
* vérifier les changements dans l'utilisation des ressources de votre serveur lors de l'optimisation,
* mesurer la consommation et la durée des ressources lors de l'initialisation de votre serveur.

Les métriques historiques affichent des moyennes de valeur avec une période de 1 minute, disponibles dans le niveau Gratuit.

:star2: [**Passez au niveau Paiement à l'utilisation**](https://app.edgegap.com/user-settings?tab=memberships) **pour débloquer des métriques précises avec des intervalles de 1 seconde.**

<figure><img src="https://3008966946-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2FoIpCR3x9ibiXMEIWFgKG%2Fimage.png?alt=media&#x26;token=86dcd914-db9f-4e81-8444-6c83805be9b6" alt=""><figcaption></figcaption></figure>

{% hint style="info" %}
[Contactez-nous](mailto:info@edgegap.com) avant votre sortie pour demander une assistance d'hébergement en direct pour des sorties à grande échelle.
{% endhint %}

### Contexte et statut

Des informations supplémentaires sur le déploiement peuvent être récupérées au format JSON :

* depuis l'intérieur du déploiement (serveur de jeu), en utilisant [API de contexte de déploiement](https://docs.edgegap.com/api/#tag/Context/operation/context-get),
* depuis l'extérieur du déploiement (backend / tiers), en utilisant [API d'état de déploiement](https://docs.edgegap.com/api/#tag/Deployments/operation/deployment-status-get).

{% hint style="info" %}
L'API Context (depuis le déploiement) nécessite un jeton Context API, tandis que l'API Status utilise votre jeton Edgegap.
{% endhint %}

{% hint style="warning" %}
**Trop de requêtes 429** - nous limitons le débit de votre organisation à **20 req/s** pour les points de terminaison des API Context et Status. Utilisez [#injected-environment-variables](#injected-environment-variables "mention") et [Webhooks](https://docs.edgegap.com/docs/deployment/arbitrium-deploy-webhook) pour une solution évolutive.
{% endhint %}

### Filtrer les déploiements

Pour rechercher rapidement parmi tous les déploiements, vous pouvez [utiliser notre tableau de bord](https://app.edgegap.com/deployment-management/deployments/list):

<figure><img src="https://3008966946-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2F42IaKG0pFQXSkvPCRH1T%2Fimage.png?alt=media&#x26;token=6aba8781-13c9-4c0f-87e9-2d9612a57342" alt=""><figcaption></figcaption></figure>

[Lister les déploiements avec l'API](https://docs.edgegap.com/api/#tag/Deployments/operation/deployments-get) et appliquer des filtres avec des intégrations backend :

<table><thead><tr><th width="237">Attribut de déploiement</th><th width="193">Opérateurs</th><th>Valeur exemple</th></tr></thead><tbody><tr><td><a href="#deployment-lifecycle"><code>statut</code></a></td><td><a data-footnote-ref href="#user-content-fn-2"><code>eq</code></a>  ou <a data-footnote-ref href="#user-content-fn-3"><code>neq</code></a></td><td><code>"ready"</code> ou <code>"error"</code></td></tr><tr><td><a href="#observability"><code>request_id</code></a></td><td><a data-footnote-ref href="#user-content-fn-2"><code>eq</code></a> </td><td><a data-footnote-ref href="#user-content-fn-4"><code>"7e709a0d8efd"</code></a></td></tr><tr><td></td><td><a data-footnote-ref href="#user-content-fn-5"><code>dans</code></a>  ou <a data-footnote-ref href="#user-content-fn-6"><code>nin</code></a></td><td><a data-footnote-ref href="#user-content-fn-4"><code>[ "7e709a0d8efd", "4ba353100b4b" ]</code></a></td></tr><tr><td><a href="#discoverability"><code>étiquettes</code></a></td><td><a data-footnote-ref href="#user-content-fn-2"><code>eq</code></a>  ou <a data-footnote-ref href="#user-content-fn-3"><code>neq</code></a></td><td><code>"tagA"</code></td></tr><tr><td></td><td><a data-footnote-ref href="#user-content-fn-5"><code>dans</code></a>  ou <a data-footnote-ref href="#user-content-fn-6"><code>nin</code></a></td><td><code>[ "tagA", "tagB" ]</code></td></tr><tr><td><a href="#id-1.-start-a-deployment"><code>created_at</code></a></td><td><a data-footnote-ref href="#user-content-fn-2"><code>eq</code></a>  ou <a data-footnote-ref href="#user-content-fn-7"><code>lte</code></a>  ou <a data-footnote-ref href="#user-content-fn-8"><code>gte</code></a></td><td><a href="https://en.wikipedia.org/wiki/ISO_8601"><code>2025-05-12T20:03:20Z</code></a></td></tr><tr><td><a href="application-and-versions"><code>application</code></a></td><td><a data-footnote-ref href="#user-content-fn-2"><code>eq</code></a>  ou <a data-footnote-ref href="#user-content-fn-3"><code>neq</code></a></td><td><code>"my-app"</code></td></tr><tr><td></td><td><a data-footnote-ref href="#user-content-fn-5"><code>dans</code></a>  ou <a data-footnote-ref href="#user-content-fn-6"><code>nin</code></a></td><td><code>[ "my-app", "my-other-app" ]</code></td></tr><tr><td><a href="application-and-versions"><code>version</code></a></td><td><a data-footnote-ref href="#user-content-fn-2"><code>eq</code></a>  ou <a data-footnote-ref href="#user-content-fn-3"><code>neq</code></a></td><td><code>"1.0.0"</code></td></tr><tr><td></td><td><a data-footnote-ref href="#user-content-fn-9"><code>dans</code></a>  ou <a data-footnote-ref href="#user-content-fn-6"><code>nin</code></a></td><td><code>[ "1.0.0", "prod" ]</code></td></tr><tr><td><a href="../../docs/session"><code>is_joinable_by_session</code></a></td><td><a data-footnote-ref href="#user-content-fn-2"><code>eq</code></a> </td><td><code>true</code> ou <code>false</code></td></tr><tr><td><a href="../../docs/session"><code>available_session_sockets</code></a></td><td><p><a data-footnote-ref href="#user-content-fn-2"><code>eq</code></a>  ou <a data-footnote-ref href="#user-content-fn-3"><code>neq</code></a>  ou </p><p><a data-footnote-ref href="#user-content-fn-10"><code>lt</code></a>  ou <a data-footnote-ref href="#user-content-fn-7"><code>lte</code></a> ou </p><p><a data-footnote-ref href="#user-content-fn-11"><code>gt</code></a>  ou <a data-footnote-ref href="#user-content-fn-8"><code>gte</code></a>  </p></td><td><code>5</code></td></tr></tbody></table>

{% hint style="info" %}
Chaque attribut peut avoir au plus 1 opérateur de filtre dans une seule requête. Voir [api](https://docs.edgegap.com/docs/api "mention") pour plus d'informations.
{% endhint %}

Triez les résultats par plusieurs champs dans l'ordre dans lequel ils apparaissent dans la requête :

| Attribut de déploiement                                              | Ordre                                                                   |
| -------------------------------------------------------------------- | ----------------------------------------------------------------------- |
| [`created_at`](#id-1.-start-a-deployment)                            | [`asc`](#user-content-fn-12)[^12] ou [`desc`](#user-content-fn-13)[^13] |
| [`available_session_sockets`](https://docs.edgegap.com/docs/session) | [`asc`](#user-content-fn-14)[^14] ou [`desc`](#user-content-fn-15)[^15] |

Exemples de requêtes de filtrage :

<details>

<summary>Lister <a href="#id-4.-deployment-error">Déploiements en erreur</a> pour dépanner et supprimer.</summary>

URL encodée :

```
https://api.edgegap.com/v1/deployments?query={"filters":[{"field":"status","operator":"eq","value":"error"},{"field":"application","operator":"eq","value":"my-app"},{"field":"version","operator":"eq","value":"green"}],"order_by":[{"field":"created_at","order":"desc"}]}
```

Requête JSON formatée :

```json
{
  "filters": [
    {
      "field": "status",
      "operator": "eq",
      "value": "error"
    },
    {
      "field": "application",
      "operator": "eq",
      "value": "my-app"
    },
    {
      "field": "version",
      "operator": "eq",
      "value": "green"
    }
  ],
  "order_by": [
    {
      "field": "created_at",
      "order": "desc"
    }
  ]
}
```

</details>

<details>

<summary>Lister <a href="../../matchmaking/matchmaker-in-depth#rolling-updates-and-ab-tests">Déploiements avec version d'application obsolète</a> pour confirmer qu'une sortie est complète.</summary>

URL encodée :

```
https://api.edgegap.com/v1/deployments?query={"filters":[{"field":"status","operator":"eq","value":"ready"},{"field":"application","operator":"eq","value":"my-app"},{"field":"version","operator":"eq","value":"blue"}],"order_by":[{"field":"created_at","order":"desc"}]}
```

Requête JSON formatée :

```json
{
  "filters": [
    {
      "field": "status",
      "operator": "eq",
      "value": "ready"
    },
    {
      "field": "application",
      "operator": "eq",
      "value": "my-app"
    },
    {
      "field": "version",
      "operator": "eq",
      "value": "blue"
    }
  ],
  "order_by": [
    {
      "field": "created_at",
      "order": "desc"
    }
  ]
}
```

</details>

{% hint style="success" %}
N'oubliez pas d'ajouter l' `l'en-tête` en-tête avec votre jeton API Edgegap dans la requête.
{% endhint %}

### Webhooks et Postbacks

Recevez de simples notifications HTTP dans votre backend de jeu pour les changements de [#deployment-lifecycle](#deployment-lifecycle "mention") en spécifiant une URL de webhook dans votre [requête API de déploiement](https://docs.edgegap.com/api/#tag/Deployments/operation/deploy). Disponible pour :

* À la mise en Ready : le conteneur de déploiement [a démarré avec succès](#id-1.-start-a-deployment) (le serveur commence l'initialisation après cela),
* En cas d'erreur : le déploiement n'a pas pu démarrer et une [#id-4.-deployment-error](#id-4.-deployment-error "mention") s'est produite,
* À l'arrêt : [#id-5.-deployment-stopped](#id-5.-deployment-stopped "mention") et le serveur de jeu n'est plus accessible.

Les webhooks Ready et Error ne seront jamais déclenchés pour le même déploiement.

<details>

<summary>Exemple de payload de webhook</summary>

```json
{
  "request_id": "f68e011bfb01",
  "application": "my-game-server",
  "version": "2024.01.30-16.23.00-UTC",
  "fqdn": "f68e011bfb01.pr.edgegap.net",
  "public_ip": "162.254.141.66",
  "deployed_at": "2026-02-10T20:35:48Z",
  "termination_scheduled_at": "2026-02-10T21:35:48Z",
  "ports": {
    "gameport": {
      "external": 31504,
      "internal": 7777,
      "protocol": "UDP",
      "name": "gameport",
      "tls_upgrade": false,
      "link": "f68e011bfb01.pr.edgegap.net:31504",
      "proxy": null
    }
  },
  "location": {
    "city": "Montréal",
    "country": "Canada",
    "continent": "Amérique du Nord",
    "administrative_division": "Québec",
    "timezone": "Heure de l'Est",
    "latitude": 45.513707,
    "longitude": -73.619073
  },
  "tags": [
    "tag1",
    "tag2"
  ],
  "host_id": "alpha-north-america-70364ef8",
  "host_in_private_fleet": false,
  "private_fleet_id": "PUBLIC_CLOUD",
  "vcpu_units": 256,
  "memory_mib": 512
}
```

</details>

{% hint style="warning" %}
**Les webhooks ne sont pas réessayés**, donc si votre backend ne traite pas la requête en raison d'une limitation de débit ou d'une erreur, le webhook peut être perdu. Utilisez les webhooks uniquement pour **des cas d'utilisation non critiques ou à des fins de débogage**.
{% endhint %}

{% hint style="info" %}
Les webhooks observent le cycle de vie du déploiement, mais ne connaissent pas l'état d'initialisation de votre scène/niveau. Pour observer la progression du chargement de votre scène/niveau, implémentez un webhook personnalisé dans votre serveur de jeu.
{% endhint %}

## 🚨 Dépannage

Lors du dépannage des déploiements :

1. vérifiez qu'il n'y a pas d'erreurs dans votre [#deployment-logs](#deployment-logs "mention") et [#container-logs](#container-logs "mention"),
2. exécutez votre serveur localement pour écarter les bugs d'intégration,
3. consultez les étapes de dépannage sur cette page,
4. contactez-nous sur [Discord Communautaire](https://discord.gg/MmJf8fWjnt) et incluez votre ID de déploiement.

{% hint style="info" %}
Voir [#player-issue-resolution](#player-issue-resolution "mention") pour nos recommandations sur la gestion des retours de la communauté de joueurs.
{% endhint %}

<details>

<summary>Impossible de connecter les clients au serveur - <code>La requête a expiré.</code>, <code>请求超时</code> , <code>Échec de connexion</code> , ou <code>La vérification du port a échoué</code>.</summary>

* Tout d'abord, assurez-vous que le déploiement est Ready et qu'il n'y a pas d'exceptions d'exécution ou d'erreurs dans votre journal de déploiement. Si votre déploiement s'est arrêté, inspectez les journaux dans notre [Tableau de bord](https://app.edgegap.com/deployment-management/deployments/list).
* Si vous utilisez le netcode Mirror, vous devez avoir ["Démarrage automatique du serveur"](https://mirror-networking.gitbook.io/docs/hosting/edgegap-hosting-plugin-guide#build-and-push) sélectionné dans votre `NetworkManager` , recompilez, poussez et redéployez votre serveur.
* Si vous utilisez le netcode FishNet, vous devez activer [« Démarrer en mode Headless »](https://fish-networking.gitbook.io/docs/manual/components/managers/server-manager#settings-are-general-settings-related-to-the-servermanager) dans votre `ServerManager`, recompilez, poussez et redéployez votre serveur.
* Si vous utilisez le netcode Photon Fusion 2, assurez-vous que votre serveur transmet l'IP publique du déploiement, le port externe et le `roomCode` sur le serveur, et le même code de salle dans le client dans le [paramètre « NeworkRunner.StartGame »](https://doc.photonengine.com/fusion/current/manual/network-runner#creating-or-joining-a-room) paramètre `StartGameArgs`. L'ID de déploiement (par ex. `b63e6003b19f`) est un excellent choix car il est unique globalement et facilement accessible au client par [Matchmaker](https://docs.edgegap.com/learn/matchmaking/matchmaker-in-depth) assignation et au [#injected-environment-variables](https://docs.edgegap.com/matchmaking/matchmaker-in-depth#injected-environment-variables "mention").
* Ensuite, vérifiez que votre paramètre de port dans les paramètres netcode de votre build serveur correspond au port interne dans votre [Version de l'application](https://app.edgegap.com/application-management/applications/list). Vous pouvez modifier le mappage de port en éditant le [Version de l'application](https://app.edgegap.com/application-management/applications/list) sans recompiler. Trouvez votre protocole dans votre intégration netcode.
* Veuillez vous assurer que votre client de jeu se connecte au **port externe** affiché sur la page de détails de votre déploiement, cette valeur sera toujours randomisée pour des raisons de sécurité.
* Si vous utilisez le protocole Secure Websocket (WSS) dans votre intégration netcode, assurez-vous que [Version de l'application](https://app.edgegap.com/application-management/applications/list) la configuration du port pour le port WSS a l'option de mise à niveau TLS activée.
* Êtes-vous situé en Chine et utilisez-vous [Smart Fleets](https://docs.edgegap.com/docs/deployment/session/fleet-manager/fleet) ? Votre connexion peut être bloquée par le Grand Firewall. Envisagez d'ajouter un serveur situé en Chine à votre flotte, ou d'utiliser un VPN pour vous connecter.

</details>

<details>

<summary>Mon déploiement s'est arrêté/redémarré et je ne peux plus accéder à ses journaux.</summary>

* Dans le cas où le processus serveur plante en raison d'une exception, notre système tentera de redémarrer automatiquement le serveur. Envisagez de tester votre serveur localement pour découvrir la cause première.
* Nous ne conservons les journaux que pendant la durée du déploiement ; si vous souhaitez inspecter les journaux après l'arrêt du déploiement, veuillez [intégrer un stockage de journaux tiers](https://docs.edgegap.com/docs/deployment/endpoint-storage).
* Voir [#id-5.-deployment-stopped](#id-5.-deployment-stopped "mention") pour découvrir toutes les causes de l'arrêt de votre déploiement.

</details>

<details>

<summary>Mon déploiement s'est arrêté automatiquement après X minutes.</summary>

* Les déploiements du niveau Gratuit ont une limite de temps de 60 minutes, envisagez de mettre à niveau votre compte.
* Tous les déploiements seront terminés après 24 heures d'exécution conformément à notre politique de nettoyage des serveurs, pour la maintenance de l'infrastructure et pour éviter des coûts inattendus lorsque le déploiement n'a pas été correctement arrêté. Pour les serveurs longue durée, envisagez d'utiliser [flottes-privees](https://docs.edgegap.com/learn/orchestration/flottes-privees "mention") avec [persistance](https://docs.edgegap.com/learn/orchestration/persistance "mention").
* Voir [#id-5.-deployment-stopped](#id-5.-deployment-stopped "mention") pour découvrir toutes les causes de l'arrêt de votre déploiement.

</details>

<details>

<summary>Mon déploiement est prêt mais je ne peux pas me connecter pendant plusieurs minutes après.</summary>

* Une fois un déploiement Ready, l'initialisation de votre moteur de jeu commence. Ce processus peut prendre de quelques secondes à plusieurs minutes, et le serveur n'accepte pas les connexions de joueurs pendant cette période.
* Envisagez d'optimiser l'initialisation de votre serveur pour réduire cette durée.
* Les clients de jeu doivent réessayer la connexion à des intervalles d'une seconde pendant un temps limité (selon la durée de votre initialisation), après quoi ils retournent au matchmaking.
* Envisagez d'ajouter une scène de chargement afin que le serveur puisse effectuer l'initialisation (et le travel dans le cas d'Unreal Engine) en même temps que les clients, tout en synchronisant l'état des deux.

</details>

<details>

<summary>Mon appareil Meta Quest affiche <code>HTTP 0 : Impossible de résoudre l'hôte de destination</code> .</summary>

* Lors de la construction d'applications Unity pour la cible Android, la permission d'accès à Internet peut être supprimée automatiquement de l'artefact APK client généré.
* Ré-ajoutez les permissions dans (requiert une reconstruction du client ensuite) :
  * Project Settings / OpenXR / :gear: Meta Quest Support / Forcer la suppression des permissions Internet (décochez).
  * Player Settings / Internet Access (définir sur require).

</details>

<details>

<summary>Que se passe-t-il si un joueur quitte mon déploiement ?</summary>

* Par défaut, les serveurs n'empêchent pas les connexions des joueurs. L'authentification des joueurs relève de vos développeurs, car de nombreuses méthodes et fournisseurs d'authentification peuvent être utilisés.
* Les clients de jeu peuvent stocker localement les informations de connexion pour tenter une reconnexion en cas de plantage inattendu du client.
* Pour permettre aux joueurs de rejoindre des parties en cours, envisagez d'utiliser [#backfill](https://docs.edgegap.com/matchmaking/matchmaker-in-depth#backfill "mention") ou [Sessions](https://docs.edgegap.com/docs/deployment/session).

</details>

<details>

<summary>Mon serveur affiche 100 % d'utilisation du CPU après être devenu ready.</summary>

* Cela peut ne pas être un problème, car les moteurs de jeu ont tendance à effectuer des opérations lourdes en CPU pendant l'initialisation du serveur. Si l'utilisation du CPU ne diminue pas après 2-3 minutes depuis le début du déploiement, vous devrez peut-être optimiser votre serveur ou augmenter les ressources de la version de l'application.
* Réduire le tick rate peut avoir un impact sur l'utilisation du CPU car le serveur effectue moins d'opérations de messagerie.
* Si vous utilisez le netcode Mirror, vous devez avoir ["Démarrage automatique du serveur"](https://mirror-networking.gitbook.io/docs/hosting/edgegap-hosting-plugin-guide#build-and-push) sélectionné dans votre `NetworkManager` , recompilez, poussez et redéployez votre serveur.
* Si vous utilisez le netcode FishNet, vous devez activer [« Démarrer en mode Headless »](https://fish-networking.gitbook.io/docs/manual/components/managers/server-manager#settings-are-general-settings-related-to-the-servermanager) dans votre `ServerManager`, recompilez, poussez et redéployez votre serveur.
* Vous êtes limité à 1,5 vCPU et 3 Go de mémoire (RAM) dans le niveau Gratuit.
* Vous pouvez augmenter les ressources allouées lors de la création d'une nouvelle version d'application. Vous pouvez dupliquer votre version d'application dans notre tableau de bord et ajuster ces valeurs selon vos besoins, sans recompiler votre serveur ou image.

</details>

<details>

<summary>Mon déploiement redémarre en boucle et affiche l'erreur `OOM kill`.</summary>

* Ce comportement est dû au dépassement de la quantité de mémoire allouée. Envisagez d'optimiser l'utilisation de la mémoire avec du pooling d'objets, la compression ou la suppression d'objets inutiles dans votre scène.
* Assurez-vous que votre projet charge la scène par défaut contenant votre `NetworkManager` et que la scène est incluse dans les paramètres de build d'Unity.
* Vous êtes limité à 1,5 vCPU et 3 Go de mémoire (RAM) dans le niveau Gratuit.
* Vous pouvez augmenter les ressources allouées lors de la création d'une nouvelle version d'application. Vous pouvez dupliquer votre version d'application dans notre tableau de bord et ajuster ces valeurs selon vos besoins, sans recompiler votre serveur ou image.

</details>

<details>

<summary>Parfois, l'utilisation de la mémoire (RAM) de mon serveur affiche des pics élevés, est-ce un problème ?</summary>

* Tant que vous restez dans la quantité de mémoire allouée à la version de l'application, ce n'est pas un problème.&#x20;
* Dépasser la quantité de mémoire allouée à la version de l'application entraînera un \`OOM kill\` (voir ci-dessus).

</details>

<details>

<summary>Les performances de mon serveur seront-elles impactées par d'autres serveurs exécutés sur la même machine ?</summary>

* Non, notre plateforme garantit que les ressources allouées ne seront pas utilisées par d'autres studios ou d'autres serveurs sur l'infrastructure partagée. Avec Edgegap, il n'y a pas de voisins bruyants.

</details>

[^1]: les sessions peuvent durer jusqu'à 24 heures

[^2]: égal

[^3]: différent de

[^4]: request\_id (ID du déploiement)

[^5]: dans le tableau

[^6]: pas dans le tableau

[^7]: inférieur ou égal

[^8]: supérieur ou égal

[^9]: &#x20;dans le tableau

[^10]: inférieur à

[^11]: supérieur à

[^12]: ascendant, du plus ancien au plus récent

[^13]: descendant, du plus récent au plus ancien

[^14]: ascendant, les remplis d'abord

[^15]: descendant, les vides d'abord


# Persistance

Apprenez à gérer des mondes persistants avec des déploiements toujours en ligne 24/7 sur [flottes-privees](https://docs.edgegap.com/learn/orchestration/flottes-privees "mention").

De nombreux genres (MMO, Sandbox, jeux sociaux) tirent parti des mondes persistants pour permettre aux joueurs :

* de se rencontrer et de socialiser avec de nouveaux amis ; de favoriser des communautés de joueurs organiques,
* d'explorer un monde ouvert vivant rempli de contenus générés par les utilisateurs placés par les joueurs,
* de participer à des raids épiques durant des heures avec de grands groupes ou des guildes entières.

Explorez des stratégies pour **offrir la meilleure expérience joueur possible, garder les coûts sous contrôle et éliminer la frustration des joueurs due aux pannes ou aux retours en arrière**. Améliorez le modèle de serveur traditionnel en apportant les avantages de l'edge computing conditionnés pour une utilisation facile par les développeurs de jeux.

## ✔️ Préparation

Pour permettre des déploiements persistants et ininterrompus 24/7 :

* [créez une nouvelle version d'application (ou mettez à jour une version existante) avec notre API](https://docs.edgegap.com/docs/api/gestion-des-versions#post-v1-app-app_name-version),
  * spécifiez `"max_duration": -1`  pour éviter la terminaison automatique après 24 h,
* Utilisez [API de déploiement de flotte privée](https://docs.edgegap.com/docs/api/serveurs-dedies#post-private-fleets-deploy) pour démarrer [serveurs en attente](https://docs.edgegap.com/learn/deployments#regional-standby) par [persistance](https://docs.edgegap.com/learn/orchestration/persistance "mention").
  * Choisissez entre des Machines Virtuelles (Performance) ou des spécifications Bare Metal (Overdrive).

{% hint style="warning" %}
**Testez la montée en charge de votre serveur et** [**le processus de terminaison**](https://docs.edgegap.com/learn/deployments#id-5.-deployment-stopped) **pour vérifier la fiabilité de vos contrôles de coûts. L'état du serveur stocké en mémoire sera perdu une fois le déploiement arrêté, voir** [#configuration-and-state](#configuration-and-state "mention").
{% endhint %}

## 🔑 Propriété du serveur

Explorez les avantages et inconvénients des modèles de propriété modernes et traditionnels avec une touche d'edge computing.

### Hébergement par le studio

L'hébergement des serveurs est traditionnellement géré par le studio, qui couvre le coût de l'hébergement à partir des revenus du jeu.

👍 **Avantages**

* tarification produit transparente - le coût de l'hébergement est couvert par la licence/abonnement du joueur,
* forte compatibilité client/serveur avec découplage souple des clients, services et montée en charge,
* plus résistant à la triche et au reverse engineering en raison de la nature propriétaire des serveurs.

👎 **Inconvénients**

* le support du modding par la communauté est limité pour garantir l'intégrité et la stabilité du serveur.

### Serveurs communautaires

Permettez à vos joueurs d'héberger et de financer leurs propres serveurs et éliminez le besoin de services de location tiers. Canalisez les revenus via votre studio plutôt que par des tiers qui n'ont pas de visibilité sur la qualité de l'expérience utilisateur finale.

👍 **Avantages**

* support de modding amélioré via une liste sélectionnée de mods [application-and-versions](https://docs.edgegap.com/learn/orchestration/application-and-versions "mention"),
* boucle de retour joueur améliorée grâce à une collaboration plus étroite avec la communauté,
* risque financier réduit car les joueurs couvrent le coût de l'hébergement.

👎 **Inconvénients**

* plus d'opérations pour le studio - modération des demandes des joueurs et collecte des paiements,
* compatibilité client/serveur plus faible en raison du nombre accru de versions moddées,
* susceptible aux tricheurs en raison d'une base de code distribuée et de la possibilité de reverse engineering.

## 🥛 Capacité & Mise à l'échelle

Apprenez des techniques avancées pour optimiser la disponibilité des serveurs, le coût d'hébergement et la qualité de service.

### Capacité

**Les déploiements ne suivent ni ne gèrent les connexions actives des joueurs** après vous [#id-1.-start-a-deployment](https://docs.edgegap.com/learn/deployments#id-1.-start-a-deployment "mention") pour vous donner un contrôle absolu et la liberté d'implémenter n'importe quel design.

Mettez en œuvre la gestion de la capacité pour garantir que vos serveurs :

* maximisent les économies de coûts - [benchmarquent](https://docs.edgegap.com/learn/deployments#container-metrics) et utilisent efficacement les ressources serveur,
* offrent un gameplay fluide - empêchent la surcharge des serveurs par trop de joueurs simultanés,
* éviter les mauvaises critiques dues aux plantages - intercepter et gérer les exceptions inattendues.

Pour garantir une gestion efficace de la capacité des serveurs :

* libérez des emplacements joueurs si [des joueurs assignés au serveur de jeu](https://docs.edgegap.com/matchmaking/matchmaker-in-depth#player-tickets) ne se connectent pas dans quelques secondes,
* envoyez fréquemment un message de heartbeat minimal des clients vers le serveur pour suivre l'activité,
* déconnectez les clients et libérez les emplacements joueurs si aucune activité n'est détectée pendant plusieurs secondes,
* empêchez l'ajout de joueurs sur des serveurs à pleine capacité sans emplacements disponibles.

{% hint style="success" %}
Voir [Broken link](https://docs.edgegap.com/learn/orchestration/broken-reference "mention") pour la gestion automatisée de la capacité avec notre service géré.
{% endhint %}

### Monter en charge

**La mise à l'échelle des serveurs persistants ne nécessite pas de « deviner »** le trafic régional ou le coût serveur. Réservez [flottes-privees](https://docs.edgegap.com/learn/orchestration/flottes-privees "mention") capacité pour [la marée basse](#user-content-fn-1)[^1] et débordez automatiquement vers le cloud lors de pics inattendus.

Mettez en œuvre des stratégies de mise à l'échelle des serveurs pour :

* permettre un hébergement à grande échelle tout en protégeant soigneusement contre les abus,
* minimiser le gaspillage de coûts serveur dû aux serveurs en veille vides,
* éviter les longues files d'attente en répondant rapidement à l'augmentation de la demande des joueurs.

<figure><img src="https://3008966946-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2FWVZEdEvyAcAROhqNYbKQ%2Fimage.png?alt=media&#x26;token=a26d6f3a-9071-41aa-b27f-ee96555f84a9" alt=""><figcaption><p>Architecture de référence pour l'auto-scaling</p></figcaption></figure>

#### Points clés d'intégration

1. Les clients intègrent une Autorité d'Échelle - [matchmaking](https://docs.edgegap.com/learn/matchmaking "mention"), [navigateur-de-serveurs](https://docs.edgegap.com/learn/navigateur-de-serveurs "mention"), ou une solution personnalisée.
   1. Découvrez d'autres joueurs, réservez de la capacité dans des serveurs en cours d'exécution, ou demandez de nouveaux serveurs si nécessaire.
2. L'Autorité d'Échelle assigne des serveurs en cours d'exécution ou lance de nouveaux serveurs pour desservir les joueurs.
3. Le serveur informe l'Autorité d'Échelle en temps réel du démarrage/arrêt du serveur et des changements de connexion des joueurs.
   1. L'Autorité d'Échelle supprime (expire) les enregistrements obsolètes des serveurs non réactifs (plantés).
4. Les clients se connectent et établissent des sessions de jeu directement avec le serveur, puis passent au jeu.

**Nous recommandons fortement une mise à l'échelle basée sur le nombre de connexions plutôt que la charge physique** (CPU & RAM), car les fluctuations momentanées de la charge physique peuvent entraîner une disponibilité imprévisible.

### Redescendre en charge

Des politiques de réduction efficaces sont essentielles pour optimiser les coûts, mais [arrêter des serveurs](https://docs.edgegap.com/docs/api/serveurs-dedies#v1-self-stop-request_id-access_point_id) sans précaution peut affecter négativement l'expérience des joueurs. **Considérez ces facteurs et testez les changements avant de les déployer :**

**Votre détection de l'activité / déconnexion des joueurs est-elle fiable ?**

* L'absence d'entrée indique-t-elle de façon fiable une inactivité du joueur ? Les joueurs utilisent souvent des bots, macros et autres techniques pour simuler de l'activité et maintenir une connexion active afin d'éviter les temps d'attente.
* Y a-t-il des actions fréquemment effectuées par des joueurs actifs qui sont difficiles à simuler ?
* L'utilisation de bots ou de macros est-elle un problème ou une fonctionnalité avec [#studio-hosting](#studio-hosting "mention") les serveurs ?

**L'arrêt des serveurs est-il facilement et rapidement réversible (remonter en charge) ?**

* Une fois atteint [#id-3.-deployment-ready](https://docs.edgegap.com/learn/deployments#id-3.-deployment-ready "mention"), votre serveur peut nécessiter du temps supplémentaire pour effectuer l'initialisation du moteur et [#state-management](#state-management "mention") (restauration de l'état). Engagez-vous des coûts supplémentaires pour le calcul ou le transfert de données avec les services de jeu ? Ce temps d'attente affecte-t-il l'expérience du joueur ?
* Pouvez-vous masquer le chargement du serveur avec une scène de chargement, un mini-jeu, un hall d'attente ou d'autres moyens ?

**Les joueurs sont-ils liés à des instances de serveur spécifiques ou peuvent-ils migrer facilement ?**

* Comment la connexion à un serveur différent influence-t-elle le compte du joueur, l'historique des achats, l'expérience sociale, la progression, l'inventaire et autres aspects du gameplay ?
* Examinez votre [#recovery-objectives](#recovery-objectives "mention") et assurez-vous que les données critiques ne sont pas perdues.
* Mettez en œuvre des méthodes automatisées ou des outils pour joueurs afin de restaurer les données critiques.
* Fournissez un support humain et communiquez avec votre communauté au sujet des pannes et des problèmes.

## 🔎 Découvrabilité

Pour trouver des serveurs actifs acceptant de nouveaux joueurs, mettez en œuvre une ou plusieurs méthodes de découverte :

* Permettez aux joueurs de parcourir les serveurs et de choisir dans une liste avec [navigateur-de-serveurs](https://docs.edgegap.com/learn/navigateur-de-serveurs "mention").
* Démarrez de nouvelles parties lorsque suffisamment de joueurs se joignent [matchmaking](https://docs.edgegap.com/learn/matchmaking "mention").
  * Ajouter des joueurs pour [remplacer les départs dans les matchs existants avec remplissage (backfill)](https://docs.edgegap.com/matchmaking/matchmaker-in-depth#backfill).
* [Implémentez un backend de jeu personnalisé ou tiers pour découvrir les serveurs](https://docs.edgegap.com/advanced-features/managed-clusters#nakama-by-heroic-labs).

## 💭 Configuration & État

Intégrez des services pour définir les exigences initiales du serveur et gérer l'état des joueurs et des serveurs.

### Gestion de la configuration

La configuration se réfère aux **données initiales transmises à votre serveur lors du déploiement :**

* [variables injectées spécifiques à l'environnement](https://docs.edgegap.com/learn/application-and-versions#other-parameters-optional):
  * par ex. données de compatibilité version client/serveur,
* [emplacement du serveur](https://docs.edgegap.com/learn/deployments#arbitrium_deployment_location-detailed-information-about-deployment-location), [ports du serveur](https://docs.edgegap.com/learn/deployments#arbitrium_ports_mapping-detailed-information-about-your-internal-and-external-ports) et [autres informations serveur](https://docs.edgegap.com/learn/deployments#injected-environment-variables),
* [informations de matchmaking](https://docs.edgegap.com/matchmaking/matchmaker-in-depth#injected-environment-variables) ou [variables de déploiement personnalisées](https://docs.edgegap.com/learn/deployments#custom-variables),
* paramètres, clés et secrets d'intégration tierce.

{% hint style="info" %}
**La configuration est immuable**  - elle est lue une fois après le démarrage de votre serveur et ne change pas par la suite.
{% endhint %}

### Gestion de l'état

L'état se réfère aux données décrivant le **résultat d'une série d'actions précédentes des joueurs et d'événements serveur :**

* connexion du joueur, changements d'état contrôlés par le joueur (par ex. [Pion](https://dev.epicgames.com/documentation/en-us/unreal-engine/pawn-in-unreal-engine)),
* changements liés aux objets contenus dans le niveau/la scène (par ex. [Acteur](https://dev.epicgames.com/documentation/en-us/unreal-engine/actors-in-unreal-engine), [Objet de jeu](https://docs.unity3d.com/6000.0/Documentation/Manual/GameObjects.html)),
* changements liés à [mode de jeu](https://dev.epicgames.com/documentation/en-us/unreal-engine/game-mode-and-game-state-in-unreal-engine#gamemodes), [état du jeu](https://dev.epicgames.com/documentation/en-us/unreal-engine/game-mode-and-game-state-in-unreal-engine#gamestate), ou [scène de jeu](https://docs.unity3d.com/6000.0/Documentation/Manual/CreatingScenes.html) informations.

{% hint style="info" %}
**Les données d'état changent fréquemment.** Les clients sont mis à jour de façon sélective sur les informations pertinentes par l'autorité serveur.
{% endhint %}

{% hint style="success" %}
**Effectuez des sauvegardes fréquentes de l'état pour prévenir la perte de données** en cas de problèmes inattendus côté client ou serveur :

* de manière asynchrone en temps réel en utilisant un service tiers, par ex. [Nakama par Heroic Labs](https://docs.edgegap.com/advanced-features/managed-clusters#nakama-by-heroic-labs),
* au démarrage ou à l'arrêt client/serveur, sous forme de fichiers d'état désérialisés dans [stockage d'objets cloud](https://www.linode.com/products/object-storage/).
  {% endhint %}

Les objets de jeu désignent généralement un propriétaire qui les contrôle, cela peut être soit le serveur soit un joueur.&#x20;

#### Objets possédés par le serveur

Les objets possédés par le serveur ne peuvent être manipulés que par le serveur. Les joueurs connectés ont un accès en lecture limité aux objets possédés par le serveur. Les objets possédés par le serveur ne sont généralement pas partagés avec d'autres serveurs.

{% hint style="success" %}
Les objets possédés par le serveur peuvent être **chargés par un serveur de remplacement en cas de crash serveur inattendu**. Utilisez [ID de déploiement](https://docs.edgegap.com/learn/deployments#basic-information) pour identifier votre nouveau fichier de sauvegarde lors du premier lancement, et pour stocker l'état des objets possédés par le serveur.
{% endhint %}

#### Objets possédés par le joueur

Les objets possédés par le joueur peuvent être manipulés à la fois par les joueurs et par le serveur. Assigner la propriété d'objets persistants aux joueurs facilite la migration vers d'autres serveurs ultérieurement.

{% hint style="success" %}
**Sauvegardez l'état des objets possédés par le joueur sur l'appareil du joueur ou un backend de jeu** entre les sessions de jeu.
{% endhint %}

{% hint style="info" %}
Prévenez la triche en validant les changements avec l'autorité serveur. Autorité et propriété peuvent être séparées.
{% endhint %}

### Objectifs de récupération

En cas de problèmes, certaines catégories de données peuvent être plus sensibles à la perte de données, par exemple :

* données de compte, d'abonnement, d'achat et de microtransaction - **critiques**,
* données de progression, de succès, de classements et d'inventaire - **important**,
* données de détection de triche, modération, performance et suivi des erreurs - **important**,
* données de comportement des joueurs, sociales, de chat - **faible importance**.

{% hint style="success" %}
**Mettez en œuvre la restauration des achats à partir d'une source indépendante d'historique des transactions** pour une meilleure expérience.
{% endhint %}

Nous recommandons vivement de discuter des éléments suivants au sein de votre équipe :

* catégories de données traitées dans vos clients et serveurs de jeu,
* importance et sensibilité de chaque catégorie pour votre entreprise et vos joueurs,
* Recovery Point Objective (RPO) - quantité acceptable de perte de données avant qu'un dommage grave ne survienne,
* Recovery Time Objective (RTO) - durée d'indisponibilité acceptable avant qu'un dommage grave ne survienne.

## 👀 Observabilité

Les serveurs persistants à longue durée posent de nouveaux défis d'observabilité, notamment la détection d'anomalies dans la surveillance, la journalisation et le suivi des bugs.

Nous **recommandons fortement de mettre en place des alertes pour les redémarrages de serveurs** pour gagner en visibilité sur les problèmes.

Notre [endpoint-storage](https://docs.edgegap.com/docs/endpoint-storage "mention") **intégration des logs** **transfère uniquement les journaux** **après** [#id-5.-deployment-stopped](https://docs.edgegap.com/learn/deployments#id-5.-deployment-stopped "mention"), ajoutez des logs personnalisés et du suivi de bugs (comme [Sentry](https://sentry.io/welcome/)) pour dépanner les défaillances partielles et les bugs.

{% hint style="success" %}
Envisagez de réserver [flottes-privees](https://docs.edgegap.com/learn/orchestration/flottes-privees "mention") capacité de veille pour les jeux aux schémas de trafic prévisibles.
{% endhint %}

[^1]: le CCU le plus bas de la journée


# Flottes privées

Réservez une capacité de veille sur une base mensuelle pour des serveurs persistants 24/7 toujours en ligne. Choisissez votre préférence entre Machines Virtuelles (Performance) ou spécifications Bare Metal (Overdrive).

**Les Flottes Privées sont un ajout optionnel à Edgegap Cloud (par défaut),** une option d'hébergement populaire permettant [persistance](https://docs.edgegap.com/learn/orchestration/persistance "mention") avec des serveurs toujours en ligne 24/7 et des tarifs favorables pour les jeux au trafic prévisible.

🌟 [**Passez au niveau Pay as You Go**](https://app.edgegap.com/user-settings?tab=memberships) **pour débloquer l'hébergement de flottes privées avec capacité de veille !**

{% hint style="warning" %}
[Smart Fleets (héritage)](https://docs.edgegap.com/docs/fleet) et [Sessions (héritage)](https://docs.edgegap.com/docs/session) seront dépréciés et remplacés par [flottes-privees](https://docs.edgegap.com/learn/orchestration/flottes-privees "mention") et [navigateur-de-serveurs](https://docs.edgegap.com/learn/navigateur-de-serveurs "mention") le 1er mars 2026. [**Contactez-nous via Discord**](https://discord.gg/MmJf8fWjnt) **pour en savoir plus et obtenir de l'aide pour la migration.**
{% endhint %}

## ✔️ Introduction

Les Flottes Privées vous permettent de choisir des emplacements d'hôtes spécifiques et de réserver une capacité de calcul de veille dédiée au sein de notre infrastructure cloud disponible mondialement, adaptée à :

* [**serveurs persistants 24/7**](https://docs.edgegap.com/learn/orchestration/persistance) présentant des mondes ouverts avec du contenu généré par les utilisateurs placé par les joueurs,
* **jeux MMO** priorisant les expériences sociales avec un grand nombre d'utilisateurs simultanés par serveur,
* **jeux publiés avec un trafic quotidien principalement prévisible** schémas et communautés de joueurs stables.

## ☁️ Matériel

Choisissez l'une de nos spécifications d'hôte génériques :

| Spécification                                                                   |                                                                                                                                     Performance |                                                                                                                                       Overdrive |
| ------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------: | ----------------------------------------------------------------------------------------------------------------------------------------------: |
| Idéal Pour                                                                      |                                                                                    <p>jeux basés sur des matchs,<br>ou au trafic prévisible</p> |                                                                      <p>jeux intensifs en CPU (IA),<br>ou au-delà d'un ratio CPU/RAM de 1:2</p> |
| Spécifications CPU                                                              | <p>16 vCPU<br><a data-footnote-ref href="#user-content-fn-1">2.0</a> - <a data-footnote-ref href="#user-content-fn-2">3.7</a> fréquence GHz</p> | <p>16 vCPU<br><a data-footnote-ref href="#user-content-fn-1">3.7</a> - <a data-footnote-ref href="#user-content-fn-2">5.1</a> fréquence GHz</p> |
| Spécifications RAM                                                              |                                                                                                                                           32 Go |                                                                                                                                           64 Go |
| Sortant gratuit inclus                                                          |                                                                                                                                   5 To par hôte |                                                                                                                                   5 To par hôte |
| <p><strong>Prix, prépayé mensuellement</strong></p><p>(basé sur engagement)</p> |                                                                                                                           **250,00 $ par hôte** |                                                                                                                           **290,00 $ par hôte** |

{% hint style="success" %}
[**Aperçu d'une estimation de prix lors de la configuration de votre flotte dans le tableau de bord**](https://app.edgegap.com/private-fleet-management/private-fleets/list)**.**
{% endhint %}

**Le prix de réservation de votre premier mois et le quota d'égress gratuit sont calculés au prorata.** Cela signifie que vous n'êtes facturé que pour la partie du temps jusqu'à la fin du mois en cours.

**Les réservations se renouvellent automatiquement le&#x20;premier jour de chaque mois à 00:00 UTC jusqu'à suppression.** Votre carte sera automatiquement débitée du montant mensuel pour les hôtes renouvelés à ce moment.

{% hint style="success" %}
Une flotte avec [hôtes actifs](#lifecycle) ne peut pas changer de spécifications. Créez d'abord une nouvelle flotte ou supprimez les hôtes actifs.
{% endhint %}

{% hint style="info" %}
Une petite quantité de ressources sur chaque hôte est réservée pour le système d'exploitation, la surveillance et l'orchestration.
{% endhint %}

#### Modification du planning et suppression d'hôtes

Vous pouvez modifier ou supprimer ce planning à tout moment avant l'heure programmée, sans frais. Vous pouvez désigner n'importe quel nombre d'hôtes privés réservés (actifs) pour suppression à la fin de la période de facturation en cours, avant la date de renouvellement. Les hôtes supprimés ne seront pas facturés pour les renouvellements ultérieurs. Toute déploiement exécuté sur des hôtes privés prévus pour suppression sera arrêté proprement au moment de la suppression sans avertissements supplémentaires.

#### Démarrage différé ou capacité insuffisante du fournisseur

En cas de démarrage différé d'un hôte privé ou de capacité insuffisante du fournisseur, le montant de votre paiement et la facture pour les périodes programmées ou de renouvellement seront ajustés en conséquence.

## 📍 Emplacements

Choisissez un centroïde en déposant une épingle et prévisualisez vos emplacements principaux/de secours pour les nouveaux hôtes.

Sélectionnez une stratégie de repli pour contrôler les emplacements adaptés pour chaque centroïde :

* **Proximité (par défaut)** - rayon du centroïde de 700 km, pour des conceptions plus sensibles à la latence,
* **Redondance** - rayon du centroïde de 1 400 km, permettant des emplacements plus éloignés comme solutions de repli.

<figure><img src="https://3008966946-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2F0otdBhulhvgFgO6mNWtg%2Fimage.png?alt=media&#x26;token=6388d70c-7cf4-469f-8ce4-9735c67aeb4d" alt=""><figcaption></figcaption></figure>

{% hint style="info" %}
La disponibilité des emplacements dépend de la spécification matérielle choisie. La disponibilité Overdrive est limitée.
{% endhint %}

📢 Provisionnement API en cours de développement, [faites-nous savoir](https://discord.gg/NgCnkHbsGp) vos besoins d'Intégration Continue !

## 🔄 Cycle de vie des hôtes

Les hôtes de la Flotte Privée suivent une simple séquence de cycle de vie en trois étapes.

📢 La planification des ajouts de nouveaux hôtes est en cours de développement, [faites-nous savoir](https://discord.gg/NgCnkHbsGp) parlez-nous de votre processus de publication !

#### 1. En attente

De nouveaux hôtes ont été demandés, nous les démarrons dans l'ordre de distance depuis le centroïde.

#### 2. Actif

L'hôte est actif et réactif, prêt à [#id-1.-start-a-deployment](https://docs.edgegap.com/learn/deployments#id-1.-start-a-deployment "mention").

#### 3. Prévu pour suppression

Tant qu'il est encore actif, cet hôte sera supprimé à la fin de la période de facturation en cours (mois). Cette action peut être annulée à tout moment jusqu'à la suppression.

{% hint style="warning" %}
Les déploiements exécutés sur des hôtes privés seront [arrêtés proprement](https://docs.edgegap.com/learn/deployments#id-5.-deployment-stopped) une fois que l'hôte sera supprimé.
{% endhint %}

{% hint style="success" %}
**Évitez la frustration due aux retours en arrière et aux perturbations du gameplay** en informant les joueurs et en redirigeant les nouveaux déploiements vers d'autres hôtes de la flotte privée, une fois qu'un hôte privé prévu pour suppression approche de l'arrêt.
{% endhint %}

## ⚡ Déploiement

[Les déploiements pour la Flotte Privée](https://docs.edgegap.com/docs/api/serveurs-dedies#post-private-fleets-deploy) fonctionnent exactement de la même manière que [les déploiements cloud réguliers](https://docs.edgegap.com/docs/api/serveurs-dedies#post-deployments), sauf que vous devez spécifier une [liste priorisée d'ID d'hôtes](https://docs.edgegap.com/docs/api/serveurs-dedies#get-private-fleets-fleet-name-hosts) où déployer.

* Le déploiement sera démarré sur le premier hôte privé de votre liste disposant de ressources suffisantes.
* Si aucun hôte privé n'a de capacité disponible, le déploiement [#overflow-to-cloud](#overflow-to-cloud "mention").

### Basculera vers le Cloud

Si vos hôtes de flotte privée sélectionnés n'ont pas suffisamment de capacité au moment du déploiement, votre demande utilisera automatiquement [#server-score](https://docs.edgegap.com/learn/deployments#server-score "mention") la stratégie et se déploiera sur Edgegap Cloud.

Pour tenir compte de cette possibilité et vous préparer :

* Lisez [#resource-specifications](https://docs.edgegap.com/learn/deployments#resource-specifications "mention") variables injectées pour identifier le cas de débordement dans le déploiement.
  * Les hôtes cloud peuvent fournir une fréquence CPU inférieure à celle de l'Overdrive des hôtes privés [#hardware](#hardware "mention"), limitez la capacité des joueurs ou d'autres fonctionnalités intensives en CPU dans le serveur pour éviter les goulets d'étranglement.
* Remplacez le beacon d'hôte privé manquant par l'un des cloud à faible latence [ping-beacons](https://docs.edgegap.com/learn/orchestration/ping-beacons "mention").
* Préparez votre déploiement [arrêt propre](https://docs.edgegap.com/learn/deployments#id-5.-deployment-stopped) après 24 heures (durée de vie maximale dans le cloud).
  * Gérez [persistance](https://docs.edgegap.com/learn/orchestration/persistance "mention") et [#recovery-objectives](https://docs.edgegap.com/learn/persistance#recovery-objectives "mention") pour prévenir la perte de données.

## 🔎 Découvrabilité

Trouvez les déploiements exécutés sur des flottes privées et établissez des sessions de joueurs en utilisant [navigateur-de-serveurs](https://docs.edgegap.com/learn/navigateur-de-serveurs "mention"), ou [#filter-deployments](https://docs.edgegap.com/learn/deployments#filter-deployments "mention") pour intégrer une backend personnalisé / des solutions tierces.

📢 [appariement](https://docs.edgegap.com/learn/appariement "mention") intégration en cours de développement, [faites-nous savoir](https://discord.gg/NgCnkHbsGp) parlez-nous de vos besoins !

### Ping Beacons

Activez les beacons pour votre flotte afin de déployer automatiquement et maintenir des [#ping-beacons](#ping-beacons "mention") hautement disponibles sur chacun de vos hôtes privés. Héberger les beacons sur la même machine que vos déploiements fournira la mesure de ping la plus précise.

[^1]: fréquence de base

[^2]: turbo - courtes rafales CPU


# Balises de ping

Utilisez des balises Ping pour éviter les correspondances avec des joueurs situés dans des régions éloignées et améliorer l'expérience des joueurs.

## 🟢 Qualité de connexion

La qualité de la connexion au serveur varie pour chaque joueur et est impactée par de nombreux facteurs, notamment :

* la puissance du signal Wi‑Fi (si sans fil ou mobile),
* l'état du fournisseur d'accès à Internet,
* les conditions du réseau local,
* le protocole réseau utilisé,
* l'utilisation de réseaux privés virtuels (VPN),
* ou des restrictions propres à certains pays.

Afin de minimiser le ping des joueurs et **fournir la meilleure mise en relation possible des joueurs** et rendre [#server-placement](https://docs.edgegap.com/learn/deployments#server-placement "mention") optimaux, les clients de jeu **utilisent des balises Ping pour mesurer la latence** vers plusieurs nœuds réseau majeurs dans le monde en temps réel. La mesure du temps de trajet aller‑retour réel des paquets prend en compte tous les facteurs mentionnés ci‑dessus et fournit la métrique la plus précise à un instant donné.

Gardez à l'esprit que **un ping élevé vers une balise n'équivaudra pas nécessairement à un ping élevé vers le serveur**, puisque les serveurs sont plus densément peuplés que les balises. Le nombre de balises est ajusté en temps réel pour assurer la meilleure couverture, le transfert de données minimal requis et le temps le plus court pour compléter la mesure.

En plus de la surveillance d'Edgegap, nous recommandons de **mettre en œuvre vos propres analyses côté client** pour suivre la démographie de vos joueurs et la qualité de leur connexion lors du matchmaking, afin que les problèmes puissent être découverts, triés et résolus aussi rapidement que possible.

## 🗼 À propos des balises Ping

Récupérez une liste de balises que les joueurs peuvent pinger directement depuis :

* Matchmaker [#matchmaking-api](https://docs.edgegap.com/matchmaking/matchmaker-in-depth#matchmaking-api "mention") depuis un client de jeu,
* API Edgegap [point de terminaison /locations/beacons](https://docs.edgegap.com/api/#tag/Locations/operation/location-beacon-list) en utilisant [le jeton API Edgegap](https://app.edgegap.com/user-settings?tab=tokens) (depuis votre backend).

Les balises Ping peuvent être utilisées simultanément à plusieurs fins :

* prévenir les correspondances à forte latence en [#measuring-round-trip-time](#measuring-round-trip-time "mention") automatique.
* fournir un [#hub-selection-ui](#hub-selection-ui "mention") pour que les joueurs puissent choisir leurs hubs favoris,
* fournir un [#region-selection-ui](#region-selection-ui "mention") pour que les joueurs puissent exclure des régions éloignées,

{% hint style="info" %}
**Trop de requêtes 429** - pour garantir la stabilité de la plateforme, nous **limitons le taux de requêtes de votre organisation à** **40 req/s** pour ce point de terminaison de l'API. Mettez en place un [#active-cache](#active-cache "mention") pour éviter d'atteindre la limite de débit.
{% endhint %}

{% hint style="success" %}
[#measuring-round-trip-time](#measuring-round-trip-time "mention") en utilisant **Le ping ICMP, UDP ou TCP n'est pas soumis à une limitation de débit**.
{% endhint %}

## 🗺️ Interface de sélection de région

Empêchez les utilisateurs d'être mis en relation avec d'autres utilisateurs d'une région particulière en proposant une liste de régions à activer ou désactiver dans l'interface de votre jeu.

**Désactiver automatiquement les régions à forte latence :**

* lister toutes les balises disponibles,
* effectuer [#measuring-round-trip-time](#measuring-round-trip-time "mention") vers toutes les balises,
* **désactiver une région si la latence mesurée envers toutes les balises dépasse un seuil donné.**

Votre seuil dépend des spécificités du design du jeu ; nous recommandons de faire correspondre dans des régions avec une latence inférieure à 250 ms (millisecondes).

## 📍 Interface de sélection de hub

Certains joueurs préfèrent pouvoir sélectionner parmi une liste exhaustive de localisations.

**Désactiver automatiquement les hubs à forte latence :**

* lister toutes les balises disponibles,
* effectuer [#measuring-round-trip-time](#measuring-round-trip-time "mention") vers toutes les balises,
* **désactiver les hubs si la latence mesurée dépasse un seuil donné,**
* identifier les hubs activés dans l'interface du jeu en utilisant la propriété City de la balise.

Votre seuil dépendra des spécificités du design de votre jeu, mais nous recommandons généralement de faire correspondre dans des hubs avec une latence inférieure à 150 ms (millisecondes).

Nous recommandons également de choisir le nom « Hub » dans votre interface, ou un autre **nom qui n'implique pas que ce sont les seuls emplacements de serveurs disponibles**. Edgegap orchestre des serveurs de jeu dans le monde entier sur plus de 615 emplacements physiques et auprès de plus de 17 fournisseurs de centres de données pour garantir le déploiement à l'emplacement idéal.

## 🌡️ Mesure du temps aller‑retour

En développement de jeux, les termes « ping » et « latence » font généralement référence à [au temps de trajet aller‑retour des paquets](https://www.cloudflare.com/learning/cdn/glossary/round-trip-time-rtt/).

Voir [#id-5.-game-integration](https://docs.edgegap.com/matchmaking#id-5.-game-integration "mention") pour la mesure automatique du ping :

Vue détaillée du processus de mesure de la latence dans [Matchmaker](https://docs.edgegap.com/learn/matchmaking/matchmaker-in-depth):

<figure><img src="https://3008966946-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2Fn6ke8Ed6jijjdlPQ4CfP%2Fimage.png?alt=media&#x26;token=c85c70b2-73af-4980-a962-488393d264e6" alt=""><figcaption></figcaption></figure>

## ⏰ Haute disponibilité

## 🧠 Cache actif

**Si vous n'utilisez pas** [**Matchmaker**](https://docs.edgegap.com/learn/matchmaking) (par exemple les utilisateurs du Matchmaker Avancé), nous recommandons de mettre en place une assurance de scalabilité supplémentaire avant une sortie à grande échelle. **Créez votre propre service backend de jeu** qui conserve un cache centralisé en mémoire, répondant avec les emplacements des balises aux clients de jeu sans utiliser notre API de liste de balises pour chaque requête client.

Ce service devrait activement **effectuer une seule requête API pour mettre à jour la liste des balises toutes les 60 secondes.**


# Matchmaking

Commencez rapidement avec le matchmaking et explorez des scénarios d'exemple pour différents genres.

Suivez cette vidéo pour démarrer avec notre service Matchmaker :

{% embed url="<https://youtu.be/HxtvzvJ1FTk>" %}

## ✔️ Préparation

### Architecture du Matchmaking

Ce guide se concentrera sur **l'API Matchmaking et l'API Backfill**.

<figure><img src="https://3008966946-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2Fp2QpL1MXYtwSWB2VJN2A%2Fimage.png?alt=media&#x26;token=ecc73799-c2e6-4884-965f-48e4c125659c" alt=""><figcaption></figcaption></figure>

Il y a quatre (4) flux de données importants lorsque le matchmaking est impliqué :

1. [API Matchmaking](https://docs.edgegap.com/learn/matchmaker-in-depth#matchmaking-api) **est utilisée par les clients de jeu pour communiquer avec le Matchmaker :**
   1. pour la gestion des groupes, l'attribution de serveurs et la surveillance,
   2. pour la mesure du ping avec [ping-beacons](https://docs.edgegap.com/learn/orchestration/ping-beacons "mention").
2. [deployments](https://docs.edgegap.com/learn/orchestration/deployments "mention") L'API est utilisée pour déployer, mettre à l'échelle et gérer vos serveurs dédiés par le Matchmaker.
3. [Transports Netcode](https://docs.edgegap.com/docs/sample-projects) sont utilisés pour communiquer entre les clients de jeu et les serveurs dédiés.
4. [#backfill-match](https://docs.edgegap.com/learn/matchmaker-in-depth#backfill-match "mention") **pour remplacer ou ajouter des joueurs à un serveur en cours d'exécution.**

{% hint style="info" %}
Après la sortie, **votre matchmaker devra fonctionner 24h/24 et 7j/7** pour garantir que les joueurs du monde entier puissent rejoindre des serveurs.
{% endhint %}

## 🍀 Exemple simple

Commencez par un exemple simple et testez le flux de joueur de base du matchmaking :

* création de l'instance du matchmaker sur le [#hosting-cluster](https://docs.edgegap.com/learn/matchmaker-in-depth#hosting-cluster "mention"),
* définition des règles et paramètres dans votre matchmaker [#configuration](https://docs.edgegap.com/learn/matchmaker-in-depth#configuration "mention"),
* test du flux de joueur et gestion des tickets avec [#matchmaking-api](https://docs.edgegap.com/learn/matchmaker-in-depth#matchmaking-api "mention").

### 1. Configuration sur le niveau gratuit

☑️ [Inscrivez-vous pour votre compte Edgegap gratuit](https://app.edgegap.com/auth/register) et ouvrez le [page du tableau de bord Matchmaker](https://app.edgegap.com/matchmaker-management-v2/matchmakers/list).

☑️ Cliquez sur **Créer un Matchmaker** d'abord, puis saisissez :

* nom du matchmaker - pour votre référence, par ex. `quickstart-dev` ,
* téléchargez notre configuration JSON d'exemple simple.

🍀 **Exemple simple (Configuration minimale recommandée) :**

{% hint style="danger" %}
**Assurez-vous de changer l'application** **`nom`**  **et** **`version`**  **pour correspondre à votre** [application-and-versions](https://docs.edgegap.com/learn/orchestration/application-and-versions "mention").
{% endhint %}

<pre class="language-json"><code class="lang-json">{
  "version": "3.2.1",
  "inspect": true,
  "max_deployment_retry_count": 3,
  "profiles": {
    "simple-example": {
      "ticket_expiration_period": "5m",
      "ticket_removal_period": "1m",
      "group_inactivity_removal_period": "5m",
      "application": {
        "name": "<a data-footnote-ref href="#user-content-fn-1">my-game-server</a>",
        "version": "<a data-footnote-ref href="#user-content-fn-2">2024.01.30-16.23.00-UTC</a>"
      },
      "rules": {
        "initial": {
          "match_size": {
            "type": "player_count",
            "attributes": {
              "team_count": 1,
              "min_team_size": 2,
              "max_team_size": 2
            }
          },
          "beacons": {
            "type": "latencies",
            "attributes": {
              "difference": 100,
              "max_latency": 200
            }
          }
        },
        "expansions": {}
      }
    }
  }
}
</code></pre>

**Dépannage et FAQ :**

☑️ Si aucune erreur de validation n'apparaît, cliquez sur **Créer et Démarrer** et attendez la fin du processus. Cela entraînera le démarrage d'un nouveau cluster gratuit, avec votre matchmaker d'exemple simple.

✅ Vous pouvez maintenant passer à l'étape suivante.

### 2. Explorer la configuration

À mesure que nous publions des mises à jour du Matchmaker, chaque nouvelle version utilise [le versionnage sémantique](https://docs.edgegap.com/learn/matchmaker-in-depth#changelog) pour communiquer clairement l'impact des changements en interprétant le format `major.minor.patch`:

* 🔥 `majeure` les versions incluent des changements incompatibles et nécessitent une revue d'intégration,
* 🌟 `mineure` les versions incluent des améliorations substantielles rétrocompatibles,
* 🩹 `correctif` les versions incluent des corrections de bugs et des améliorations mineures.

[Inspecter les tickets](https://docs.edgegap.com/learn/matchmaker-in-depth#matchmaking-api) pour mieux comprendre et déboguer les flux de matchmaking possibles pendant le développement. Nous recommandons de désactiver l'API inspect pour votre matchmaker en production.

**Certaines** [**déploiements peuvent entraîner des erreurs**](https://docs.edgegap.com/orchestration/deployments#id-4.-deployment-error)**.** Nous tentons de résoudre cela en réessayant le déploiement jusqu'à `max_deployment_retry_count` fois automatiquement (sans confirmation du client).

Pour garantir que des plantages inattendus du client ou des tickets abandonnés ne restent pas et n'occupent pas les ressources de votre matchmaker, les tickets non appariés seront annulés après `ticket_expiration_period` ce qui provoque le changement de leur statut en `ANNULÉ` puis définitivement supprimés après `ticket_removal_period` .

{% hint style="info" %}
[Découvrez comment le matchmaker maximise le taux de remplissage des matchs et réduit les temps d'attente à moins de 10 secondes.](https://docs.edgegap.com/learn/matchmaker-in-depth#find-match)
{% endhint %}

Le cœur de notre logique de matchmaking est configuré dans [#matchmaking-profiles](https://docs.edgegap.com/learn/matchmaker-in-depth#matchmaking-profiles "mention"). Chaque profil est une file d'attente de matchmaking complètement isolée, pointant vers [#app-versions](https://docs.edgegap.com/orchestration/application-and-versions#app-versions "mention") avec une quantité prédéfinie de ressources CPU et mémoire (RAM) requises.

[#matchmaking-rules](https://docs.edgegap.com/learn/matchmaker-in-depth#matchmaking-rules "mention") dans l'ensemble de règles initial doit être respecté pour que les joueurs soient regroupés, chaque règle définie par trois propriétés :

* nom de votre choix, par ex. - `taille du match`,
* type de règle, également appelé opérateur, par ex. - `player_count`,
* et enfin les attributs de l'opérateur, par ex. `team_count` ou `max_team_size`.

**Règle du nombre de joueurs**

C'est une règle spéciale définissant combien de joueurs doivent correspondre pour initier l'attribution :

* `team_count` se réfère au nombre d'équipes, 1 équipe peut être utilisée pour les modes coopératifs ou tous contre tous,
* `min_team_size` se réfère au nombre minimum de joueurs par équipe.
* `max_team_size` se réfère au nombre maximum de joueurs par équipe.

Notre exemple simple démontre un jeu coopératif avec 2 joueurs.

{% hint style="warning" %}
La règle Player Count **est requise et ne peut être définie qu'une seule fois** dans vos règles de configuration initiales.
{% endhint %}

**Règle des latences**

✅ Vous pouvez maintenant passer à l'étape suivante.

### 3. Examiner les détails de l'instance

☑️ Examinez les détails de votre nouveau matchmaker dans notre tableau de bord une fois qu'il est initialisé :

<figure><img src="https://3008966946-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2FY4Byy46pgEoXXmrtH92n%2Fimage.png?alt=media&#x26;token=3fb5fd0e-526e-4f89-ac9a-9ee6809aeaf1" alt=""><figcaption></figcaption></figure>

* **Statut** indique la santé du service, peut être EN LIGNE, HORS LIGNE ou ERREUR.
* **Identifiant** aide le personnel d'Edgegap à trouver rapidement votre matchmaker si vous avez besoin d'aide pour le dépannage.
* **Démarré le** peut être utile pour retrouver l'heure de la dernière mise à jour.
* **Taille** correspond à l'un de nos [Niveaux de tarification](https://edgegap.com/resources/pricing#matchmaker).
* **URL de l'API** sera utilisée par les clients de jeu et les serveurs de jeu pour communiquer avec votre matchmaker.
* **URL Swagger** est une interface pratique de spécification openAPI que nous fournissons pour explorer le schéma de l'API.
* **Jeton d'authentification** est un jeton secret unique utilisé par les clients de jeu et les serveurs de jeu pour l'authentification.

{% hint style="danger" %}
**Le personnel d'Edgegap ne demandera jamais vos jetons. Régénérez votre jeton si vous suspectez une faille de sécurité.**
{% endhint %}

Pour tester votre nouveau matchmaker, **vous aurez besoin de l'URL Swagger, de l'URL de l'API et du jeton d'authentification**.

✅ Vous pouvez maintenant passer à l'étape suivante.

{% hint style="info" %}
Pour mettre à jour vos règles de matchmaker en développement, modifiez votre configuration et redémarrez-la.
{% endhint %}

{% hint style="success" %}
Voir [#rolling-updates-and-ab-tests](https://docs.edgegap.com/learn/matchmaker-in-depth#rolling-updates-and-ab-tests "mention") pour les jeux en direct et les mises à jour sans interruption.
{% endhint %}

### 4. Tester l'API Tickets

{% hint style="info" %}
**Veuillez patienter jusqu'à 5 minutes** après avoir démarré votre matchmaker pour permettre la propagation DNS de se compléter.
{% endhint %}

☑️ D'abord, **ouvrez votre URL Swagger** pour inspecter votre schéma openAPI dans l'interface swagger :

<figure><img src="https://3008966946-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2FyFErlc8rw9KHMOqloIUF%2Fimage.png?alt=media&#x26;token=5a806adf-d644-4af6-b65e-9af82232bfcd" alt=""><figcaption></figcaption></figure>

☑️ Cliquez sur **Autoriser** 🔒, collez votre **Jeton d'authentification**, et confirmez en cliquant sur **Autoriser**.

<figure><img src="https://3008966946-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2FWnFM0p4UwDuo6Z5IOiUf%2Fimage.png?alt=media&#x26;token=7cbdff75-7f6b-467c-8df3-fa568b846dac" alt=""><figcaption></figcaption></figure>

☑️ Faites défiler vers **API Ticket** **- POST /tickets**, développez et cliquez sur **Essayez-le**.

<figure><img src="https://3008966946-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2FpxA3FxrxhlelzSWvb5CO%2Fimage.png?alt=media&#x26;token=8fc4fa97-44d5-48e3-8c02-c2dd49c6cd74" alt=""><figcaption></figcaption></figure>

☑️ Prévisualisez votre requête :

* remarquez `player_ip` défini sur `null` - cela fera que le Matchmaker utilise automatiquement l'adresse IP ajoutée à votre requête (voir [#server-to-server-api](https://docs.edgegap.com/learn/matchmaker-in-depth#server-to-server-api "mention") pour des alternatives),
* `profil` se réfère à votre [#matchmaking-profiles](https://docs.edgegap.com/learn/matchmaker-in-depth#matchmaking-profiles "mention"),
* `attributs` incluent des valeurs pour vos règles de matchmaker, dans ce cas pour la `latencies` règle,
  * règle `player_count` est la seule règle qui ne nécessite aucun attribut dans les tickets joueurs.

☑️ Cliquez sur **Exécuter** et examinez la réponse à votre requête de ticket joueur :

* `id` est votre identifiant unique de ticket de matchmaking, enregistrez-le pour vérifier votre ticket plus tard,
* `profil` confirmant le choix de [#matchmaking-profiles](https://docs.edgegap.com/learn/matchmaker-in-depth#matchmaking-profiles "mention"),
* `group_id` est un [identifiant de groupe unique attribué à chaque ticket, un joueur solo est représenté comme un groupe de 1](https://docs.edgegap.com/learn/matchmaker-in-depth#group-up),
* `team_id` est un identifiant d'équipe unique attribué à chaque joueur une fois que `TEAM_FOUND` le statut est atteint,
  * [chaque équipe peut contenir plusieurs groupes, sans dépasser la taille d'équipe configurée](https://docs.edgegap.com/learn/matchmaker-in-depth#matchmaking-rules),
* `player_ip` est l'adresse IP publique résolue du joueur, quel que soit le mode d'identification,
* `assignment` est défini sur `null` pour indiquer que le ticket n'a pas été apparié ou attribué à un serveur,
* `created_at` fournit des informations sur le moment où le ticket joueur a été créé pour l'interface utilisateur du jeu,
* `status` indique le statut actuel du ticket, tous les tickets commencent en `RECHERCHE` .

<figure><img src="https://3008966946-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2FZauPhgT9t1roetX4yc7g%2Fimage.png?alt=media&#x26;token=7834faf8-ce73-42dc-bae0-0293f05f1ea1" alt=""><figcaption></figcaption></figure>

☑️ Créez un second ticket en appuyant sur **Exécuter** à nouveau, afin que nos deux joueurs se correspondent et qu'un serveur soit démarré.

☑️ Réduisez POST /tickets et ouvrez **GET /tickets/{ticketId}**, puis cliquez sur **Essayez-le**.

☑️ Saisissez l'ID du ticket de la réponse à l'étape précédente et cliquez sur **Exécuter**.

<figure><img src="https://3008966946-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2FNznf5aHqhWefs77SFbzJ%2Fimage.png?alt=media&#x26;token=1d04803c-fbe6-4a19-9ef7-f814ea87affe" alt=""><figcaption></figcaption></figure>

☑️ Examinez l'attribution mise à jour pour votre ticket joueur :

* statut changé en `MATCH_FOUND` d'abord, tout en conservant `assignment` défini sur `null` pour indiquer que les joueurs ont été appariés et qu'un serveur est en cours d'attribution,

<figure><img src="https://3008966946-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2FGzBkyUepbqP71lFWG052%2Fimage.png?alt=media&#x26;token=a0412446-cc4f-4070-a14c-fef79046f3f7" alt=""><figcaption></figcaption></figure>

☑️ Cliquez sur **Exécuter** à nouveau pour vérifier votre ticket, et examinez l'attribution mise à jour de votre ticket :

* statut changé en `HOST_ASSIGNED` avec `assignment` contenant les détails du serveur assigné.

<figure><img src="https://3008966946-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2FWnbG4B1KFoxttkz5bALl%2Fimage.png?alt=media&#x26;token=12a10044-2117-4a6d-845a-76c243231552" alt=""><figcaption></figcaption></figure>

<details>

<summary>Dépannage et FAQ</summary>

Mon ticket est bloqué en `RECHERCHE` .

* Veuillez vérifier que vous avez créé suffisamment de tickets avec des critères qui se chevauchent et respectent votre configuration.

***

Mon ticket est coincé en changeant entre `MATCH_FOUND` et `TEAM_FOUND` de manière répétée.

* Les comptes du niveau gratuit sont limités à 1 déploiement à la fois. Veuillez envisager de passer à un niveau supérieur ou d'arrêter votre déploiement actuel pour en démarrer un nouveau.

***

Mon ticket passe directement à `ANNULÉ`.

* Votre ticket a atteint sa date d'expiration. Recréez un nouveau ticket ou augmentez la période d'expiration dans votre configuration à des fins de test.

***

Je reçois HTTP 404 Not Found en vérifiant mon ticket.

* Votre ticket a été supprimé soit par une requête DELETE, soit en atteignant sa période de suppression (commence après l'expiration du ticket, définie dans votre configuration). Recréez un nouveau ticket ou augmentez les périodes d'expiration/suppression dans votre configuration à des fins de test.

</details>

☑️ [Inspectez votre nouveau déploiement dans notre tableau de bord](https://app.edgegap.com/deployment-management/deployments/list):

* remarquez que chaque déploiement est étiqueté avec tous les IDs de tickets et le profil pour une traçabilité accrue.

<figure><img src="https://3008966946-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2FG4Ear9NrMHhgFH6T4ODB%2Fimage.png?alt=media&#x26;token=acc9831c-a9d2-4eb2-8c39-c81b8e61ddd2" alt=""><figcaption></figcaption></figure>

☑️ Essayez de vous connecter depuis votre client de jeu au serveur assigné.

{% hint style="warning" %}
Si vous rencontrez une latence élevée, votre intégration netcode peut être configurée pour simuler la latence réseau. **Désactivez le VPN lors des tests** pour des conditions plus réalistes et recevez un [déploiement à faible latence](https://docs.edgegap.com/orchestration/deployments#server-placement).
{% endhint %}

☑️ Une fois que vous avez vérifié que vous pouvez vous connecter à votre déploiement sans problème et que vous avez terminé les tests, **Arrêtez votre déploiement** pour libérer de la capacité dans votre compte pour la prochaine version.

✅ Vous pouvez maintenant passer à l'étape suivante.

{% hint style="info" %}
Trouvez la spécification openAPI pour les tests à `{matchmaker-url}/swagger/v1/swagger.json`.
{% endhint %}

### 5. Intégration au jeu

Le matchmaker s'intègre avec :

* **Client de jeu**, pour [gérer les groupes, les adhésions, les attributions et les tickets](https://docs.edgegap.com/learn/matchmaker-in-depth#group-up),
* **Serveur dédié**, pour [#backfill-match](https://docs.edgegap.com/learn/matchmaker-in-depth#backfill-match "mention") après qu'un joueur quitte.

☑️ Dans **Client de jeu**, nous recommandons de fournir des mises à jour du statut des tickets aux joueurs via l'interface utilisateur en jeu pour une meilleure expérience. Voir :

☑️ Dans **Client de jeu**, assurez-vous de gérer les erreurs réessayables `429 Trop de requêtes`  avec un backoff exponentiel et une nouvelle tentative, laissant le matchmaker récupérer pendant des pics de trafic soudains.

☑️ Dans **Client de jeu**, assurez-vous de gérer les erreurs non réessayables :

* `404 Introuvable` - le ticket a été supprimé,
* `500 Erreur interne du serveur` - panne temporaire du service.

☑️ Dans **Serveur de jeu**, lisez les préférences des joueurs et le contexte initial du serveur :

1. [Variables injectées (Matchmaker)](https://docs.edgegap.com/learn/matchmaker-in-depth#injected-environment-variables) **pour récupérer les données initiales de matchmaking des joueurs.**
2. [Variables injectées (Versions de l'application)](https://docs.edgegap.com/orchestration/application-and-versions#other-parameters-optional) pour les paramètres de version, les paramètres et les secrets.
3. [Variables injectées (Déploiement)](https://docs.edgegap.com/orchestration/deployments#injected-environment-variables) pour les informations de déploiement, IP, emplacement, etc...

☑️ Une fois que les joueurs sont connectés, **Serveur de jeu et clients de jeu** démarrent une scène de chargement - scène 3D, une interface sociale de type lobby, ou un écran de chargement avec une barre de progression, pour indiquer que l'initialisation progresse.

☑️ Assurez-vous que votre [déploiement sera arrêté](https://docs.edgegap.com/docs/deployment#stop-a-deployment) correctement une fois le match conclu.

🙌 Félicitations, vous avez terminé l'intégration du matchmaking ! Pour en savoir plus, continuez la lecture.

## 🏁 Exemple avancé

Une configuration complète utilisant toutes les fonctionnalités de matchmaking y compris [#matchmaking-profiles](https://docs.edgegap.com/learn/matchmaker-in-depth#matchmaking-profiles "mention"), [#matchmaking-rules](https://docs.edgegap.com/learn/matchmaker-in-depth#matchmaking-rules "mention"), et [#rule-expansion](https://docs.edgegap.com/learn/matchmaker-in-depth#rule-expansion "mention") peut ressembler à ceci :

## 🎾 Lobby personnalisé

Les lobbies personnalisés (lobbies privés, niveaux bac à sable) sont une option très populaire pour le multijoueur en canapé et pour tester de nouvelles fonctionnalités dans les jeux avant qu'elles n'entrent dans les principaux modes de jeu. Ils nécessitent généralement le moins de restrictions, mais visent à garantir que les joueurs peuvent [#group-up](https://docs.edgegap.com/learn/matchmaker-in-depth#group-up "mention").

{% hint style="info" %}
Pour les lobbies privés sans accès public, définissez `"team_size": 1`  et faites en sorte que le propriétaire du groupe lance le jeu seul. Le propriétaire peut partager les détails du groupe et de l'affectation de l'hôte à n'importe quel nombre de membres pour qu'ils rejoignent.
{% endhint %}

{% hint style="success" %}
Ajouter `custom-lobby-example`  profil **dans votre matchmaker existant** pour prendre en charge les lobbies personnalisés.
{% endhint %}

## 🥛 Vitrine Backfill

En s'appuyant sur [#simple-example](#simple-example "mention"), cette configuration présente [Backfill](https://docs.edgegap.com/learn/matchmaker-in-depth#backfill-match) avec [Groupes](https://docs.edgegap.com/learn/matchmaker-in-depth#group-up).

## ⚔️ Jeux compétitifs

Les jeux compétitifs se concentrent sur la compétition entre joueurs pour obtenir la victoire, que ce soit individuellement (tout le monde contre tout le monde) ou en équipe. Assurez des matchs équitables et équilibrés en appariant des joueurs ou des équipes de niveaux de compétence similaires, et maintenez le rythme du jeu en trouvant rapidement une compétition équitable.

Vous pouvez **définir plusieurs équipes avec 1 joueur ou plus chacune**, par exemple :

<table><thead><tr><th width="300">Mode de jeu</th><th>Nombre d'équipes</th><th>Taille d'équipe</th><th>Joueurs totaux</th></tr></thead><tbody><tr><td>FPS 5v5</td><td>2</td><td>5</td><td><strong>10</strong></td></tr><tr><td>MOBA 5v5</td><td>2</td><td>5</td><td><strong>10</strong></td></tr><tr><td>Battle Royale 20x3</td><td>20</td><td>3</td><td><strong>60</strong></td></tr><tr><td>Free For All 10 joueurs</td><td>1</td><td>10</td><td><strong>10</strong></td></tr></tbody></table>

Définir plusieurs [#matchmaking-profiles](https://docs.edgegap.com/learn/matchmaker-in-depth#matchmaking-profiles "mention") pour des règles et paramètres spécifiques au mode de jeu, et [étendre selon les besoins](https://docs.edgegap.com/learn/matchmaker-in-depth#rule-expansion).

* **Pour tous les matchs :**
  * restreindre [latence de matchmaking](https://docs.edgegap.com/learn/matchmaker-in-depth#ping-optimization) pour éviter d'apparier des joueurs éloignés,
  * [#group-up](https://docs.edgegap.com/learn/matchmaker-in-depth#group-up "mention") pour les groupes préformés et empêcher de dépasser les tailles d'équipe,
  * relâcher lentement les restrictions de latence au fil du temps pour trouver plus de joueurs,
  * allouer plus de CPU ou de mémoire avec différents [#app-versions](https://docs.edgegap.com/orchestration/application-and-versions#app-versions "mention") pour des profils spécifiques,
* **Pour les matchs occasionnels :**
  * omettre les restrictions de rang pour maximiser la vitesse de correspondance et le taux de remplissage des matchs,
  * laisser les joueurs fournir leurs préférences de carte pour trouver une carte adaptée à tous,
  * spécifier la taille du groupe de backfill pour remplacer les partants sans dépasser les tailles d'équipe,
  * supprimer les limitations de latence pour garantir un match après 3 minutes (180s) de temps d'attente.
* **Pour les matchs compétitifs :**
  * restreindre le rang pour n'autoriser que des adversaires de niveau de compétence similaire,
  * utiliser des montées ou descentes de rangs pour apparier les joueurs aux extrémités du classement de la ligue.
* **Pour le top 1 % des matchs de haute compétence (challengers) :**
  * utiliser des évaluations de compétence numériques (ELO) pour obtenir un contrôle fin sur la distribution des compétences dans les matchs,
  * attendre plus longtemps avant de relâcher les exigences de latence en raison du nombre réduit de joueurs.

{% hint style="success" %}
Utiliser plusieurs profils pour **séparer les modes de jeu occasionnels, les modes compétitifs et les challengers de haut niveau** joueurs vous permet de personnaliser les règles et les expansions pour chaque type de joueur séparément.
{% endhint %}

## 🤝 Jeux coopératifs

Les jeux coopératifs exigent que les joueurs travaillent ensemble en équipe vers un objectif commun, ou contre un adversaire IA. Alignez des joueurs ayant des préférences et des habitudes de jeu similaires. Remplacez les joueurs qui partent, et améliorez [#connection-quality](https://docs.edgegap.com/orchestration/ping-beacons#connection-quality "mention") pour offrir une expérience joueur réactive.

Avec un nombre d'équipes de 1 et une taille d'équipe maximale de 4, **exige jusqu'à 4 joueurs par match**.

Définir plusieurs [#matchmaking-profiles](https://docs.edgegap.com/learn/matchmaker-in-depth#matchmaking-profiles "mention") pour les règles et paramètres spécifiques aux modes de jeu :

* commencez avec un minimum de 4 joueurs pour maintenir les joueurs en file et maximiser le taux de remplissage des matchs,
* restreindre [latence de matchmaking](https://docs.edgegap.com/learn/matchmaker-in-depth#ping-optimization) pour éviter d'apparier des joueurs éloignés,
* laissez les joueurs choisir une difficulté de jeu particulière pour convenir au niveau de compétence de chacun,
* laisser les joueurs fournir leurs préférences de carte pour trouver une carte adaptée à tous,
* restreindre la différence de niveau des joueurs pour exiger un degré de progression similaire,
* spécifier la taille du groupe de backfill pour remplacer les partants sans dépasser la capacité du serveur,
* utiliser des indicateurs de modération pour séparer les joueurs à faible karma et les tricheurs de la population générale,
* [#group-up](https://docs.edgegap.com/learn/matchmaker-in-depth#group-up "mention") pour les groupes préformés et pour remplir les équipes sans dépasser la capacité du serveur,
* allouer plus de CPU ou de mémoire en utilisant différents [#app-versions](https://docs.edgegap.com/orchestration/application-and-versions#app-versions "mention") pour d'autres profils.

Commencez par les conditions idéales, et [étendez les restrictions](https://docs.edgegap.com/learn/matchmaker-in-depth#rule-expansion) pour assurer des matchs rapides :

* relâchez les restrictions de latence au fil du temps pour trouver plus de joueurs,
* augmentez la différence de niveau de joueur autorisée pour trouver plus de joueurs,
* diminuez la taille d'équipe minimale pour exiger moins de joueurs et lancer le jeu plus tôt,
  * le serveur peut remplir les emplacements vides avec des coéquipiers IA,
  * ou [#backfill-match](https://docs.edgegap.com/learn/matchmaker-in-depth#backfill-match "mention") pour ajouter des joueurs plus tard,
* définissez la taille d'équipe minimale à 1 pour lancer le jeu en solo après 150s de temps d'attente

## 🎈 Jeux sociaux

Les jeux sociaux se concentrent sur la création de liens et de relations entre les joueurs par la collaboration, la communication et l'expérience partagée. Prenez en charge un grand nombre de joueurs, maximisez le taux de remplissage des matchs et alignez les préférences et habitudes de jeu des joueurs. Remplacez les joueurs qui partent, et assurez une haute [#connection-quality](https://docs.edgegap.com/orchestration/ping-beacons#connection-quality "mention") pour offrir une expérience joueur réactive.

Avec un nombre d'équipes de 1 (free for all) et une taille d'équipe maximale de 50, **exige jusqu'à 50 joueurs par match**.

Définir [#matchmaking-profiles](https://docs.edgegap.com/learn/matchmaker-in-depth#matchmaking-profiles "mention") pour les règles et paramètres spécifiques aux modes de jeu :

* restreindre [latence de matchmaking](https://docs.edgegap.com/learn/matchmaker-in-depth#ping-optimization) pour éviter d'apparier des joueurs éloignés,
* laissez les joueurs indiquer leurs préférences de mode de jeu et trouvez un mode adapté à tous,
* spécifier la taille du groupe de backfill pour remplacer les partants sans dépasser la capacité du serveur,
* utiliser des indicateurs de modération pour séparer les joueurs à faible karma et les tricheurs de la population générale,
* [#group-up](https://docs.edgegap.com/learn/matchmaker-in-depth#group-up "mention") pour les lobbies préformés ou pour remplir les équipes sans dépasser la capacité du serveur,
* allouer plus de CPU ou de mémoire en utilisant différents [#app-versions](https://docs.edgegap.com/orchestration/application-and-versions#app-versions "mention") pour d'autres profils.

Commencez par les conditions idéales, et [étendez les restrictions](https://docs.edgegap.com/learn/matchmaker-in-depth#rule-expansion) pour assurer des matchs rapides :

* relâchez les restrictions de latence au fil du temps pour trouver plus de joueurs,
* diminuez lentement la taille d'équipe minimale pour exiger moins de joueurs et lancer le jeu plus tôt,
  * le serveur peut remplir les emplacements vides avec des joueurs IA,
  * ou [#backfill-match](https://docs.edgegap.com/learn/matchmaker-in-depth#backfill-match "mention") pour ajouter des joueurs plus tard,
* définissez la taille d'équipe minimale à 1 pour lancer le jeu en solo après 150s de temps d'attente

[^1]: remplacez par le nom de votre propre application

[^2]: remplacez par la version de votre propre application


# Regard approfondi

En savoir plus sur les concepts de matchmaker sans code d’Edgegap en profondeur et personnalisez-les selon vos besoins.

## ✔️ Introduction

**Commencez en 5 minutes et testez toutes les fonctionnalités gratuitement, sans carte de crédit requise.**

Passez à la version supérieure lorsque vous êtes prêt pour un cluster plus puissant et privé (dédié). L’intégration native avec Edgegap [deployments](https://docs.edgegap.com/learn/orchestration/deployments "mention") offre un ping de premier ordre où que soient vos joueurs.

{% hint style="info" %}
Le niveau gratuit permet 3 heures d’exécution après chaque redémarrage. Votre matchmaker fonctionnera sur une infrastructure partagée avec des ressources limitées, adaptée aux tests. **Après votre sortie publique, le matchmaker doit fonctionner 24/7.**
{% endhint %}

Il y a trois concepts essentiels pour chaque Matchmaker :

* [#hosting-cluster](#hosting-cluster "mention") - infrastructure serveur sous-jacente, entièrement gérée et exploitée par Edgegap.
* [#configuration](#configuration "mention") - ensemble de règles et de paramètres qui définissent le fonctionnement du matchmaker.
* 🌐 Instance de service **-** service de matchmaking en direct fonctionnant 24/7 sur le Cluster, utilisant la Configuration pour mettre les joueurs en relation et produire des affectations de déploiement (serveur).

{% hint style="success" %}
[Mettez fréquemment à jour votre version de matchmaker](#changelog) pour **profiter des nouvelles fonctionnalités et corrections de bugs.**
{% endhint %}

## ▶️ Démarrer le matchmaking

Découvrez le processus de matchmaking pour personnaliser, dépanner et optimiser l’intégration de votre jeu.

<figure><img src="https://3008966946-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2Fm4U4bgwucX6iGEieMISU%2Fimage.png?alt=media&#x26;token=39b97619-700b-4062-9dd9-73fa08fb96c2" alt=""><figcaption><p>Séquence de matchmaking</p></figcaption></figure>

1. [Authentifier le joueur](#authenticate) - empêche les copies piratées de jouer en ligne,
2. [Créer une lobby](#create-group) - rejoignez vos amis et partagez les préférences joueur/match,
3. [**Se regrouper**](#group-up) **- enregistrez votre Lobby en tant que groupe de matchmaking,**
4. [**Trouver un match**](#find-match) **- préparez-vous et commencez à chercher un match (nouveau ou existant),**
   1. Affecter le serveur et injecter les tickets - le serveur est automatiquement affecté après quelques secondes,
5. [**Se connecter et authentifier**](#connect-to-server) **- tenter une connexion sécurisée au serveur de jeu,**
   1. Confirmer l’identité - le serveur vérifie l’identité du client de jeu en utilisant des jetons tiers,
   2. Accepter ou expulser un joueur - le serveur décide si le joueur est autorisé à rejoindre.

**Commencez rapidement - ajoutez notre exemple de démarrage de matchmaking à votre jeu**:

### Authentifier

{% hint style="success" %}
**Ce jeton peut être inclus en toute sécurité dans votre client de jeu, car il n’accorde pas d’accès à l’API Edgegap.**
{% endhint %}

Les joueurs individuels peuvent être identifiés à l’aide de leur ID de ticket, disponible sur les clients et le serveur. Optionnellement, ajoutez une authentification personnalisée ou des limites avec un proxy personnalisé en utilisant [#server-to-server-api](#server-to-server-api "mention") l’API.

### Se regrouper

Créer un groupe (party) garantit que les joueurs rejoignent la même équipe et le même serveur avec leurs amis.

{% hint style="success" %}
Créez un groupe marqué prêt à [#find-match](#find-match "mention") aussi rapidement qu’un **joueur solo sans membres de groupe**.
{% endhint %}

<figure><img src="https://3008966946-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2FzPLV5ap16XQn0vYZsnQb%2FUntitled-2024-10-29-1018.png?alt=media&#x26;token=aa7165ab-abe1-4f7d-a84e-d2c4af8f36ad" alt=""><figcaption><p>Diagramme d’activité du cycle de vie du groupe</p></figcaption></figure>

#### Lobby et groupe

Utilisez un service de Lobby si la conception de votre jeu nécessite de définir des préférences de matchmaking contrôlées par le joueur (par ex. choix de personnage, difficulté, carte, etc.). Lorsque les joueurs rejoignent et quittent le Lobby, ils mettent également à jour le groupe de matchmaking pour se préparer à trouver un match plus tard.

{% hint style="success" %}
**Pas le temps pour un service de Lobby ?** Invitez les joueurs à partager les IDs de groupe via Discord ou messages privés.
{% endhint %}

<table><thead><tr><th width="390">Conception du jeu - Fonctionnalité / Exigence</th><th>Lobby pré-match</th><th>Groupe de matchmaker</th></tr></thead><tbody><tr><td><a data-footnote-ref href="#user-content-fn-1">inviter des amis à jouer avec moi</a></td><td>✅</td><td>✅</td></tr><tr><td>modifier mes préférences joueur/match</td><td>✅</td><td>❌</td></tr><tr><td>voir les préférences des autres membres du lobby</td><td>✅</td><td>❌</td></tr><tr><td>stocker et gérer des données personnalisées clé-valeur</td><td>✅</td><td>❌</td></tr><tr><td>notifier les membres du groupe que je suis prêt à jouer</td><td>❌</td><td>✅</td></tr><tr><td>afficher la progression du matchmaking et trouver un match</td><td>❌</td><td>✅</td></tr><tr><td>obtenir l’affectation d’équipe pour un joueur/groupe</td><td>❌</td><td>✅</td></tr><tr><td>récupérer les détails de connexion au serveur de jeu</td><td>❌</td><td>✅</td></tr></tbody></table>

Notre matchmaker multiplateforme prend en charge tous les services de Lobby commerciaux et personnalisés :

<table><thead><tr><th>Service Lobby (tiers)</th><th width="120" data-type="checkbox">Unreal Engine</th><th width="75" data-type="checkbox">Unity</th><th width="50" data-type="checkbox">PC</th><th width="90" data-type="checkbox">Consoles</th><th width="65" data-type="checkbox">VR/XR</th><th width="100" data-type="checkbox">Mobile</th></tr></thead><tbody><tr><td><a href="https://dev.epicgames.com/docs/game-services/lobbies-and-sessions/lobbies/lobbies-intro">Epic Online Services Lobby</a><br>(Epic Games)</td><td>true</td><td>true</td><td>true</td><td>true</td><td>true</td><td>true</td></tr><tr><td><a href="https://partner.steamgames.com/doc/features/multiplayer/matchmaking#friends">Steamworks Lobby</a><br>(Valve Corporation)</td><td>true</td><td>true</td><td>true</td><td>true</td><td>true</td><td>true</td></tr><tr><td><a href="https://heroiclabs.com/docs/nakama/concepts/groups/">Nakama Group</a><br>(Heroic Labs)</td><td>true</td><td>true</td><td>true</td><td>true</td><td>true</td><td>true</td></tr><tr><td><a href="https://learn.microsoft.com/en-us/gaming/playfab/community/associations/groups/quickstart">Playfab Lobby</a><br>(Microsoft)</td><td>true</td><td>true</td><td>true</td><td>true</td><td>true</td><td>true</td></tr><tr><td><a href="https://docs.braincloudservers.com/learn/key-concepts/multiplayer/lobbies/#lobby-experience">brainCloud Lobby</a><br>(bitHeads)</td><td>true</td><td>true</td><td>true</td><td>true</td><td>true</td><td>true</td></tr><tr><td><a href="https://developer.apple.com/documentation/gamekit/connecting-players-with-their-friends-in-your-game">Gamekit Friends</a><br>(Apple)</td><td>true</td><td>true</td><td>false</td><td>false</td><td>false</td><td>true</td></tr><tr><td>Lobby personnalisé<br>(votre entreprise)</td><td>true</td><td>true</td><td>true</td><td>true</td><td>true</td><td>true</td></tr></tbody></table>

Le propriétaire du Lobby (le joueur envoyant des invitations) doit également créer le groupe de matchmaking.

**Stockez l’ID de votre groupe dans vos données de lobby partagées**, afin que les autres membres du lobby puissent facilement trouver et rejoindre un groupe de matchmaking associé au lobby tiers. Les joueurs invités dans le groupe utilisent l’ID du groupe pour **créer leurs adhésions (rejoindre)**, et pour **stocker en toute sécurité leurs** [**attributs de matchmaking**](#matchmaking-rules)**.**

{% hint style="warning" %}
**Une fois qu’un groupe commence le matchmaking, il ne peut plus être rejoint.** [#abandon-queue](#abandon-queue "mention") et en créer un nouveau.
{% endhint %}

#### Optimisation du ping

Si [#configuration](#configuration "mention") comprend [`latences` règle](#rule-example-elo_rating) tous les membres du groupe envoient leurs [ping-beacons](https://docs.edgegap.com/learn/orchestration/ping-beacons "mention") mesures à **empêcher de mettre en relation des joueurs dans des régions éloignées** ou avec un ping (latence) beaucoup plus élevé/plus faible.

{% code title="Exemple de mesures de ping du client de jeu en millisecondes" %}

```json
{
  "Chicago" : 224,4,
  "Francfort" : 23,2,
  "Tokyo" : 167,4
}
```

{% endcode %}

#### **Abandonner la file d’attente**

Le propriétaire du groupe peut supprimer le groupe, supprimant automatiquement toutes les adhésions du groupe. Supprimer le groupe après le démarrage du matchmaking annulera toutes les adhésions, et les supprimera peu de temps après.

Les membres du groupe (à l’exception du propriétaire) peuvent supprimer leurs adhésions (quitter le groupe) à tout moment avant [#find-match](#find-match "mention"). Supprimer une adhésion par la suite annulera le matchmaking pour tout le groupe.

{% hint style="info" %}
Une fois le matchmaking annulé, les membres sont [retirés du matchmaking automatiquement](#matchmaking-profiles) et notifiés via l’adhésion `statut:CANCELLED`  dans leur prochaine réponse de sondage de statut.
{% endhint %}

Une fois annulé, si le groupe souhaite relancer le matchmaking, le propriétaire du groupe doit recréer le groupe, partager le nouvel ID de groupe avec les membres et leur faire recréer leurs adhésions.

**Une fois qu’un match est trouvé, le groupe ne peut pas être supprimé** (`409 Conflit`), et sera [supprimé automatiquement](#connect-to-server). Votre serveur devrait laisser un certain temps (par ex. 60 s) aux joueurs pour se connecter avant de supposer qu’un joueur a abandonné. Dans ce cas votre serveur peut :

* remplacer le joueur partant par un personnage IA pour démarrer immédiatement le match,
* ou créer un [backfill](#backfill-match) pour trouver un nouveau joueur pour remplacer le partant,
* ou poursuivre sans remplacer le partant, si la conception de votre jeu permet un nombre variable de joueurs.

### Trouver un match

Pour commencer à chercher un match, tous les membres et le propriétaire doivent se marquer comme prêts.

{% hint style="success" %}
Pour permettre au propriétaire du groupe de **démarrer le matchmaking immédiatement, marquez les adhésions comme prêtes lors de la création**. Une fois que le propriétaire se marque prêt, le matchmaking commencera, puisque tout le monde est prêt.
{% endhint %}

{% hint style="info" %}
Pour une meilleure expérience, **fournissez des mises à jour de statut aux joueurs via l’interface utilisateur en jeu**.
{% endhint %}

**Tous les joueurs doivent sonder leur adhésion à intervalles réguliers** (recommandé 3-5 s) pour détecter le démarrage du matchmaking, et pour communiquer la progression du matchmaking via l’interface utilisateur en jeu.

Les joueurs devraient **enregistrer de manière persistante leur ID d’adhésion et de groupe**, afin qu’en cas de plantage du client de jeu ils puissent relancer le jeu et reprendre sans perdre la progression du matchmaking.

Une fois que nous trouvons suffisamment de joueurs à placer dans la même équipe en respectant votre [#matchmaking-rules](#matchmaking-rules "mention"), les joueurs seront notifiés dans leur réponse d’adhésion avec `statut:TEAM_FOUND`.

Supprimer une adhésion à ce stade entraînera l’annulation de toutes les adhésions de groupe et le retour de toutes les autres équipes affectées au même équipage à `statut:SEARCHING` .

Les équipes continuent le matchmaking avec d’autres équipes en utilisant les valeurs communes entre leurs groupes (ou la moyenne dans le cas de `number_difference` ) jusqu’à ce que suffisamment d’équipes soient constituées. Les adhésions l’indiquent avec la réponse  `statut:MATCH_FOUND` , ce qui signifie que votre [déploiement est en cours de démarrage](https://docs.edgegap.com/orchestration/deployments#id-1.-start-a-deployment).

**Le matchmaker vise à maximiser le taux de remplissage des matchs, et ne passera pas à `MATCH_FOUND` jusqu’à ce que l’un des cas suivants :**

1. suffisamment d’équipes sont appariées avec la taille d’équipe maximale configurée,
2. ou si [#rule-expansion](#rule-expansion "mention") est défini ET le temps d’expansion est atteint, ET suffisamment d’équipes sont appariées avec la taille d’équipe minimale configurée,
3. ou que le temps d’expiration du ticket configuré soit écoulé ET suffisamment d’équipes sont appariées avec la taille d’équipe minimale configurée.

Si aucun des scénarios ne réussit avant l’expiration du ticket configuré, le groupe et les tickets sont annulés.

{% hint style="info" %}
Vous constatez de longs temps d’attente pendant les tests, ou avec des joueurs dans des régions moins populaires ? Réglez une période d’expiration de ticket plus courte (par ex. 30 s) et recréez le groupe (ou les tickets) côté client à l’expiration.
{% endhint %}

L’expiration du ticket se réinitialise automatiquement chaque fois qu’un groupe (ou un joueur) est apparié à une équipe.

{% hint style="success" %}
Stocker `team_id`  et `match_id` dans le backend de votre jeu pour afficher les informations des membres de l’équipe en jeu.
{% endhint %}

{% hint style="info" %}
Chaque joueur reçoit un **ID de ticket unique, qui peut être utilisé pour** [#authenticate](#authenticate "mention") **avec les serveurs de jeu.**
{% endhint %}

Si le joueur a été apparié et affecté à un serveur de jeu, son ticket est supprimé automatiquement. Les joueurs qui abandonnent la file d’attente après `statut:HOST_ASSIGNED`  peuvent être remplacés par [backfill](#backfill-match).

Une fois que les joueurs reçoivent `statut:HOST_ASSIGNED`  ils passent à [#connect-to-server](#connect-to-server "mention").

### Se connecter au serveur

### Backfill du match

Une fois l’initialisation du serveur de jeu terminée, **votre serveur doit**:

* **Démarrer le minuteur d’abandon pour chaque nouveau joueur.** Nous recommandons d’indiquer la progression du chargement aux joueurs connectés avec une scène/niveau de chargement - soit une scène 3D complète, une interface sociale de type lobby, ou un écran de chargement avec une barre de progression.
* **Suivez les nouvelles connexions de joueurs ou les départs de joueurs existants au fil du temps**:
  1. Les nouveaux joueurs doivent annoncer l’ID de ticket au serveur pour authentification et pour mapper leur connexion au matchmaker [#injected-variables](#injected-variables "mention") ou `assigned_ticket` (si backfilled).
  2. Créez de nouveaux backfills pour la capacité de joueur inutilisée (départs) tout au long de la durée de vie du serveur.
  3. Renouvelez les backfills expirés, qui sont supprimés après `ticket_expiration_period`.
* **Nettoyez (supprimez) tout backfill restant** une fois le [#id-5.-deployment-stopped](https://docs.edgegap.com/orchestration/deployments#id-5.-deployment-stopped "mention"):
  * Unity - [`OnApplicationQuit`](https://docs.unity3d.com/6000.0/Documentation/ScriptReference/MonoBehaviour.OnApplicationQuit.html) callback ou callback de fin de jeu personnalisé,
  * Unreal Engine - [`OnWorldDestroyed`](https://forums.unrealengine.com/t/call-function-before-quit-game/344954/2) , [`PreExit`](https://forums.unrealengine.com/t/event-on-close/298087/2) , ou un callback de fin de jeu personnalisé.

Tout profil peut être utilisé pour le Backfill tant qu’une affectation de serveur valide et au moins un ticket sont fournis. Voir [#backfill-showcase](https://docs.edgegap.com/learn/matchmaking/..#backfill-showcase "mention") pour un exemple minimal.

## ⚙️ Configuration

L’API du matchmaker est générée à partir d’une configuration JSON spécifiée lorsque vous créez un nouveau Matchmaker (ou redémarrage rapide). Vous pouvez spécifier n’importe quel nombre de profils avec des règles et expansions variées :

{% hint style="success" %}
Voir [](https://docs.edgegap.com/learn/matchmaking "mention") pour nos SDKs et des scénarios d’exemple détaillés.
{% endhint %}

{% hint style="warning" %}
Modifier un matchmaker en cours d’exécution **déclenchera un rechargement rapide**, supprimant tous les tickets et provoquant une brève période d’indisponibilité.
{% endhint %}

### Profils (Files d’attente) <a href="#matchmaking-profiles" id="matchmaking-profiles"></a>

Les profils représentent des files de matchmaking entièrement séparées, partageant la même version du matchmaker. Vous pouvez **configurer n’importe quel nombre de profils pour chaque matchmaker.** Diviser votre base de joueurs en plusieurs profils peut entraîner des temps d’attente plus longs pour vos joueurs.

Chaque profil de matchmaker utilise une [Version de l’application](https://docs.edgegap.com/learn/orchestration/application-and-versions) comme modèle pour démarrer de nouveaux déploiements (serveurs).

{% hint style="success" %}
Certaines modes de jeu peuvent nécessiter plus de vCPU / RAM, surtout s’ils prennent en charge un plus grand nombre de joueurs. Chaque **matchmaker peut inclure plusieurs profils**, chacun lié à une version d’application avec des ressources ajustées.
{% endhint %}

### Règles <a href="#matchmaking-rules" id="matchmaking-rules"></a>

Chaque joueur et groupe rejoint la file de matchmaking et trouve des matchs en utilisant  `initiales` règles au départ.

Chaque entrée dans le profil au chemin `.rules.initial` représente une règle, où :

* **clé** est une valeur chaîne pour nommer la règle comme vous le souhaitez ; par ex. `match_size` , et
* **valeur** est un objet définissant le type et les attributs de la règle, conformément à notre jeu de règles standard.

{% hint style="info" %}
Toutes les règles doivent être satisfaites simultanément pour initier l’affectation d’hôte et démarrer ou trouver un déploiement.
{% endhint %}

**Opérateurs (Type de règle)**

**`player_count`** est une règle spéciale définissant combien de joueurs doivent correspondre pour initier l’affectation.

{% hint style="warning" %}
Règle `player_count`  **est requise et ne peut être définie qu’une seule fois** dans vos règles de configuration initiales.
{% endhint %}

Le matchmaker s’efforce toujours de maximiser le taux de remplissage des matchs, jusqu’à la `max_team_size` :

1. spécifiée ; si la taille d’équipe maximale est atteinte, le match est constitué immédiatement,
2. sinon, les joueurs restent en file d’attente pour remplir le match jusqu’à ce que [l’expansion](#rule-expansion) (ou l’expiration) soit sur le point d’être écoulée,
3. peu avant [l’expansion](#rule-expansion) (ou l’expiration), si un match partiel est possible (≥ min et < max team size), ce match sera constitué avec tous les joueurs au même stade d’expansion (en supposant que les autres règles passent).

{% hint style="success" %}
Pour les modes coopératifs, free-for-all, ou à taille d’équipe asymétrique, définissez votre `"team_count": 1` .
{% endhint %}

Le nombre d’équipes peut être configuré pour composer plusieurs équipes équilibrées pour les jeux compétitifs :

* **les attributs du groupe sont calculés comme la moyenne/chevauchement** des **attributs des joueurs du groupe,**
* **les attributs de l’équipe sont calculés comme la moyenne/chevauchement** des attributs de **groupe de l’équipe.**

En supposant une taille d’équipe fixe de 4 joueurs :

<figure><img src="https://3008966946-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2FSFEzBayk3XNEUTIynjNd%2Fimage.png?alt=media&#x26;token=11a43fdf-3a99-4caa-8d2b-639e0f3cc06f" alt=""><figcaption><p>Scénarios d’exemple de match</p></figcaption></figure>

{% hint style="info" %}
**Les groupes s’apparentent en équipes sans sur-remplir,** uniquement si une équipe a une capacité suffisante pour accueillir tout le groupe.
{% endhint %}

**`string_equality`** apparie les joueurs ayant exactement la même valeur chaîne.

<details>

<summary>Exemple de règle : <code>selected_game_mode</code></summary>

`selected_game_mode`  la règle fera correspondre les joueurs en respectant la casse :

:white\_check\_mark: Alice + Bob + Dave peuvent être appariés,

:x: Alice + Erin, ou Charlie + Frank ne seront jamais appariés.

| "Free For All" | "Capture The Flag" | "capture the flag" |
| -------------- | ------------------ | ------------------ |
| Alice          | Erin               | Frank              |
| Bob            | Charlie            |                    |
| Dave           |                    |                    |

</details>

**`number_difference`** apparie les joueurs selon la différence numérique absolue entre eux.

<details>

<summary>Exemple de règle : <code>elo_rating</code></summary>

`elo_rating`  règle ci-dessus avec `"max_difference" : 50` initialement :

:white\_check\_mark: Alice + Bob peuvent être appariés, ou Bob + Charlie peuvent être appariés,

:x: Alice + Bob + Charlie ne seront jamais appariés.

<figure><img src="https://3008966946-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2FxtTxZ7TPSa8a8WtnGNAE%2Fimage.png?alt=media&#x26;token=c48b843b-c4e5-47bf-9154-07254a788067" alt=""><figcaption></figcaption></figure>

</details>

**`intersection`** apparie les joueurs avec une ou plusieurs valeurs chaîne qui se chevauchent, en respectant la casse.

<details>

<summary>Exemple de règle : <code>selected_map</code></summary>

`selected_map` règle ci-dessus avec `"overlap" : 1`  correspondra :

:white\_check\_mark: Alice + Bob + Charlie peuvent correspondre, ou Alice + Bob + Dave peuvent correspondre,

:x: Alice + Bob + Charlie + Dave ne correspondront jamais.

<figure><img src="https://3008966946-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2FcQSUAnRkZKVyuGjFWSYL%2Fimage.png?alt=media&#x26;token=bf1a4e28-230a-4c9a-9ef6-a0dea4dbecdb" alt=""><figcaption></figcaption></figure>

</details>

#### Expansion de règle

Optionnellement, **`les expansions`**  modifient les attributs d’une règle après une période passée en file d’attente pour assouplir les limitations et élargir le pool de joueurs pouvant être appariés, **ce qui entraîne des matchs plus rapides**.

<details>

<summary>Scénario d’exemple : Expansions</summary>

[Initialement, nous exigeons 1 équipe composée exactement de 4 joueurs (éventuellement divisés en groupes)](https://docs.edgegap.com/learn/matchmaking/..#advanced-example) avec :

* un maximum de 125 ms de latence contre le même (n’importe quel) beacon,
* une différence de latence de 125 ms ou moins entre la valeur la plus basse/la plus haute pour le même beacon,
* une différence de classement de compétence de 50 points ou moins entre le joueur le moins bien classé et le mieux classé,
* le même mode de jeu sélectionné (respect de la casse),
* au moins une sélection de carte correspondante (respect de la casse) parmi les joueurs,
* au moins une valeur correspondante de [taille de groupe de backfill](#backfill-match) parmi les joueurs.

Dans l’exemple ci-dessus, nous **élargissons la recherche en modifiant les attributs** après :

<table data-view="cards"><thead><tr><th></th><th></th></tr></thead><tbody><tr><td>30 secondes :</td><td><ul><li>4 joueurs</li><li><strong>plage d’elo de 150</strong></li><li><strong>latence max 250 ms</strong></li></ul></td></tr><tr><td>60 secondes :</td><td><ul><li>4 joueurs</li><li><strong>plage d’elo de 200</strong></li><li>latence max 250 ms</li></ul></td></tr><tr><td>3 minutes (180 s) :</td><td><ul><li><strong>1-4 joueurs</strong></li><li>plage d’elo de 200</li><li><strong>toute latence</strong></li></ul></td></tr></tbody></table>

</details>

<details>

<summary>Affinement des expansions</summary>

Prédire les préférences des joueurs est similaire à viser une cible en mouvement. Commencez avec un ensemble de règles moins restrictif au lancement et optimisez ensuite par itérations avec [#analytics](#analytics "mention").

Ces questions peuvent aider à cadrer votre réflexion :

* Quelle est la durée de ma session de jeu ?
  * Une session de 5 min signifie que chaque joueur rejoint la file toutes les 5 min, ce qui réduira indirectement le temps d’attente grâce à davantage de joueurs en file à un moment donné.
* Quel est mon [pic CCU](#user-content-fn-2)[^2] et mon [CCU de basse période](#user-content-fn-3)[^3]?
  * S’il y a une forte variance (plus de 60 %) entre bas/haut, vous pourriez avoir besoin d’un profil séparé pour la basse période afin d’attendre plus longtemps à chaque expansion, pour accumuler plus de joueurs.
* Quelle est la distribution géographique de mes joueurs ?
  * Une répartition homogène sur plusieurs fuseaux horaires signifie que le pic et la basse période ont une variance plus faible, mais n’améliore pas la vitesse de match puisque les joueurs de différentes régions ne devraient pas s’apparier si votre [#ping-optimization](#ping-optimization "mention") est correctement configuré (cela entraînerait un ping élevé).
* Quelle est la distribution des notes de compétence de mes joueurs (par région) ?
  * La distribution des compétences suit typiquement une [courbe en cloche](https://www.simplypsychology.org/normal-distribution.html) (distribution naturelle), donc à chaque écart-type par rapport à la moyenne, vous trouvez moins de joueurs plus éloignés de la moyenne. Les joueurs avec des valeurs moyennes seront appariés rapidement, lors de la première expansion, mais les extrêmes posent problème.
  * Nous recommandons d’augmenter la valeur de différence élargie à chaque expansion, par ex. 25 -> 50 -> 100, afin de tenir compte du fait qu’il y a moins de joueurs aux extrémités de la courbe.
  * Si vous avez une catégorie challenger (joueurs pro), nous recommandons un profil séparé avec une configuration de compétence personnalisée, car l’échantillon est plus petit et ne suit souvent pas la tendance macro sur l’ensemble de la base de joueurs. (tendance vers les extrêmes, courbe en cloche inversée)
* Comment puis-je améliorer la vitesse de matchmaking et le taux de remplissage des matchs avec une petite base de joueurs ?
  * Apprenez autant que possible sur vos joueurs et leurs préférences !
  * Envisagez de supprimer certaines règles ou d’assouplir les restrictions initialement.
  * Assouplissez la taille d’équipe ou le nombre d’équipes au fil du temps - un match partiel vaut mieux que pas de match.
  * Augmentez la durée entre les expansions pour accumuler plus de joueurs.
  * Contactez-nous pour plus d’astuces et conseils, spécifiquement pour la conception de votre jeu.

</details>

{% hint style="info" %}
Les expansions de n’importe quel attribut de règle **écraseront les valeurs précédentes** de cet attribut.
{% endhint %}

## 📌 Variables injectées

Votre serveur pourrait avoir besoin de connaître des détails sur ses joueurs. Les attributs des joueurs, les valeurs de match résolues et d’autres valeurs sont injectés dans votre déploiement parallèlement aux habituels [#injected-variables](https://docs.edgegap.com/orchestration/application-and-versions#injected-variables "mention").

Aperçu non formaté **🏁 Variables d’exemple avancées :**

```
MM_MATCH_PROFILE=advanced-example
MM_EXPANSION=initial
MM_TICKET_IDS=["cusfn10msflc73beiik0","cusfn18msflc73beiil0"]
MM_TICKET_cusfn10msflc73beiik0={"id":"cusfn10msflc73beiik0","created_at":"2025-02-21T22:17:42.3886970Z","player_ip":"174.93.233.25","group_id":"b2080c27-19c9-4fb0-8fe7-4bf1e5d285d1","team_id":"cusfn1gmsflc73beiim0","attributes":{"beacons":{"Chicago":12.3,"LosAngeles":145.6,"Tokyo":233.2},"elo_rating":1337,"selected_game_mode":"quickplay","selected_map":["DustII","Airport","BankVault"],"backfill_group_size":["new","1"]}}
MM_TICKET_cusfn18msflc73beiil0={"id":"cusfn18msflc73beiil0","created_at":"2025-02-21T22:17:42.2548390Z","player_ip":"174.93.233.23","group_id":"015d4dc8-6c79-4b5c-bbc6-f309b9787c8f","team_id":"cusfn1gmsflc73beiim0","attributes":{"beacons":{"Chicago":87.3,"LosAngeles":32.4,"Tokyo":253.2},"elo_rating":1339,"selected_game_mode":"quickplay","selected_map":["Island","Airport"],"backfill_group_size":["new","1"]}}
MM_GROUPS={"b2080c27-19c9-4fb0-8fe7-4bf1e5d285d1":["cusfn10msflc73beiik0"],"015d4dc8-6c79-4b5c-bbc6-f309b9787c8f":["cusfn18msflc73beiil0"]}
MM_TEAMS={"cusfn1gmsflc73beiim0":["b2080c27-19c9-4fb0-8fe7-4bf1e5d285d1","015d4dc8-6c79-4b5c-bbc6-f309b9787c8f"]}
MM_MATCH_ID=advanced-example_initial-2025-02-21T22:17:43.3886970Z
MM_INTERSECTION={"selected_map":["Airport"],"backfill_group_size":["new","1"]}
MM_EQUALITY={"selected_game_mode":"quickplay"}
```

{% hint style="info" %}
Les variables d’environnement sont **stockées sous forme de JSONs sous forme de chaîne**, analysez-les en utilisant notre SDK ou une méthode personnalisée.
{% endhint %}

{% hint style="success" %}
**Les serveurs peuvent mapper les connexions des joueurs aux groupes et aux attributs** après que le joueur envoie son ID de ticket au serveur.
{% endhint %}

## 🧵 Traçage des joueurs

Si vos joueurs rencontrent des problèmes, tracer leur chemin jusqu’aux logs du serveur peut être utile. Chaque **déploiement de Matchmaker** **sera étiqueté avec les IDs de tickets des joueurs affectés** afin que vous puissiez facilement [#filter-deployments](https://docs.edgegap.com/orchestration/deployments#filter-deployments "mention") et trouver [#container-logs](https://docs.edgegap.com/orchestration/deployments#container-logs "mention") pour vous aider à dépanner.

{% hint style="success" %}
**Affichez les IDs de ticket et les IDs de déploiement dans l’UI d’historique des matchs du client** pour tracer les joueurs lors du dépannage.
{% endhint %}

{% hint style="info" %}
Voir [#connection-quality](https://docs.edgegap.com/orchestration/deployments#connection-quality "mention") pour en savoir plus sur le dépannage des déploiements.
{% endhint %}

## 👀 Analytique

Obtenez des informations sur la charge et les performances de votre matchmaker, sans code ni configuration requise.

🌟 [**Passez le Matchmaker au niveau Enterprise**](https://app.edgegap.com/matchmaker-management-v2/matchmakers/list) **pour débloquer les métriques et insights du matchmaking :**

<figure><img src="https://3008966946-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2Fhb8NmB4ELuG7ayGLTeHs%2Fimage.png?alt=media&#x26;token=e3e0371e-c33f-48c8-bd15-5c11448dc633" alt=""><figcaption></figcaption></figure>

<figure><img src="https://3008966946-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2Fl0zTNccJASUTkJfTYxss%2Fimage.png?alt=media&#x26;token=0d061320-9524-4b12-83e6-ea9112ef1409" alt=""><figcaption></figcaption></figure>

## ☁️ Cluster d’hébergement

Le matchmaker est hébergé et géré 24/7 par Edgegap.

Choisissez une option d’hébergement la mieux adaptée à votre objectif :

#### Niveaux de cluster privé

Passez à un cluster privé en un clic. Changer de niveau de cluster privé après le lancement, sans aucune indisponibilité pour les joueurs, est aussi possible avec [#rolling-updates-and-ab-tests](#rolling-updates-and-ab-tests "mention"). Les clusters gérés fournissent un hébergement de service à haute disponibilité maintenu par Edgegap avec support en direct 24/7 pour les jeux publiés.

Les besoins en ressources pour votre instance dépendront des facteurs suivants :

* **nombre de joueurs** - plus de joueurs entraînent plus de tickets et de requêtes API,
* **nombre de requêtes par joueur** - des tentatives de nouvelle requête plus rapides augmentent la charge du service et consomment des ressources,
* **complexité de la configuration** - les règles d’intersection et les expansions sont particulièrement exigeantes,
* **durée moyenne du match** - des sessions plus courtes font que les joueurs rejoignent le matchmaking plus souvent,
* **périodes d’expiration et de suppression** - les tickets obsolètes s’accumulent avec le temps et consomment des ressources,
* **logique de repli de nouvelle tentative côté client** - réessayer avec un backoff jitter aide à étaler les pics de trafic.

{% hint style="warning" %}
**Préparez-vous au succès et optimisez après le lancement, afin de ne pas bloquer vos joueurs le jour de la sortie.** Utilisez [#matchmaking-sdk](https://docs.edgegap.com/unity/developer-tools#matchmaking-sdk "mention") ou **implémentez un backoff exponentiel avec jitter** pour récupérer d’une forte charge.
{% endhint %}

### Limites de débit

Pour protéger votre cluster contre le dépassement de sa capacité de rafale et un crash, nous limitons le nombre de requêtes par seconde en nous basant sur nos tests de charge internes en utilisant [#advanced-example](https://docs.edgegap.com/learn/matchmaking/..#advanced-example "mention") la configuration.

<table><thead><tr><th>Point de terminaison API</th><th width="130">Niveau Gratuit</th><th width="130">Niveau Hobbyiste</th><th width="130">Niveau Studio</th><th width="130">Niveau Entreprise</th></tr></thead><tbody><tr><td><strong>Limite globale</strong></td><td><strong>100</strong></td><td><strong>200</strong></td><td><strong>750</strong></td><td><strong>2,000</strong></td></tr><tr><td>Créer un déploiement</td><td>5</td><td>10</td><td>30</td><td>30</td></tr><tr><td>Lister les balises</td><td>10</td><td>20</td><td>75</td><td>200</td></tr><tr><td>Créer un groupe<br>+ Créer un ticket<br>+ Créer un ticket de groupe</td><td>10</td><td>20</td><td>75</td><td>200</td></tr><tr><td>Lire l'appartenance<br>+ Lire le groupe<br>+ Lire le ticket</td><td>10</td><td>120</td><td>450</td><td>1,300</td></tr><tr><td>Créer un backfill</td><td>5</td><td>10</td><td>37</td><td>100</td></tr></tbody></table>

Les limites de débit sont exprimées en **requêtes combinées par seconde vers l'ensemble spécifié de points de terminaison API**.

Si vos clients de jeu ne réessaient pas les requêtes après avoir reçu une réponse `429 Trop de requêtes`  **vos déploiements peuvent manquer des joueurs** qui arrêtent de lire leurs affectations en raison d'une forte charge.

#### Test de charge

Le matchmaking et les affectations nécessitent l'utilisation du CPU et de la mémoire, entraînant un coût d'hébergement pour chaque matchmaker privé. Consultez les ressources et les prix associés à chaque niveau sur [notre page de tarification](https://edgegap.com/resources/pricing#matchmaker).

{% hint style="success" %}
**Utilisez toujours** [**clusters privés**](#private-cluster-tiers) **pour les tests de stress.** Les matchmakers gratuits sont strictement limités aux tests de développement uniquement.
{% endhint %}

Lors de la conception de votre test de charge, **veuillez prendre en compte des schémas de joueurs réalistes**:

| Scénario réaliste                                                                                            | Schéma de trafic irréaliste                                                                                 |
| ------------------------------------------------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------- |
| ✅ Les joueurs rejoignent le matchmaking progressivement, augmentant les req/s sur plusieurs heures.          | ❌ Tous les joueurs se coordonnent et créent leurs tickets à la même seconde exacte.                         |
| ✅ Les joueurs attendent un temps croissant entre leurs nouvelles tentatives (par ex. 1s-5s-10s-10s).         | ❌ Tous les joueurs réessaient immédiatement après avoir reçu `429 Trop de requêtes`  la réponse.            |
| ✅ La plupart des joueurs recevront leurs affectations en peu de temps (10-60s) et arrêteront le polling.     | ❌ Tous les joueurs continuent à interroger pendant une durée définie même après avoir reçu une affectation. |
| ✅ La plupart des joueurs terminent leur partie (ce qui prend du temps) avant de relancer le matchmaking.     | ❌ Tous les joueurs relancent immédiatement le matchmaking après avoir reçu leur affectation.                |
| ✅ Le trafic de pointe est soutenu pendant 6-8 heures par jour, après quoi certains fuseaux horaires chutent. | ❌ Le trafic de pointe est soutenu 24 heures sur 24, avec tous les joueurs jouant nuit et jour.              |

Si un matchmaker subit une forte charge :

* si le CPU est limité, le matchmaking peut être ralenti,
* si le matchmaker manque de mémoire, il redémarrera sans perdre les informations des tickets, en espérant que les clients implémentent un backoff exponentiel et que le pic soit étalé sur une période plus longue.

## ⏩ Mises à jour progressives <a href="#rolling-updates-and-ab-tests" id="rolling-updates-and-ab-tests"></a>

Suivre la compatibilité entre les versions serveur et client peut devenir compliqué. Suivez nos conseils pour des releases et mises à jour fiables et pour éviter les temps d'arrêt ou les problèmes de compatibilité.

**Votre URL de Matchmaker et le jeton d'authentification resteront toujours les mêmes après un redémarrage.**

{% hint style="danger" %}
**Créez des matchmakers séparés pour dev & production** environnements pour expérimenter en toute sécurité.
{% endhint %}

#### ⚠️ **Avant la mise en ligne**

Nous recommandons de créer plusieurs copies de votre matchmaker à l'avance : `vert`, `bleu` et `orange`. Vous pouvez faire pivoter le matchmaker en service lorsque vous publiez des mises à jour ([stratégie blue/green](https://en.wikipedia.org/wiki/Blue%E2%80%93green_deployment)).

**Choisissez des régions différentes pour chaque instance afin de prévenir les temps d'arrêt** lors d'incidents localisés.

<figure><img src="https://3008966946-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2Flzy4elHYDPBMpjSMG1HS%2Fimage.png?alt=media&#x26;token=7da795fc-ae6c-490f-b65c-5f8dda635503" alt=""><figcaption><p>Exemple d'environnement DevOps Blue/Green</p></figcaption></figure>

#### **🔃 Mise à jour Client + Serveur**

**Pré-requis :** Cette section suppose que vous avez complété [#before-going-live](#before-going-live "mention").

Afin de **publier des mises à jour client + serveur du jeu**, vous pouvez :

1. Préparer une nouvelle version de l'application serveur `v1.2.0-rc` sur Edgegap :
   1. pousser une nouvelle étiquette d'image vers votre registre de conteneurs `t1.2.0`,
   2. créer une nouvelle version d'application `v1.2.0-rc`,
2. Effectuer des tests dev en [déployant votre nouvelle version d'application](https://app.edgegap.com/deployment-management/deployments/list) `v1.2.0-rc`:
   1. connecter l'éditeur de votre moteur de jeu à l'URL fournie + port externe,
3. Mettre à jour le matchmaker inutilisé `bleu` pour le lier à votre nouvelle étiquette d'image `t1.2.0`,
   1. activer la mise en cache pour la nouvelle version de l'application `v1.2.0-rc` , activer le cache pour cette version garantira que l'image est également mise en cache pour la version `v-blue`  puisqu'elles référencent la même étiquette,
   2. attendre que l'indicateur de mise en cache dans la version `v1.2.0-rc`  atteigne :green\_circle: vert,
4. Mettez à jour votre nouveau client de jeu `c2` pour utiliser la nouvelle version `v-blue` lors de la création des tickets :
   1. mettez à jour votre URL de base et le jeton d'autorisation dans le client de jeu,
5. Effectuez des tests QA et des vérifications finales de votre nouveau client de jeu `c2`:
   1. si vous trouvez et résolvez des problèmes, répétez le processus depuis le début,
   2. attendre 3-7 jours pour propager les changements DNS du matchmaker auprès des FAI globalement, après l'arrêt du matchmaker (un redémarrage rapide n'exige pas de mises à jour DNS ni de période d'attente),
6. Publiez la mise à jour de votre nouveau client de jeu `c2` sur les plateformes de distribution de jeux,
7. Laissez le temps au nouveau client de jeu `c2` de se distribuer aux appareils des joueurs (généralement jusqu'à 3-7 jours) :
   1. surveillez les clients de jeu obsolètes `c1`  en utilisant le déploiement [#analytics](https://docs.edgegap.com/orchestration/deployments#analytics "mention"),
8. Nettoyez les ressources inutilisées dans votre compte Edgegap :
   1. supprimer l'étiquette d'image `t1.0.0` pour libérer de la capacité dans le registre de conteneurs,
   2. supprimer l'étiquette d'image `t1.1.0` pour libérer de la capacité dans le registre de conteneurs,
   3. éteignez votre `vert`  matchmaker pour suspendre la facturation jusqu'à votre prochaine mise à jour.

{% hint style="success" %}
**Pour votre prochaine mise à jour**, augmentez les numéros de version et échangez `vert` et `bleu` mots-clés dans le guide.
{% endhint %}

#### **⚡ Correctif serveur**

**Pré-requis :** Cette section suppose que vous avez complété [#before-going-live](#before-going-live "mention").

Pour **publier un patch serveur sans nécessiter de mise à jour du client de jeu**, vous pouvez :

1. Préparer une nouvelle version de l'application serveur `v1.2.0-rc` sur Edgegap :
   1. pousser une nouvelle étiquette d'image vers votre registre de conteneurs `t1.2.0`,
   2. créer une nouvelle version d'application `v1.2.0-rc`,
2. Effectuez des tests et des vérifications en [déployant votre nouvelle version d'application](https://app.edgegap.com/deployment-management/deployments/list) `v1.2.0-rc`:
   1. connecter l'éditeur de votre moteur de jeu à l'URL fournie + port externe,
   2. si vous trouvez et résolvez des problèmes, répétez le processus depuis le début,
   3. activer la mise en cache pour la nouvelle version de l'application `v1.2.0-rc` , activer le cache pour cette version garantira que l'image est également mise en cache pour la version `v-green`  plus tard puisqu'ils référenceront la même étiquette,
   4. attendre que l'indicateur de mise en cache dans la version `v1.2.0-rc`  atteigne :green\_circle: vert,
3. Mettre à jour la version `v-green`  pour le lier à votre nouvelle étiquette d'image `t1.2.0`,
   1. les nouveaux matchs initieront automatiquement l'affectation avec l'étiquette mise à jour `t1.2.0`,
   2. surveillez les clients de jeu obsolètes `c1`  en utilisant le déploiement [#analytics](https://docs.edgegap.com/orchestration/deployments#analytics "mention"),
4. Nettoyage des ressources inutilisées dans votre compte Edgegap :
   1. supprimer l'étiquette d'image `t1.1.0` pour libérer de la capacité dans le registre de conteneurs.

## 📗 API <a href="#matchmaking-api" id="matchmaking-api"></a>

Les clients et serveurs peuvent appeler l'API directement ou via les SDK des moteurs de jeu, voir aussi [](https://docs.edgegap.com/learn/matchmaking "mention").

### Serveur à Serveur <a href="#server-to-server-api" id="server-to-server-api"></a>

Ajoutez des contrôles améliorés ou personnalisés sur le flux de matchmaking - implémentez un proxy personnalisé en utilisant notre [managed-clusters](https://docs.edgegap.com/learn/advanced-features/managed-clusters "mention") ou n'importe quel cloud FaaS[^4] plateforme de calcul, pour obtenir l'un des éléments suivants :

* attacher des attributs sensibles du joueur - tels que des drapeaux de tricheur, des classements de compétence, ou similaires,
* fournir le contexte d'équipe et de match en jeu - lister mes coéquipiers et adversaires pendant le chargement,
* restreindre des cas limites spécifiques - par ex. autoriser seulement 1 groupe par joueur à tout moment,
* ajouter de la mise en cache ou des limites de débit API - réduire le nombre de requêtes et la charge sur le matchmaker,
* personnaliser l'intégration lobby-groupe - créer des lobbies asymétriques/basés sur des rôles avant le matchmaking.

{% hint style="success" %}
**Inclure le paramètre `player_ip`  avec l'adresse IP publique du membre** pour garantir la latence la plus faible possible pour le joueur et profiter de [#id-1.-server-score-strategy-best-practice](https://docs.edgegap.com/orchestration/deployments#id-1.-server-score-strategy-best-practice "mention").
{% endhint %}

{% hint style="info" %}
Les clients de jeu peuvent utiliser [ipify.org](http://ipify.org/) service gratuit pour trouver leurs IP publiques. Les VPN peuvent masquer l'adresse IP publique.
{% endhint %}

<figure><img src="https://3008966946-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2FzLfA3fEBgwaziGtp2yMO%2Fimage.png?alt=media&#x26;token=3d551e74-4a60-47a6-9d79-a506f961663d" alt=""><figcaption><p>Diagramme d'activité du matchmaking Serveur à Serveur</p></figcaption></figure>

#### Partage de ressources cross-origin (CORS)

Pour les jeux WebGL hébergés sur des plateformes de distribution tierces (par ex. [itch.io](http://itch.io/)), l'envoi de requêtes vers le Matchmaker depuis le client de jeu peut entraîner [des violations de la politique de partage de ressources cross-origin](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS) . La plupart des navigateurs web modernes envoient une [requête préliminaire](https://developer.mozilla.org/en-US/docs/Glossary/Preflight_request) pour vérifier qu'un service backend (le Matchmaker) comprend et accepte la communication depuis votre client de jeu.

L'échec de la vérification préliminaire (par défaut pour des raisons de sécurité) peut entraîner [l'une des plusieurs erreurs possibles liées au CORS](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS/Errors/CORSMissingAllowOrigin), le plus souvent `En-tête CORS 'Access-Control-Allow-Origin' manquant` .

Pour résoudre cette erreur, ajoutez le **`paramètre allowed_cors_origin`** à votre configuration pour soit :

* mettre en liste blanche vos domaines d'hébergement client exacts :

<details>

<summary>🍀 Exemple simple (Exemple de domaines spécifiques)</summary>

<pre class="language-json"><code class="lang-json">{
  "version": "3.2.0",
  "allowed_cors_origins": [
    "https://dev.my-game-server.com",
    "https://prod.my-game-server.com"
  ],
  "profiles": {
      <a data-footnote-ref href="#user-content-fn-5">...</a>
  }
}
</code></pre>

</details>

* ou mettre en liste blanche un domaine générique (incluant tous les sous-domaines) :

<details>

<summary>🍀 Exemple simple (Exemple de domaine générique)</summary>

<pre class="language-json"><code class="lang-json">{
  "version": "3.2.0",
  "allowed_cors_origins": ["https://*.my-game-server.com"],
  "profiles": {
      <a data-footnote-ref href="#user-content-fn-5">...</a>
  }
}
</code></pre>

</details>

{% hint style="info" %}
**Aucune authentification n'est requise pour les requêtes préliminaires du Matchmaker**, si les domaines sont configurés correctement.
{% endhint %}

## 🚨 Dépannage

**Votre succès est notre priorité.** Si vous souhaitez envoyer des requêtes personnalisées, demander des fonctionnalités critiques manquantes, ou partager des remarques, [veuillez nous contacter sur notre Discord communautaire](https://discord.gg/MmJf8fWjnt).

<details>

<summary>Pourquoi est-ce que j'obtiens des erreurs en essayant de créer un nouveau matchmaker ?</summary>

* Veuillez lire l'erreur, il est possible que vous ayez mal orthographié un identifiant, une règle, ou un opérateur. - Utilisez [JSONLint](https://jsonlint.com/) pour valider le formatage de votre JSON, il se peut que vous ayez oublié une virgule ou une parenthèse. - Contactez-nous via [notre Discord communautaire](https://discord.gg/MmJf8fWjnt) pour obtenir de l'aide, nous serons heureux d'assister. 🙏

</details>

<details>

<summary>Pourquoi mon matchmaker s'est-il éteint automatiquement après 3 heures ?</summary>

* Les matchmakers du niveau Gratuit sont destinés aux tests initiaux et sont automatiquement éteints après 3 heures. Pour continuer les tests, vous pouvez [redémarrer votre matchmaker](https://app.edgegap.com/matchmaker-management-v2/matchmakers/list).
* Envisagez de passer à un niveau payant pour un temps d'exécution illimité.

</details>

<details>

<summary>Pourquoi ne puis-je pas démarrer un deuxième déploiement sur mon compte ?</summary>

* Vous ne pouvez exécuter qu'un seul déploiement simultané dans le niveau Gratuit.
* Veuillez envisager de passer à un niveau payant pour des déploiements illimités.

</details>

<details>

<summary>Pourquoi est-ce que je reçois des affectations/déploiements à des moments aléatoires, sans tenir compte de <code>player_count</code>?</summary>

* Vous ou un autre membre de l'équipe avez peut-être créé des tickets lors d'une session de test précédente qui n'ont pas été affectés. Veuillez [redémarrer votre matchmaker](https://app.edgegap.com/matchmaker-management-v2/matchmakers/list).

</details>

<details>

<summary>Mon ticket est bloqué dans <code>RECHERCHE</code> .</summary>

* Veuillez vérifier que vous avez créé suffisamment de tickets correspondants respectant votre configuration.

</details>

<details>

<summary>Mon ticket est bloqué en changeant entre <code>MATCH_FOUND</code> et <code>ÉQUIPE_TROUVÉE</code> à plusieurs reprises.</summary>

* Les comptes du niveau Gratuit sont limités à 1 déploiement à la fois.
* Veuillez envisager de passer à un niveau supérieur ou d'arrêter votre déploiement actuel pour en démarrer un nouveau.

</details>

<details>

<summary>Mon ticket passe directement à <code>ANNULÉ</code>.</summary>

* Votre ticket a atteint son expiration. Créez un nouveau ticket ou augmentez la période d'expiration dans votre configuration à des fins de test.

</details>

<details>

<summary>Je reçois <code>HTTP 404 Introuvable</code> lorsque je vérifie mon ticket.</summary>

* Votre ticket a été supprimé soit par une requête DELETE, soit en atteignant sa période de suppression (commence après que le ticket a expiré, définie dans votre configuration). Recréez un nouveau ticket ou augmentez les périodes d'expiration/suppression dans votre configuration à des fins de test.

</details>

<details>

<summary>Mon matchmaker affiche une erreur, que dois-je faire ?</summary>

* S'il s'agit d'une instance de développement ou de test, essayez de redémarrer d'abord votre matchmaker. - Veuillez signaler tout problème via [notre Discord communautaire](https://discord.gg/MmJf8fWjnt).
* Dans le cas où ce problème impacte un jeu en direct, créez une [demande de support urgente](https://edgegap.atlassian.net/servicedesk/customer/portal/3).

</details>

## 🔖 Journal des modifications

Votre fichier de configuration sera validé en fonction de la version du matchmaker utilisée, assurez-vous que vos règles correspondent aux capacités de la version du matchmaker.

{% hint style="info" %}
**La dernière version du matchmaker est `3.2.1`**. Tous les exemples sur cette page sont à jour. Surveillez les avis de fin de support pour la version de votre matchmaker. Voir aussi [#rolling-updates-and-ab-tests](#rolling-updates-and-ab-tests "mention").
{% endhint %}

#### 3.2.1 (24 nov. 2025)

{% hint style="success" %}
**Ceci est la dernière version du service matchmaker, recommandée pour une utilisation en production.**
{% endhint %}

{% hint style="warning" %}
**Pour mettre à niveau la version de votre matchmaker - Arrêtez, Éditez, Redémarrez.** Le redémarrage rapide n'appliquera pas les changements de version.
{% endhint %}

🩹 **Corrections de bugs :**

* Corrections de bugs mineurs de déploiement, résolution de plusieurs erreurs lors du démarrage de votre matchmaker.

#### 3.2.0 (31 oct. 2025)

🩹 **Corrections de bugs :**

* Diverses petites corrections de spécification et mises à jour de cohérence de la documentation.
* Divers correctifs de stabilité et d'auto-réparation dans l'infrastructure du matchmaker.

**✨ Améliorations et nouvelles fonctionnalités :**

* **Introduction de** [#group-up](#group-up "mention") **fonctionnalité** - la gestion des groupes est désormais facile et ne nécessite pas de tiers !
  * Fini le partage d'attributs complexes de ticket entre les membres du groupe, vous n'avez besoin que de l'ID de groupe.
  * Commencez à faire correspondre en tant que groupe une fois que tous vos joueurs se sont déclarés prêts.
  * Validez les attributs des membres du groupe par rapport au leader du groupe lors de la jonction, empêchant les groupes non appariables (les attributs des joueurs du groupe ne correspondraient pas aux règles du profil).
  * Validez la taille du groupe et refusez les nouvelles adhésions une fois la taille d'équipe maximale atteinte.
  * Lisez notre documentation mise à jour avec le nouveau flux utilisateur, mises à jour SDK bientôt disponibles !
* Les tickets (appartenances) incluent désormais votre ID de match - suivez les joueurs et ajoutez des éléments UI pour partager les surnoms de votre équipe ou des équipes adverses, le classement de compétence, ou d'autres propriétés stockées chez des tiers.
* Refonte [#rate-limits](#rate-limits "mention") majeure basée sur des tests de stress internes, meilleure gestion des courtes rafales.
* Taux de remplissage des matchs amélioré en retardant la taille des matchs partiels jusqu'à la fin de l'expansion.
  * Si la taille maximale de l'équipe est atteinte, match immédiat.
  * Sinon, faire le match à la fin de l'expansion en cours, si la taille minimale de l'équipe est atteinte.
* Définissez les périodes d'expiration et de suppression par profil et optimisez pour la meilleure expérience joueur.

{% hint style="warning" %}
Pour mettre à jour votre configuration, augmentez la version et copiez les champs d'expiration et de suppression dans chaque profil.
{% endhint %}

#### 3.1.0 (10 juin 2025)

🩹 **Corrections de bugs :**

* Les matchmakers valident désormais correctement les tickets avec plusieurs profils incluant des règles différentes.

**✨ Améliorations et nouvelles fonctionnalités :**

* Plus d'optimisations pour maximiser le taux de remplissage des matchs avec [règle player\_count](#matchmaking-rules). Les tickets attendront désormais la fin de l'expansion (ou l'expiration) si seul un match partiel est possible (>min et \<max taille d'équipe).
  * Les matches complets (taille d'équipe maximale atteinte) sont effectués immédiatement (aucun changement).
* Passez à Enterprise [#hosting-cluster](#hosting-cluster "mention") pour débloquer le matchmaking [#analytics](#analytics "mention")! Obtenez des informations sur la charge et la performance du matchmaker, sans code ni configuration requis. Les métriques au lancement incluent :
  * tickets totaux, backfills, affectations et déploiements effectués sur une période personnalisée,
  * taux par minute pour les métriques ci-dessus sur une période personnalisée,
  * totaux et séries temporelles des tickets expirés, matchs étendus, taux de remplissage des matchs,
  * métriques d'utilisation de l'API, et plus encore.
* Documentation [#matchmaking-rules](#matchmaking-rules "mention") améliorée avec de meilleurs exemples et visuels.

#### 3.0.0 (20 mai 2025)

**⚠️ Changements incompatibles :**

* Utilisez [taille min/max d'équipe pour remplir les équipes efficacement](#matchmaking-rules) (remplace les expansions basées sur le nombre de joueurs) :
  * dans votre configuration `player_count` règle, remplacez `team_size` par `min_team_size` et `max_team_size` pour atteindre le matching en "meilleur effort" visant à maximiser le taux de remplissage des matchs,
  * pour exiger un nombre spécifique de joueurs par équipe, définissez min et max à la même valeur,
  * les backfills contournent la `player_count` règle et correspondent toujours avec 1 ticket (inchangé).
* Les tickets, tickets de groupe et backfills avec toutes les latences supérieures à la plus élevée `max_latency` dans un profil donné seront immédiatement rejetés avec `400 Requête incorrecte` en réponse à la requête de création de ticket, au lieu d'expirer :
  * s'applique uniquement si [règle de latence](#matchmaking-rules) est configurée,
  * pour contourner ce comportement, créez une expansion avec `max_latency: 99999` (toute valeur supérieure à votre délai d'attente de mesure de latence client).
* [Les variables d'environnement injectées](#injected-environment-variables) contenant les données du ticket incluent désormais le champ `id` (ID du ticket) afin qu'elles puissent être réutilisées plus facilement lors de la création [#backfills](#backfills "mention").

🩹 **Corrections de bugs :**

* [#backfill](#backfill "mention") utilise désormais la période de suppression et d'expiration configurée (comme les tickets et tickets de groupe).
* [#backfill](#backfill "mention") correspond désormais correctement en utilisant les [`intersection` règles](#matchmaking-rules).
* Corrigé [spécification openAPI](#matchmaking-api) pour la requête POST [#backfills](#backfills "mention") (requiert `public_ip`) et la réponse GET /tickets (`team_id` est optionnel), incluant des exemples.

**✨ Améliorations et nouvelles fonctionnalités :**

* Jusqu'à 3x plus de matchs potentiels sont désormais considérés, produisant des groupes plus optimaux et maximisant le taux de remplissage des matchs.
* Jusqu'à 200% plus rapide pour le matching grâce aux optimisations de concurrence.
* Jusqu'à 40% d'augmentation du taux de remplissage des matchs grâce à l'optimisation de l'algorithme d'expansions.
* Stabilité du service améliorée et vitesse accrue des redémarrages rapides.

{% hint style="info" %}
Les benchmarks ont été produits avec des données générées par chaos en utilisant [configuration d'exemple avancée](#configuration).
{% endhint %}

#### 2.1.0 (24 févr. 2025)

**⚠️ Changements incompatibles :**

* Séparation des informations de profil de jeu et d'étape d'expansion dans la [#injected-environment-variables](#injected-environment-variables "mention"):
  * `MM_MATCH_PROFILE` inclura désormais uniquement le nom du profil tel qu'il apparaît dans la configuration.
  * Introduction de `MM_EXPANSION_STAGE` qui contiendra l'étape d'expansion sous forme de chaîne (par ex. "initial", "15", "30").
* Les affectations de tickets incluent désormais l'ID de groupe lorsque [#endpoint-tickets](#endpoint-tickets "mention"). L'ID de groupe est également inclus en tant que [#injected-environment-variables](#injected-environment-variables "mention"), comme un mappage de l'ID de groupe vers une liste des IDs des joueurs du groupe.
* Les affectations de tickets incluent désormais l'ID d'équipe lorsque [#endpoint-tickets](#endpoint-tickets "mention"). L'ID d'équipe est également inclus dans chaque donnée de ticket [#injected-environment-variables](#injected-environment-variables "mention").
* [#endpoint-tickets](#endpoint-tickets "mention") renvoie désormais `409 Conflit` code HTTP au lieu de `204 Pas de contenu` pour indiquer que le ticket ne peut pas être supprimé car le déploiement démarre. Pour remplacer les partants, utilisez un [#backfill](#backfill "mention") émis par le serveur après une période d'attente pré-spécifiée.
* [#endpoint-backfills](#endpoint-backfills "mention") paramètre du corps de la requête `attributes.deployment_request_id` a été déplacé vers `attributes.assignment.request_id`.
* [#endpoint-backfills](#endpoint-backfills "mention") le corps de la requête exige désormais les détails complets de l'affectation dans le cadre de `attributes` paramètre en plus du `request_id`.

🩹 **Corrections de bugs :**

* Les valeurs résolues de la règle d'intersection sont désormais [#injected-environment-variables](#injected-environment-variables "mention") dans la variable d'environnement `MM_INTERSECTION` .
* La fonctionnalité de redémarrage rapide régénère désormais de manière fiable les points de terminaison API et la spécification openAPI lorsque la configuration est modifiée.
* Correction de plusieurs bugs lors du (re)démarrage du matchmaker provoquant un temps de démarrage prolongé ou bloquant le matchmaker.

**✨ Améliorations et nouvelles fonctionnalités :**

* Augmentation des limites de débit et de la scalabilité de tous les points de terminaison API, pour tous les niveaux de matchmaker.
* Lors de l'affectation d'un joueur à un [#backfill](#backfill "mention"), l'ID du ticket du nouveau joueur sera ajouté en tant que tag au [deployments](https://docs.edgegap.com/learn/orchestration/deployments "mention").
* Backfill.
* Ajout de la fonctionnalité d'authentification Swagger UI pour tester l'API directement dans l'interface web sans avoir besoin de Postman.
* Amélioration des exemples openAPI pour refléter plus fidèlement des requêtes et réponses réalistes. [#inspect-api](#inspect-api "mention") Ajout de nouveau
  * destiné au développement et aux fins de débogage.
  * Permet de lister tous les tickets joueurs actuels dans une liste paginée.

#### Permet de lister tous les matchs actuels dans une liste paginée.

* [#backfill](#backfill "mention")1.0.0 (9 déc. 2024)
  * : À la demande (populaire), nous réintroduisons le backfill avec affectation automatisée des tickets, ce qui vous permet de réutiliser les sièges serveur lorsque des joueurs quittent la session.
* [#join-as-group](#join-as-group "mention")Idéal pour remplir les sièges de joueurs vides après le début d'un match, ou pour remplacer des joueurs partis pendant un match.
  * : Nous ajoutons la possibilité de rejoindre en groupe à la capacité déjà disponible de remplir plusieurs équipes avec des joueurs.
* [#matchmaking-sdk](https://docs.edgegap.com/unity/developer-tools#matchmaking-sdk "mention") et [#edgegap-integration-kit-by-betide-studio](https://docs.edgegap.com/unreal-engine/developer-tools#edgegap-integration-kit-by-betide-studio "mention") Idéal pour rejoindre une file de matchmaking avec un groupe d'amis ou venant d'un lobby commun.
  * SDKs de matchmaking :
* Pour faciliter l'intégration, nous proposons désormais des kits de développement logiciel pour les moteurs de jeu les plus populaires. [#latencies-attributes](#latencies-attributes "mention") Correction d'un bug où le
* n'était pas appliqué correctement. [#matchmaking-process](#matchmaking-process "mention") Les tickets seront désormais automatiquement annulés après un
* s'ils n'ont pas été affectés à un déploiement. [#endpoint-tickets](#endpoint-tickets "mention") Vous pouvez désormais
* pour améliorer le flux de votre processus de matchmaking.
* Les déploiements effectués par le matchmaker sont désormais étiquetés avec les IDs de tickets.
* Corrigé [#injected-environment-variables](#injected-environment-variables "mention") Vous pouvez désormais modifier votre configuration pendant que le matchmaker fonctionne. Cela déclenche un rechargement rapide de votre configuration sans nécessiter un cycle complet d'arrêt/démarrage du matchmaker. Note : cette fonctionnalité n'est pas recommandée pour les environnements de production, car elle supprime tous les tickets en cours et rend temporairement l'API non réactive.
* Corrigé [#injected-environment-variables](#injected-environment-variables "mention") pour utiliser les bons types primitifs au lieu de tableaux.

#### Valeurs JSON, qui contenaient auparavant des caractères échappés.

* 0.2.3 (8 oct. 2024)

#### Correction d'un bug où certains en-têtes n'étaient pas acceptés par le matchmaker lorsque des requêtes étaient effectuées depuis une application WebGL (politiques CORS).

* 0.2.2 (3 oct. 2024)

#### Correction d'un problème de validation de certificat TLS/SSL empêchant le lancement du matchmaker.

* 0.2.1 (30 sept. 2024)

#### Correction d'un bug provoquant une erreur 500 sur le point de terminaison des balises.

* 0.2.0 (25 sept. 2024)
* L'authentification de base est désormais obligatoire pour tous les points de terminaison.
* Ajout de la possibilité de configurer le nombre de tentatives en cas d'échec d'affectation sur le serveur.
* Le matchmaking basé sur les équipes est désormais la valeur par défaut pour toutes les configurations de matchmaking.
* L'application et la version sont désormais des champs obligatoires dans tous les profils.
* Ajout d'un nouveau point de terminaison pour surveiller l'état du matchmaker.
* Mise à jour du format de la variable d'environnement des tickets dans le déploiement.
* Ajout d'une option de configuration pour permettre aux hôtes de communiquer avec le matchmaker.
* L'API de débogage n'est désormais disponible que lorsqu'elle est explicitement activée dans la configuration (elle est actuellement désactivée pour refonte). `La clé` game\_profile `dans la réponse GET ticket a été remplacée par la clé suivante :`.

[^1]: les clients de jeu rejoignent un Lobby pour récupérer l’ID du groupe de matchmaking et rejoindre le groupe

[^2]: nombre maximum d’utilisateurs simultanés sur une journée donnée

[^3]: utilisateurs simultanés pendant les périodes creuses

[^4]: [Fonction en tant que Service](https://www.ibm.com/think/topics/faas)

[^5]: voir d'autres exemples


# Navigateur de serveurs

**Bienvenue sur Edgegap Server Browser OPEN BETA.** Nous espérons que vous apprécierez l'opportunité de prévisualiser notre nouveau service et d'aider à façonner son avenir via des tables rondes sur notre Discord.

Server Browser est un service géré pour [#match-bound](https://docs.edgegap.com/orchestration/deployments#match-bound "mention") et [Persistant](https://docs.edgegap.com/learn/orchestration/persistance) serveurs :

* **aider les joueurs à rechercher et rejoindre des serveurs adaptés** en fonction de la capacité, de la latence ou des paramètres du jeu ;
* **préchauffer de nouveaux serveurs** pour desservir des audiences mondiales à grande échelle et éviter des files d'attente frustrantes ;
* **simplifier les opérations de serveur** y compris les mises à jour, redémarrages, persistance, maillage, et plus encore.

{% hint style="success" %}
Vous cherchez à apparier des joueurs selon des règles strictes, sans permettre le choix du serveur ? Envisagez [matchmaking](https://docs.edgegap.com/learn/matchmaking "mention").
{% endhint %}

<figure><img src="https://3008966946-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2FwKrq9tLaamRoM6vSLXZu%2Fimage.png?alt=media&#x26;token=83756c6f-d413-4ac1-988e-b90e7fa7a0a6" alt=""><figcaption></figcaption></figure>

## ✔️ Préparation

### Flux et Hiérarchie

<figure><img src="https://3008966946-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2Fnwlt2Ot2ahlyLvI7kdGx%2Fimage.png?alt=media&#x26;token=14b5a6c8-48c8-4f23-a50a-0783acab14e3" alt=""><figcaption><p>Server Browser : Flux et Hiérarchie</p></figcaption></figure>

Server Browser propose deux fonctionnalités principales :

**▶️ Commencer la navigation** avec les clients de jeu pour :

* Découvrir et trouver des instances de serveur adaptées, voir les emplacements et réserver la capacité disponible.
* Réserver des places dans un slot d'instance, récupérer les détails de connexion et se connecter aux serveurs.
* Authentifier les connexions des joueurs depuis les Déploiements en utilisant [Identité fédérée](#user-content-fn-1)[^1].
* Mettre à jour la capacité disponible et/ou les métadonnées des slots d'instance afin de modifier les critères de découverte.

**🚀 Mise à l'échelle automatisée** (optionnel) avec des Politiques de mise à l'échelle pour :

* Surveiller les instances de serveurs, les slots, la capacité - par région et/ou autres critères.
* Créer des Déploiements pour augmenter la capacité avec préchauffage ou mise à l'échelle à la demande.
* Automatiser les opérations avec des politiques spéciales pour des démos, mises à jour, tests, QA, tournois, et plus encore.

{% hint style="info" %}
Après la sortie, **votre navigateur de serveurs devra fonctionner 24h/24 et 7j/7** pour garantir que les joueurs du monde entier puissent rejoindre des serveurs.
{% endhint %}

## ▶️ Commencer la navigation

Informez-vous sur le cycle de vie serveur/joueur et leurs responsabilités pour assurer une utilisation efficace des serveurs.

### Authentifier

Server Browser génère automatiquement deux types de jetons :

* **Jeton Serveur** - requis pour [API Serveur](#server-lifecycle) méthodes, peut être [injecté en tant que variable de version d'application](https://docs.edgegap.com/orchestration/application-and-versions#injected-variables).
  * Accorde l'accès à toutes les méthodes de l'API, et est pratique pour les tests, le devops ou l'orchestration personnalisée.
* **Jeton Client** - requis pour [API de surveillance et API de réservation de sièges](#player-lifecycle) utilisé par les clients de jeu.
  * Nous recommandons de stocker ce jeton dans un coffre-fort de secrets tiers pour faciliter la rotation des jetons.

### Découvrir une Instance

**Nouveau** [deployments](https://docs.edgegap.com/learn/orchestration/deployments "mention") **doit créer une nouvelle Instance avec au moins un Slot lors de l'initialisation.**

{% hint style="info" %}
Voir [#configuration](#configuration "mention") pour en savoir plus sur les Politiques de mise à l'échelle et démarrer automatiquement des déploiements.
{% endhint %}

**Paramètres de métadonnées personnalisées optionnels** pour le filtrage, le tri et la navigation des joueurs.

Exemples :

* informations sur le slot - capacité d'équipe et métadonnées spécifiques à l'équipe (par ex. nom de l'équipe),
* nom et tags - étiquettes personnalisables, uniques, lisibles par l'humain et consultables ;
* détails de connexion - URL, IP, ports externes, ou autres paramètres ;
* données de compatibilité - version du serveur ou versions clientes prises en charge ;
* qualificateurs de latence - identifiants de ville et de région, et [ping-beacons](https://docs.edgegap.com/learn/orchestration/ping-beacons "mention") détails ;
* paramètres de jeu - niveau/scène/carte, mode de jeu, difficulté, mods utilisés ;
* tout autre paramètre personnalisé pour aider les joueurs à filtrer et trouver un serveur adapté.

{% hint style="info" %}
Les paramètres de métadonnées ci-dessus ne sont que des exemples, vous pouvez définir n'importe quels paramètres y compris ceux-ci. Tous les paramètres de métadonnées sont optionnels, et certaines instances peuvent ne pas avoir besoin de définir tous les paramètres.
{% endhint %}

Les métadonnées prennent en charge des clés de type chaîne et des valeurs contenant string, number, boolean, ou un tableau de chaînes.

{% hint style="success" %}
Pour sérialiser des objets imbriqués essayez d'encoder leur chemin d'accès en tant que `"object.child.property"`.
{% endhint %}

Les serveurs peuvent **mettre à jour les métadonnées d'instance ou de slot à tout moment** pour modifier leurs critères de découvrabilité.

**Les instances de serveur doivent périodiquement envoyer un battement de cœur (keep-alive)** pour vérifier leur disponibilité continue et empêcher les joueurs de rejoindre des serveurs plantés ou hors ligne. L'absence de battement de cœur pendant la période d'expiration configurée supprimera automatiquement l'instance et toutes les réservations de sièges en attente.

{% hint style="info" %}
Voir [persistance](https://docs.edgegap.com/learn/orchestration/persistance "mention") pour gérer l'état persistant du monde et [#active-caching](https://docs.edgegap.com/orchestration/application-and-versions#active-caching "mention") pour des déploiements plus rapides.
{% endhint %}

### Rechercher et Parcourir

Les joueurs peuvent lister les instances de serveur et [paginer les résultats](#pagination) pour trouver un serveur qu'ils souhaiteraient rejoindre. Pour afficher les données de ping (latence), lisez les [ping-beacons](https://docs.edgegap.com/learn/orchestration/ping-beacons "mention") détails de chaque instance et [mesurer la latence](https://docs.edgegap.com/orchestration/ping-beacons#measuring-round-trip-time).

Les instances et les slots peuvent être filtrés par sièges disponibles pour rejoindre ou [paramètres de métadonnées indexés](#configuration).

<table><thead><tr><th width="170">Paramètre</th><th width="135">Opérateurs</th><th>Filtre d'exemple (basé sur l'exemple simple)</th></tr></thead><tbody><tr><td><code>"joinable_seats"</code></td><td><p><a data-footnote-ref href="#user-content-fn-2"><code>eq</code></a>  ou <a data-footnote-ref href="#user-content-fn-4"><code>ne</code></a> ou </p><p><a data-footnote-ref href="#user-content-fn-6"><code>lt</code></a>  ou <a data-footnote-ref href="#user-content-fn-7"><code>le</code></a> ou </p><p><a data-footnote-ref href="#user-content-fn-8"><code>gt</code></a>  ou <a data-footnote-ref href="#user-content-fn-9"><code>ge</code></a></p></td><td><pre><code>?filter=<a data-footnote-ref href="#user-content-fn-3">joinable_seats gt 0</a>
&#x26;orderby=<a data-footnote-ref href="#user-content-fn-5">joinable_seats desc</a>
</code></pre></td></tr><tr><td><code>"string"</code><br>(métadonnées)</td><td><p><a data-footnote-ref href="#user-content-fn-2"><code>eq</code></a>  ou <a data-footnote-ref href="#user-content-fn-4"><code>ne</code></a> ou </p><p><a data-footnote-ref href="#user-content-fn-6"><code>lt</code></a>  ou <a data-footnote-ref href="#user-content-fn-7"><code>le</code></a> ou </p><p><a data-footnote-ref href="#user-content-fn-8"><code>gt</code></a>  ou <a data-footnote-ref href="#user-content-fn-9"><code>ge</code></a>  ou<br><code>contient</code></p></td><td><pre><code>?filter=metadata.custom_name contains 'my game'
et metadata.server_version le '1.1.0'
et metadata.server_version ge '1.0.0'
&#x26;orderby=metadata.custom_name asc
</code></pre></td></tr><tr><td><p><code>"int"</code> , ou <code>"float"</code></p><p>(métadonnées)</p></td><td><p><a data-footnote-ref href="#user-content-fn-2"><code>eq</code></a>  ou <a data-footnote-ref href="#user-content-fn-4"><code>ne</code></a> ou </p><p><a data-footnote-ref href="#user-content-fn-6"><code>lt</code></a>  ou <a data-footnote-ref href="#user-content-fn-7"><code>le</code></a> ou </p><p><a data-footnote-ref href="#user-content-fn-8"><code>gt</code></a>  ou <a data-footnote-ref href="#user-content-fn-9"><code>ge</code></a>  </p></td><td><pre><code>?filter=metadata.xp_multiplier gt 1.0
&#x26;orderby=metadata.xp_multiplier desc
</code></pre></td></tr><tr><td><code>"bool"</code><br>(métadonnées)</td><td><a data-footnote-ref href="#user-content-fn-2"><code>eq</code></a>  ou <a data-footnote-ref href="#user-content-fn-4"><code>ne</code></a></td><td><pre><code>?filter=metadata.allows_new_connections eq true
</code></pre></td></tr></tbody></table>

{% hint style="success" %}
Filtrez par régions et/ou villes pour affiner la sélection avant de mesurer la latence vers les serveurs.
{% endhint %}

{% hint style="info" %}
En savoir plus sur la pagination basée sur curseur [#pagination](#pagination "mention") pour permettre aux utilisateurs de récupérer plus de résultats.
{% endhint %}

### Réserver des Sièges

Avant de rejoindre un serveur, une réservation de siège est requise pour s'assurer que l'instance offre une capacité disponible suffisante. Les réservations peuvent inclure un groupe de joueurs ou un individu seul.

**Les réservations dépassant la capacité de sièges rejoignables du slot seront automatiquement rejetées** ([409 Conflit](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Status/409)). Les sièges rejoignables sont tous les sièges disponibles qui n'ont pas encore été réservés par d'autres joueurs.

Identité fédérée : Les joueurs doivent fournir un identifiant joueur tiers unique dans leur réservation. L'envoi du même ID une fois qu'ils [#connect-to-server](#connect-to-server "mention") permettra au serveur de vérifier leur identité.

Une fois une réservation effectuée avec succès ([200 OK](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Status/200)) les joueurs doivent tenter de se connecter immédiatement. Les réservations en attente **expireront après 30 secondes à moins qu'elles ne soient confirmées** par votre serveur.

{% hint style="info" %}
Le serveur peut modifier de force la capacité de n'importe quel slot, ajouter, supprimer ou mettre à jour n'importe quel slot. **Toutes les réservations pour un slot donné seront supprimées si des réservations en attente dépassent la nouvelle capacité disponible du slot.**
{% endhint %}

### Se connecter au Serveur

Une fois qu'un joueur a trouvé une instance adaptée, il peut **récupérer les détails de connexion requis depuis les métadonnées** (URL, IP, [Port Externe](https://docs.edgegap.com/orchestration/application-and-versions#port-mapping)). Dès que la réservation de siège est effectuée, **les joueurs peuvent procéder à la connexion au serveur de jeu de votre déploiement et transmettre leur identifiant joueur**.

{% tabs %}
{% tab title="Unreal Engine" %}
Pour **se connecter depuis PIE (éditeur)** pendant le développement et les tests, appuyez sur la touche tilde `~`  et tapez `open {URL}:{port}` et attendez que votre éditeur charge la carte.

{% hint style="success" %}
En cas d'échecs de connexion ou d'écran noir consultez notre [guide de dépannage](https://docs.edgegap.com/unreal-engine#troubleshooting-and-faq-1).
{% endhint %}
{% endtab %}

{% tab title="Unity" %}
Pour **connectez votre éditeur Unity** ou **client de jeu** à votre déploiement cloud, saisissez :

* **Déploiement** **URL** pointant vers l'IP du serveur, généralement dans `NetworkManager`  composant.
* **Port externe** mappant vers le [port d'écoute interne du serveur](https://docs.edgegap.com/learn/advanced-features/application-and-versions#port-mapping), généralement dans un composant Transport.

{% hint style="success" %}
En cas de timeout de connexion ou d'autres problèmes consultez notre [guide de dépannage](https://docs.edgegap.com/unity#troubleshooting-and-faq-4).
{% endhint %}
{% endtab %}
{% endtabs %}

Pour authentifier les nouvelles connexions, **votre serveur doit envoyer une requête de confirmation de réservation en lot** avec tous les IDs des nouveaux joueurs, recevant les informations dans la réponse de confirmation :

* attribution des réservations de joueurs acceptées à leur slot préféré,
* attribution des réservations de joueurs expirées à leur slot préféré,
* une liste d'IDs de joueurs inconnus.

Votre **serveur peut décider comment gérer chaque groupe de joueurs** et s'il faut autoriser ou expulser / bannir les utilisateurs expirés ou rejetés. Chacun des **slots de l'instance doit être mis à jour immédiatement avec le nouveau nombre de sièges disponibles** pour garantir que les nouvelles réservations ne dépassent pas la capacité.

### Abandonner le Serveur

Lorsque les joueurs partent, le serveur doit mettre à jour leur slot assigné pour refléter la nouvelle capacité de sièges disponibles.

{% hint style="success" %}
Si la conception de votre jeu permet une période de reconnexion, votre serveur peut attendre avant de libérer les sièges.
{% endhint %}

Nous recommandons d'arrêter les serveurs sans joueurs pour optimiser vos coûts d'hébergement. Attendre quelques minutes avant de le faire peut réduire le nombre de redémarrages durant de courtes périodes d'inactivité.

Lisez à propos de [#recovery-objectives](https://docs.edgegap.com/orchestration/persistance#recovery-objectives "mention") pour prévenir des rétrogradations persistantes de serveur frustrantes.

## ⚙️ Configuration <a href="#configuration" id="configuration"></a>

L'API Server Browser est générée à partir d'une configuration JSON spécifiée lorsque vous créez un nouveau Server Browser (ou un redémarrage rapide). Vous pouvez spécifier l'expiration des serveurs et des slots, ainsi que des métadonnées personnalisées :

<pre class="language-json" data-title="🍀 Exemple Simple v0.0.5" data-expandable="true"><code class="lang-json">{
	"version": "0.0.5",
	"server_instances": {
		"expiration_period": "30m",
		"<a data-footnote-ref href="#user-content-fn-10">indices</a>": {
			"third_party_id": "string",
			"level": "string",
			"mode": "string",
			"difficulty": "string",
			"seed": "string",
			"avg_player_rank": "int",
			"max_player_count": "int",
			"is_ranked": "bool",
			"app_version": "string",
			"DEPLOYMENT_LOCATION.city": "string",
			"DEPLOYMENT_TAGS": "string",
			"IN_PRIVATE_FLEET": "bool",
			"HOST_BASE_CLOCK_FREQUENCY": "int",
			"DEPLOYMENT_VCPU_UNITS": "int",
			"DEPLOYMENT_MEMORY_MB": "int",
			"PORT_GAMEPORT_EXTERNAL": "string",
			"BEACON_ENABLED": "bool",
			"BEACON_PUBLIC_IP": "string",
			"BEACON_PORT_UDP_EXTERNAL": "string",
			"BEACON_PORT_TCP_EXTERNAL": "string",
			"MM_MATCH_ID": "string",
			"MM_INTERSECTION": "string",
			"MM_EQUALITY": "string"
		}
	},
	"server_instance_slots": {
		"<a data-footnote-ref href="#user-content-fn-10">indices</a>": {
			"third_party_id": "string",
			"name": "string",
			"max_player_count": "int",
			"avg_player_rank": "int",
			"avg_player_latency": "int",
			"player_ids": "string"
		}
	},
	"seat_reservations": {
		"expiration_period": "5m"
	},
	"scaling_policies": {
		"monitoring_interval": "10s",
		"deployment_registration_period": "1m"
	}
}
</code></pre>

{% hint style="info" %}
Pour de meilleures performances, évitez de spécifier des indices pour des métadonnées non utilisées pour le filtrage ou le tri. Les paramètres non indexés peuvent toujours être définis et lus avec les méthodes API de détails d'instance ou de slot, voir [#api](#api "mention").
{% endhint %}

## ☁️ Cluster d'Hébergement

Server Browser est hébergé et géré 24h/24 par Edgegap.

Choisissez une option d'hébergement la mieux adaptée à votre objectif :

### Niveaux de Cluster Privé

Passez à un cluster privé en un clic pour bénéficier d'un hébergement hautement disponible maintenu par l'équipe Edgegap avec un support en direct 24/7 pour les jeux publiés publiquement.

Les exigences en ressources pour votre instance dépendront de facteurs :

* **nombre de joueurs** - plus de joueurs entraînent plus de requêtes API,
* **nombre de requêtes par joueur** - des reconnexions plus rapides augmentent la charge du service et consomment des ressources,
* **nombre de serveurs** - plus de serveurs entraînent plus de données stockées et plus de requêtes API,
* **logique de repli de nouvelle tentative côté client** - les réessais avec backoff aléatoire aident à étaler les pics de trafic,
* **durée moyenne des parties** - des sessions plus courtes nécessitent des interactions plus fréquentes avec le navigateur de serveurs.

## 📗 API

Les clients de jeu et les serveurs dédiés envoient des requêtes API tout au long de leur cycle de vie au Server Browser.

{% file src="<https://3008966946-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2F0auyzkkQfLfNRgzKbWMn%2Fedgegap-server-browser-005.yaml?alt=media&token=84669896-e7b9-4415-8d66-131badb3fff5>" %}

Importer la spécification API dans [Client Web Scalar API](https://client.scalar.com/workspace/default/request/default) ou [Swagger Editor](https://editor.swagger.io/) pour inspecter les détails.

### Pagination

**Server Browser propose une pagination par curseur pour récupérer les données filtrées de manière incrémentale dans un ordre spécifique.** Cette approche nécessite d'envoyer un curseur (point de départ) et une taille de page (nombre d'éléments de réponse) à chaque récupération de résultats supplémentaires, contrairement à la pagination traditionnelle limit-offset.

{% hint style="info" %}
Associée à notre système propriétaire d'indexation de base de données développé pour les métadonnées de serveurs de jeu, la pagination par curseur offre une expérience utilisateur rapide, cohérente et flexible pour filtrer des données hautement dynamiques.
{% endhint %}

Notre objectif est que les utilisateurs trouvent un serveur adapté dès la première page. Pour la meilleure expérience, nous recommandons d'afficher des résultats mis en cache pour les pages précédentes, et de ne rafraîchir les résultats que lorsque l'utilisateur clique sur Rechercher.

## 🔖 Journal des modifications

{% hint style="info" %}
**La dernière version du navigateur de serveurs est `0.0.4`** . Gardez un œil sur les mises à jour et les annonces.
{% endhint %}

#### 0.0.4 (05 Janv. 2026)

* Entrée en OPEN BETA, introduction de [filtrage et tri pour les instances de serveur et les slots](#search-and-browse)!

#### 0.0.3 (28 Nov. 2025)

* Sortie initiale du service Server Browser lancée en CLOSED BETA.
* Lister les serveurs, gérer la capacité et obtenir les détails de connexion.
* Prise en charge des sessions de matchmaking avec des Déploiements Cloud et toujours en ligne avec des Flottes Privées.

[^1]: identifiants joueurs tiers

[^2]: égal

[^3]: trouve des instances avec des sièges disponibles

[^4]: différent de

[^5]: afficher d'abord les instances les plus remplies

[^6]: inférieur à

[^7]: inférieur ou égal

[^8]: supérieur à

[^9]: supérieur ou égal

[^10]: les indices contiennent vos paramètres de métadonnées personnalisés utilisés pour le filtrage ou le tri


# Fonctionnalités avancées

Ici, vous apprendrez comment tirer davantage parti de votre compte Edgegap. Comprendre certains concepts de serveur en profondeur peut rendre votre processus de développement moins sujet aux erreurs humaines, plus rentable et vous aider à personnaliser selon vos besoins spécifiques.

{% hint style="success" %}
Avant de nous envoyer vos questions, veuillez utiliser la barre de recherche dans cette documentation et sur notre [Discord Communautaire](https://discord.gg/NgCnkHbsGp). Publier vos questions, suggestions, rapports de bogues ou participer autrement au support communautaire sera récompensé par des points d'expérience !
{% endhint %}


# Registre de conteneurs

Maintenant que vous savez comment utiliser notre plateforme, vous devez conteneuriser votre serveur de jeu. Vous aurez besoin d'un endroit pour stocker vos images de conteneur afin qu'elles soient accessibles lors du déploiement de vos serveurs de jeu.

C'est pourquoi nous avons créé le registre de conteneurs Edgegap. Il s'agit d'un dépôt de conteneurs géré de manière privée qui fonctionne de la même manière que les registres publics standard, mais avec l'avantage supplémentaire d'une sécurité renforcée, de scans de vulnérabilités et d'autres fonctionnalités ! Avec une haute disponibilité et une intégration au tableau de bord, vous passerez moins de temps à apprendre de nouveaux outils et vos serveurs seront toujours prêts.

### Obtention de vos identifiants

Pour pousser des images, vous devrez d'abord vous authentifier sur notre registre, et pour cela, vous avez besoin d'identifiants. Trouvez le `Registre de conteneurs` onglet dans le `Service` section pour demander vos identifiants dans la barre latérale. À partir de là, vous pouvez demander l'accès à notre registre.

<figure><img src="https://3008966946-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2Fgit-blob-323308a355e5937e7bcd4dfdbf75cd0d4517ac86%2Frequest-access.png?alt=media" alt=""><figcaption></figcaption></figure>

Dans la boîte en bas de l'écran, vous trouverez tout ce dont vous avez besoin pour vous connecter au registre et pousser vos images de conteneur.

<figure><img src="https://3008966946-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2Fgit-blob-ed6f68d538b2ea4944d14989c82351b09dc3914c%2Fregistry-project-info.png?alt=media" alt=""><figcaption></figcaption></figure>

| Champ             | Description                                                                                               |
| ----------------- | --------------------------------------------------------------------------------------------------------- |
| URL               | L'URL de notre registre de conteneurs. Vous devrez l'utiliser lors de la connexion et du push des images. |
| Projet            | Le nom de votre projet assigné. Vous devez l'inclure dans le chemin de votre dépôt d'images.              |
| Nom d'utilisateur | Le nom d'utilisateur à utiliser lors de la connexion au registre.                                         |
| Jeton             | Le mot de passe à utiliser lors de la connexion au registre.                                              |

Vous pouvez maintenant vous connecter au dépôt en utilisant l'outil de votre choix :

#### Linux

```bash
# entrez votre mot de passe lorsqu'on le demande
docker login -u '<REPOSITORY_USERNAME>' registry.edgegap.com
```

#### cmd

```bash
# entrez votre mot de passe lorsqu'on le demande
docker login -u <REPOSITORY_USERNAME> registry.edgegap.com
```

#### Powershell

```bash
# entrez votre mot de passe lorsqu'on le demande
docker login -u '<REPOSITORY_USERNAME>' registry.edgegap.com
```

### Avertissement de connexion Docker

```
ATTENTION ! Votre mot de passe sera stocké en clair dans /home/user/.docker/config.json.
```

Vous pouvez configurer le magasin d'identifiants en suivant [cette configuration](https://docs.docker.com/engine/reference/commandline/login/#credentials-store). N'oubliez pas que cet avertissement est le comportement normal de Docker.

Il est **important** que vous compreniez que votre nom d'utilisateur robot et le jeton pour votre dépôt privé sont encodés en base64 sur votre machine à ce chemin `$HOME/.docker/config.json`. Toute personne ayant accès à ce fichier peut facilement décrypter le jeton de votre compte robot avec un décodeur base64. Assurez-vous que l'environnement `docker login registry.edgegap.com` que vous utilisez est sûr et que les permissions d'accès à ce fichier sont restreintes.

Pour supprimer vos identifiants de ce fichier, vous pouvez facilement utiliser `docker logout registry.edgegap.com` à chaque fois que vous poussez et récupérez vos images privées.

### Pousser une image vers le registre

Si vous avez besoin d'aide pour conteneuriser votre projet, consultez [notre documentation sur ce sujet](https://docs.edgegap.com/docs/tools-and-integrations/container/docker) pour vous aider à démarrer.

D'abord, vous devez ajouter une étiquette à votre image correspondant au registre. Ensuite, puisque vous êtes connecté au registre, tout ce que vous avez à faire est de pousser votre image vers l'URL et le projet trouvés sur la page :

```bash
docker image tag <IMAGE_NAME>:<TAG> registry.edgegap.com/<PROJECT_NAME>/<IMAGE_NAME>:<TAG>
docker push registry.edgegap.com/<PROJECT_NAME>/<IMAGE_NAME>:<TAG>
```

Vous pouvez pousser autant d'images que votre stockage le permet et les séparer dans différents dépôts comme bon vous semble. Cependant, vous devriez lire la section "Modèles d'app" avant de pousser trop d'images !

Vous trouverez ensuite vos dépôts sur la même page après actualisation.

### Étiqueter plusieurs fois le même artefact de build (pousser un doublon d'image)

Si vous poussez par hasard deux fois le même artefact de build avec la même valeur de tag, aucun changement ne sera effectué.

Si vous poussez par hasard deux fois le même artefact de build avec deux valeurs de tag différentes, aucun espace de stockage supplémentaire ne sera consommé et notre registre créera simplement le nouveau tag pointant vers le même artefact de build.

### Gérer vos images

Vous pouvez voir vos dépôts en vous rendant sur la même page après avoir poussé au moins une image.

En cliquant sur l'un de ces dépôts, vous pouvez voir les images qu'il contient, regroupées par artefact. Si vous avez étiqueté la même image avec deux tags différents et les avez poussés vers le registre, vous les verrez comme le même artefact.

<figure><img src="https://3008966946-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2Fgit-blob-0a4a754f4b880aa351d7a77ff94cad5335a59831%2Fartifact-list.png?alt=media" alt=""><figcaption></figcaption></figure>

<figure><img src="https://3008966946-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2Fgit-blob-7afcf8e2f1ef701a0b2dc7aa8d54b56529f7c6eb%2Fartifact-list-2.png?alt=media" alt=""><figcaption></figcaption></figure>

Les images étiquetées `1.0.1` et `1.0.2` dans l'image ci-dessus ont le même artefact. L'image étiquetée `1.0.3`, cependant, a un artefact différent.

{% hint style="warning" %}
Si vous supprimez un artefact, vous supprimerez également ses tags associés. La boîte de dialogue de confirmation listera tous les tags que cette action supprimerait afin de s'assurer que vous ne supprimez pas accidentellement des ressources nécessaires.
{% endhint %}

### Supprimer des artefacts de build via l'API

Si l'interface du tableau de bord est trop lente pour vous, ou si vous avez besoin d'un pipeline d'intégration continue automatisé qui supprimerait automatiquement vos artefacts de build obsolètes pour maintenir votre utilisation du registre dans les limites, envisagez d'utiliser notre API du registre de conteneurs. Notre [API du registre de conteneurs](https://docs.edgegap.com/docs/api) permet de lister tous les tags pour une application donnée (image), ainsi que de supprimer des tags individuels. Puisque chaque artefact d'image (build) peut avoir plusieurs tags associés en même temps (tels que `v1.1.0`, `dev`, `latest`, ou plus), vous devrez supprimer tous les tags associés à un artefact spécifique afin de libérer de l'espace dans votre registre de conteneurs Edgegap.

### Demander plus de stockage

Lorsque votre demande d'accès au registre aura été approuvée, vous recevrez une certaine quantité d'espace de stockage dans le registre.

Vous pouvez demander de l'espace supplémentaire en cliquant sur le bouton "Demander plus de stockage" à côté de l'indicateur d'utilisation de l'espace.

<figure><img src="https://3008966946-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2Fgit-blob-81bdfd593994140a1a5a5f915b5e1242b32ef8fb%2Frequest-more-storage.png?alt=media" alt=""><figcaption></figcaption></figure>

Lorsqu'un membre du personnel aura approuvé votre demande, vous disposerez de plus d'espace pour pousser vos images.

### Étapes suivantes

Apprenez à conteneuriser votre application avec notre guide : [Prise en main de Docker](https://docs.edgegap.com/docs/tools-and-integrations/container/docker).


# Clusters gérés

En savoir plus sur les clusters gérés et commencer rapidement avec des solutions back-end personnalisées.

## ✔️ Introduction

Les clusters gérés facilitent et accélèrent l'hébergement de services de jeu autogérés et de backends de jeu. Vous préparez l'image du service et nous fournissons un environnement cloud résilient et à haute disponibilité pour les exécuter :

* authentification des joueurs,
* stockage de données - comptes, progression, inventaire, récompenses, ...
* services sociaux - chat, clans, tableaux de classement, tournois, ...
* matchmaking personnalisé - en utilisant [#advanced-matchmaker](#advanced-matchmaker "mention"), [#nakama-by-heroic-labs](#nakama-by-heroic-labs "mention"), ...
* calcul sans serveur - géré [fonctions en tant que service](https://github.com/openfaas/faas) (alt. cloudscript, lambda), ...

Les clusters privés garantissent que vos services disposent de **des ressources de calcul dédiées pour servir vos joueurs 24/7**.

{% hint style="info" %}
Nos machines de cluster utilisent des CPU AMD/Intel avec une fréquence de 2,4 - 3,2 GHz. Contactez-nous sur [Discord Communautaire](https://discord.gg/MmJf8fWjnt) pour coordonner les tests de charge et pour vous assurer que votre serveur dispose des ressources suffisantes disponibles.
{% endhint %}

## 🛠️ Outils pour développeurs

Si vous voyez une opportunité d'amélioration, veuillez nous en informer dans notre [Discord Communautaire](https://discord.gg/NgCnkHbsGp).

Nous espérons que vous apprécierez une expérience fluide. 🚀

### Docker

Pour aider à rendre votre serveur fiable, nous utilisons [Docker](https://www.docker.com/) - un logiciel de virtualisation garantissant que toutes les dépendances du code serveur jusqu'au niveau du système d'exploitation seront toujours exactement les mêmes, peu importe comment ou où le serveur est lancé.

### Kubernetes (K8s)

[Kubernetes](https://kubernetes.io/docs/concepts/overview/), également connu sous le nom de K8s, est un système open source pour automatiser le déploiement, la mise à l'échelle et la gestion des applications conteneurisées (images Docker). Il regroupe les conteneurs qui composent une application en unités logiques pour une gestion et une découverte faciles.

Les clusters gérés Edgegap fournissent une API Kubernetes à des fins d'administration.

### K8s Lens

Avec plus d'un million d'utilisateurs, [K8s Lens](https://k8slens.dev/) est l'EDI Kubernetes le plus populaire au monde. Connectez-vous aux clusters, explorez, obtenez des informations, apprenez et agissez si nécessaire. Lens fournit toutes les informations de vos charges de travail et ressources en temps réel, toujours dans le bon contexte.

L'API Kubernetes du cluster Edgegap peut être utilisée via Lens ou d'autres EDI Kubernetes.

### Gestionnaire de paquets Helm

[Helm](https://helm.sh/) est la meilleure façon de trouver, partager et utiliser des logiciels conçus pour Kubernetes. Helm vous aide à gérer les applications Kubernetes - les Helm Charts vous aident à définir, installer et mettre à niveau même les applications Kubernetes les plus complexes. Les charts sont faciles à créer, versionner, partager et publier - alors commencez à utiliser Helm et arrêtez le copier-coller.

[Installation de l'interface CLI Helm](https://helm.sh/docs/intro/install/) fournit aux développeurs une interface simple pour gérer leurs packages de cluster.

## 🚀 Démarrage

☑️ [Inscrit pour votre compte Edgegap gratuit](https://app.edgegap.com/auth/register) et passez au niveau paiement à l'utilisation pour débloquer les clusters.

☑️ Accédez à [Clusters gérés](https://app.edgegap.com/cluster-management/clusters/list) page.

☑️ Cliquez sur **Créer un cluster** d'abord, puis saisissez :

* **Étiquette** pour votre cluster afin de le retrouver facilement plus tard,
* **Taille du cluster -** voir [#introduction](#introduction "mention").

{% hint style="danger" %}
**Nous recommandons fortement de créer des clusters séparés pour vos environnements de développement et de production.**
{% endhint %}

☑️ Vérifiez le coût estimé et cliquez **Créer un cluster** pour démarrer votre nouveau cluster.

☑️ Une fois le cluster prêt, **cliquez sur Kubeconfig pour télécharger votre configuration et vos identifiants** pour vous connecter et administrer votre nouveau cluster.

☑️ [Déplacez votre fichier kubeconfig](https://kubernetes.io/docs/concepts/configuration/organize-cluster-access-kubeconfig/) pour `kubectl` pour le trouver.

☑️ Utilisateurs Lens : [importez votre fichier kubeconfig](https://docs.k8slens.dev/getting-started/add-cluster/#specify-kubeconfig-files).

☑️ Testez la connexion à votre cluster avec la commande `kubectl get nodes` :

```bash
kubectl get nodes
NOM                             STATUT   RÔLES    ÂGE    VERSION
lke334087-533013-294dcfe70000   Prêt     <aucun>   10m   v1.31.0
lke334087-533013-4e69edc10000   Prêt     <aucun>   10m   v1.31.0
lke334087-533013-50bf39880000   Prêt     <aucun>   10m   v1.31.0
```

🙌 Félicitations, vous avez terminé la configuration du cluster géré ! Vous pouvez maintenant installer vos services.

## 📦 Nakama par Heroic Labs

{% hint style="info" %}
Intégrez Edgegap avec [plugin Nakama](https://github.com/edgegap/nakama-edgegap) + [plugin Unity](https://github.com/edgegap/edgegap-server-nakama-plugin-unity)! [Contactez-nous pour d'autres plateformes/fonctionnalités.](https://discord.gg/NgCnkHbsGp)
{% endhint %}

Suivez ces étapes pour héberger votre propre [Backend de jeu Nakama](https://heroiclabs.com/docs/nakama/getting-started/) sur des clusters gérés :

☑️ Créez un **enregistrement DNS de type A** chez votre fournisseur DNS (par ex. [Cloudflare](https://developers.cloudflare.com/dns/get-started/)), notez l'URL pour plus tard. Votre **IP externe pour l'enregistrement DNS** peut être trouvée dans Lens sous Services / `ingress-nginx-controller` .

☑️ Vérifiez que votre DNS est correctement configuré en effectuant une recherche [à l'aide de DNSchecker](https://dnschecker.org/ns-lookup.php).

☑️ Créez un fichier nommé `values.yaml` avec le contenu suivant (utilisez vos propres valeurs) :

<pre class="language-yaml"><code class="lang-yaml">isProductionEnvironment: true

# Le nom d'hôte externe pour le serveur Nakama - enregistrement DNS de l'étape précédente
externalHostName: <a data-footnote-ref href="#user-content-fn-1">&#x3C;DNS_A_RECORD_URL></a>

nakama:
  # La version de Nakama à déployer.
  # Voir https://hub.docker.com/r/heroiclabs/nakama/tags pour les versions disponibles.
  version: 3.26.0
  # Nom d'utilisateur et mot de passe pour la console Nakama
  username: <a data-footnote-ref href="#user-content-fn-2">&#x3C;USERNAME></a>
  password: <a data-footnote-ref href="#user-content-fn-3">&#x3C;PASSWORD></a>
</code></pre>

{% hint style="danger" %}
**Remplacez \<VALUES> ci-dessus par vos propres valeurs** dans le fichier ci-dessus.
{% endhint %}

☑️ Déployer le chart helm Nakama :

```bash
helm upgrade --install \
  --namespace nakama --create-namespace -f <FILE_PATH>/values.yaml \
  --version 1.0.0 <RELEASE_NAME> oci://registry-1.docker.io/edgegap/heroiclabs-nakama
```

☑️ Lens : vérifiez l'installation dans la section Workloads / Deployments, `nakama` devrait être en cours d'exécution.

✅ **Connectez-vous à votre console Nakama** avec l'URL et les identifiants du `values.yaml` fichier.

🙌 Félicitations, vous avez terminé la configuration du backend de jeu Nakama auto-hébergé !

### Mises à jour du service

Suivez ces étapes pour mettre à jour votre service hébergé dans le cluster géré :

☑️ Mettez à jour votre `value.yaml` fichier avec les nouveaux fichiers.

☑️ Mettez à jour votre chart helm en utilisant cette commande :

```bash
helm upgrade --reuse-values \
  --namespace nakama -f <FILE_PATH>/values.yaml \
  --version 1.0.0 <RELEASE_NAME> oci://registry-1.docker.io/edgegap/heroiclabs-nakama
```

☑️ Rechargez vos modifications en fermant les pods mis à jour, ce qui provoquera l'utilisation du nouveau chart helm après que nous redémarrions automatiquement les pods.

🙌 Félicitations, vous avez terminé la mise à jour du cluster Nakama !

## 👷 Matchmaker avancé

Suivez ces étapes pour héberger votre [OpenMatch](https://open-match.dev/site/) sur un cluster géré.

☑️ Créez un enregistrement DNS de type A chez votre fournisseur DNS (par ex. [Cloudflare](https://developers.cloudflare.com/dns/get-started/)), notez l'URL pour plus tard. Votre **IP externe pour l'enregistrement DNS** peut être trouvée dans Lens sous Services / `ingress-nginx-controller` .

☑️ Vérifiez que votre DNS est correctement configuré en effectuant une recherche [à l'aide de DNSchecker](https://dnschecker.org/ns-lookup.php).

☑️ Créez un fichier nommé `values.yaml` avec le contenu suivant (utilisez vos propres valeurs) :

```yaml
isProductionEnvironment: false

director:
  credential:
    registry: <VOTRE_REGISTRY_DIRECTOR>
    username: <VOTRE_USERNAME_REGISTRY_DIRECTOR>
    password: <VOTRE_MOT_DE_PASSE_REGISTRY_DIRECTOR>
  image: <IMAGE_DIRECTOR>
  env: {
    "KEY": "VALUE"
  }

mmf:
  credential:
    registry: <REGISTRY_MATCHMAKER_FUNCTION>
    username: <USERNAME_REGISTRY_MATCHMAKER_FUNCTION>
    password: <MOT_DE_PASSE_REGISTRY_MATCHMAKER_FUNCTION>
  image: <IMAGE_MATCHMAKER_FUNCTION>
  env: {
    "KEY": "VALUE"
  }

frontend:
  credential:
    registry: <REGISTRY_FRONTEND>
    username: <USERNAME_REGISTRY_FRONTEND>
    password: <MOT_DE_PASSE_REGISTRY_FRONTEND>
  externalHostName: <VOTRE_NOM_D_HOTE_CLOUDFLARE> # par ex. exemple.test.com
  image: <IMAGE_FRONTEND>
  env: {
    "KEY": "VALUE"
  }

# Configurations globales visibles par tous les sous-charts
global:
  kubernetes:
    resources:
      requests:
        memory: 100Mi
        cpu: 100m
      limits:
        memory: 100Mi
        cpu: 100m
```

{% hint style="danger" %}
**Remplacez \<VALUES> ci-dessus par vos propres valeurs** dans le fichier ci-dessus.
{% endhint %}

☑️ Ajoutez **le dépôt Edgegap** à votre liste de dépôts :

```bash
helm repo add edgegap-public https://registry.edgegap.com/chartrepo/edgegap-public
```

☑️ Déployer le chart helm du matchmaker avancé :

```bash
helm upgrade --install \
  --namespace matchmaker --create-namespace -f <FILE_PATH>/values.yaml \
  --version 1.0.1 <RELEASE_NAME> edgegap-public/open-match-edgegap
```

🙌 Félicitations, vous avez terminé la configuration du Matchmaker avancé !

### Mises à jour du service

Suivez ces étapes pour mettre à jour votre service hébergé dans le cluster géré :

☑️ Mettez à jour votre `value.yaml` fichier avec les nouveaux fichiers.

☑️ Mettez à jour votre chart helm en utilisant cette commande :

```bash
helm upgrade --reuse-values \
  --namespace matchmaker -f <FILE_PATH>/values.yaml \
  --version 1.0.1 <RELEASE_NAME> edgegap-public/open-match-edgegap
```

☑️ Rechargez vos modifications en fermant les pods mis à jour (director, mmf, frontend), ce qui provoquera l'utilisation du nouveau chart helm après que nous redémarrions automatiquement les pods.

🙌 Félicitations, vous avez terminé la mise à jour du Matchmaker avancé !

### Déploiement continu

Automatisez la mise à jour de vos services en ajoutant ce script shell à votre pipeline de déploiement :

```bash
#!/bin/bash

RELEASE_NAME="<RELEASE_NAME>"
NAMESPACE="matchmaker"  # Changez ceci si vous avez modifié le namespace.

helm upgrade --reuse-values -f <FILE_PATH>/value.yaml --namespace $NAMESPACE --version 1.0.1 $RELEASE_NAME edgegap-public/open-match-edgegap

echo "Installation de redis-tools"
apt-get update
apt-get install -y redis-tools

DIRECTOR_DEPLOYMENT_NAME="$RELEASE_NAME-director"
MMF_DEPLOYMENT_NAME="$RELEASE_NAME-mmf"
CUSTOM_FRONTEND_DEPLOYMENT_NAME="$RELEASE_NAME-custom-frontend"
REDIS_HOST="$RELEASE_NAME-redis-master"

declare -A replicas

# Pour chaque déploiement (director, mmf, custom-frontend) arrêtez les pods
for deployment in $DIRECTOR_DEPLOYMENT_NAME $MMF_DEPLOYMENT_NAME $CUSTOM_FRONTEND_DEPLOYMENT_NAME
do
  echo "Arrêt des pods pour le déploiement : $deployment"
  replicas[$deployment]=$(kubectl get deployment $deployment -o=jsonpath='{.spec.replicas}' --namespace $NAMESPACE)
  kubectl scale deployment/$deployment --replicas=0 --namespace $NAMESPACE
done

# Attendre que les pods soient terminés
for deployment in $DIRECTOR_DEPLOYMENT_NAME $MMF_DEPLOYMENT_NAME $CUSTOM_FRONTEND_DEPLOYMENT_NAME
do

  echo "Attente de la terminaison des pods pour le déploiement : $deployment"
  kubectl wait --for=delete pod -l app=$deployment --timeout=60s --namespace $NAMESPACE

  # Vérifier si la commande wait a réussi. Sinon, quitter le script
  if [ $? -ne 0 ]; then
    echo "Échec de l'attente de la terminaison des pods pour le déploiement : $deployment"
    exit 1
  fi
done

# Nettoyer la base de données redis
echo "Nettoyage de la base de données redis"
redis-cli -h $REDIS_HOST flushall

# Pour chaque déploiement (director, mmf, custom-frontend) restaurez l'échelle des pods à leur nombre d'origine
for deployment in $DIRECTOR_DEPLOYMENT_NAME $MMF_DEPLOYMENT_NAME $CUSTOM_FRONTEND_DEPLOYMENT_NAME
do
  echo "Redimensionnement des pods à ${replicas[$deployment]} pour le déploiement : $deployment"
  kubectl scale deployment/$deployment --replicas=${replicas[$deployment]} --namespace $NAMESPACE
done
```

### Validation du certificat Letsencrypt (C#)

Pour certains clients, la validation de certificat Letsencrypt recommandée peut échouer avec l'erreur :

```bash
Erreur Curl 60 : Échec de la vérification du certificat. Le certificat a expiré. Code d'erreur UnityTls : 7
```

{% hint style="success" %}
La mise à jour de votre système d'exploitation peut résoudre les problèmes liés à une autorité de certification racine obsolète.
{% endhint %}

En dernier recours, les clients de jeu peuvent implémenter une fonction personnalisée de gestion des certificats :

````csharp
```csharp
public class CustomCertificateHandler : CertificateHandler
{
  private readonly string EXPECTED_CERT = "-----BEGIN CERTIFICATE-----<key>-----END CERTIFICATE-----\r\n";
  protected override bool ValidateCertificate(byte[] certificateData)
  {
    X509Certificate2 certificate = new X509Certificate2(certificateData);
    X509Certificate2 expectedCert = new X509Certificate2(Encoding.ASCII.GetBytes(EXPECTED_CERT));

    using (SHA256 sha256 = SHA256.Create())
    {
      Debug.Log("certificate.Thumbprint: " + certificate.Thumbprint);
      Debug.Log("expectedCert.Thumbprint: " + expectedCert.Thumbprint);

      return certificate.Thumbprint == expectedCert.Thumbprint;
    }
  }
}
```
````

Utilisation :

```csharp
UnityWebRequest request = UnityWebRequest.Get(...);
request.certificateHandler = new BypassCertificateHandler();
request.SendWebRequest();
request.certificateHandler.Dispose();
```

Nous recommandons de stocker la `EXPECTED_CERT` valeur dans votre propre stockage de fichiers, et de la récupérer à l'exécution, afin de pouvoir la mettre à jour sans publier une mise à jour du client de jeu.

## 🟢 Opérations et observabilité

### Changements de niveau de cluster

Préparez-vous au succès et optimisez après le lancement, afin de ne pas bloquer vos joueurs le jour de la sortie.

{% hint style="warning" %}
&#x20;Changer la taille du cluster nécessite d'arrêter votre cluster. Voir [déploiement blue/green](https://circleci.com/blog/canary-vs-blue-green-downtime/) pour des mises à jour sans interruption.
{% endhint %}

### Support et mises à jour futures

**Votre succès est notre priorité.** Si vous souhaitez envoyer des demandes personnalisées, demander des fonctionnalités critiques manquantes, ou exprimer toute remarque, [veuillez nous contacter dans notre Discord Communautaire](https://discord.gg/MmJf8fWjnt).

[^1]: enregistrement DNS de l'étape précédente

[^2]: choisissez votre propre nom d'utilisateur admin

[^3]: choisissez un mot de passe sécurisé pour l'administrateur


# Relais (P2P)

{% hint style="warning" %}
Cette section de la documentation est en cours d'élaboration et est susceptible d'être modifiée.

N'hésitez pas à poser des questions ou à faire des demandes via notre [Discord](https://discord.com/invite/NgCnkHbsGp) canal. Nous sommes là pour vous aider !
{% endhint %}

Les relais distribués Edgegap bénéficient de notre réseau cloud distribué, qui comprend des centaines d'emplacements. Cela garantit que vos joueurs jouent toujours sur le meilleur relais disponible, grâce à notre technologie brevetée de décision en temps réel basée sur la télémétrie.

La mise en place de relais peut effectivement être une tâche complexe, c'est pourquoi nous avons développé une solution qui prend en charge les aspects techniques afin que vous n'ayez pas à le faire. Notre solution simplifie le processus de configuration et de gestion des relais, vous permettant de vous concentrer sur leur intégration transparente dans votre jeu ou application sans nécessiter une expertise technique approfondie.

***

### Pourquoi ai-je besoin d'un relais dans un jeu P2P

Un serveur Relay peut être un outil précieux pour les développeurs de jeux P2P. Dans les jeux P2P, les joueurs se connectent directement les uns aux autres sans avoir besoin d'un serveur central. Cependant, cette approche peut présenter certaines difficultés, telles que :

#### **Restrictions de pare-feu**

Les pare-feu peuvent bloquer les connexions P2P entre appareils, rendant difficile la connexion des joueurs entre eux.

#### **NAT strict**

Un NAT strict peut avoir un impact important sur la capacité d'un joueur à participer à des jeux peer-to-peer (P2P). Les jeux P2P reposent sur des connexions directes entre les appareils des joueurs pour faciliter la communication et le jeu, mais un NAT strict peut limiter voire bloquer ces connexions. Cela peut entraîner une latence accrue, des déconnexions et des difficultés à rejoindre ou héberger des parties.

<figure><img src="https://3008966946-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2Fgit-blob-1ff4b2b8740e5c4f621e070e7524b20cb26a52b4%2FTraditional_P2P.png?alt=media" alt=""><figcaption></figcaption></figure>

Un serveur Relay peut aider à surmonter ces défis en agissant comme intermédiaire entre les joueurs. Lorsqu'un joueur souhaite se connecter à un autre joueur, sa connexion est d'abord acheminée via le serveur Relay. Cela permet au serveur Relay de gérer le traversal NAT et les restrictions de pare-feu, facilitant ainsi la connexion entre joueurs.

Les serveurs Relay peuvent également contribuer à améliorer les performances globales des jeux P2P en réduisant la charge sur les appareils des joueurs. En gérant une partie du trafic réseau entre les joueurs, le serveur Relay peut aider à réduire la latence et à améliorer l'expérience de jeu globale.

En résumé, un serveur Relay peut être un outil précieux pour les développeurs de jeux P2P, aidant à surmonter le traversal NAT et les restrictions de pare-feu, et améliorant les performances globales du jeu.

***

### Serveur vs Client en P2P

Dans une configuration peer-to-peer (P2P) pour un jeu multijoueur, un joueur doit agir comme serveur de jeu puisqu'il n'existe pas de serveur dédié pour gérer le jeu pour tous les joueurs. Ce joueur, appelé le « serveur », est responsable de la gestion du monde du jeu et de la synchronisation de toutes les informations entre les joueurs. Les joueurs restants (Client" alt="">

se connecteront directement au serveur.

***

### Commencer

#### **Implémenter une sorte de lobby/matchmaker**

Vous devrez mettre en place une forme de lobby ou de matchmaker pour créer des sessions relay pour vos joueurs. Ne vous inquiétez pas, au départ vous n'aurez pas besoin d'un matchmaker entièrement fonctionnel, mais plutôt de quelque chose capable d'automatiser vos requêtes API sans exposer votre jeton dans le client de jeu. Envisagez d'utiliser [#nakama-by-heroic-labs](https://docs.edgegap.com/advanced-features/managed-clusters#nakama-by-heroic-labs "mention") sur les clusters Edgegap.

#### **Intégration avec l'API Edgegap**

Une fois que vous aurez terminé l'étape précédente, vous devrez principalement effectuer deux actions simples à l'aide de l'API Edgegap : créer des sessions relay et supprimer des sessions relay. Votre lobby/matchmaker devrait être responsable de la mise en œuvre de ces actions, qui autoriseront ou non vos joueurs à accéder à un relais. [Plus d'informations dans cette section](https://docs.edgegap.com/learn/distributed-relay/relay-edgegap-api).

#### **Intégration avec la couche de transport existante**

Après avoir autorisé vos joueurs sur un relais, vous devrez toujours mettre en œuvre la communication entre votre client de jeu et le relais, ce qui est connu sous le nom de couche de transport.

Pour vous faciliter la vie, nous travaillons à réaliser de nombreuses implémentations pour différents netcodes, langages et frameworks. Si vous souhaitez intégrer l'une de nos implémentations actuelles, suivez simplement le tutoriel correspondant à votre stack.

* [Unity avec Mirror Netcode](https://docs.edgegap.com/docs/sample-projects/unity-netcodes/mirror-on-edgegap)
* Réseautage Unreal - Bientôt disponible
* [Unity Netcode pour GameObjects](https://docs.edgegap.com/docs/sample-projects/unity-netcodes/unity-netcode-on-edgegap)
* [Réseautage Fishnet](https://docs.edgegap.com/docs/sample-projects/unity-netcodes/fishnet-on-edgegap)

#### **(Ou) Implémenter votre propre couche de transport**

Si vous êtes intéressé par l'implémentation de votre propre couche de transport pour un netcode spécifique, vous pouvez trouver des informations détaillées et des conseils en suivant ce guide :

[Manuel d'implémentation des Relais](https://github.com/edgegap/distributed-relay-examples#relay-implementation-manual)

Si vous avez des questions sur l'implémentation ou souhaitez connaître la feuille de route de nos intégrations actuelles, n'hésitez pas à nous contacter !


# Intégration de jeu

### Pourquoi ai-je besoin d'un entremetteur (Matchmaker) et/ou d'un Lobby ?

Un service de lobby ([#nakama-by-heroic-labs](https://docs.edgegap.com/advanced-features/managed-clusters#nakama-by-heroic-labs "mention")) joue un rôle crucial dans les jeux multijoueur en ligne pour diverses raisons techniques.

**Gestion des joueurs**

Un système de lobby ou d'entremetteur aide à gérer les joueurs en les regroupant dans des parties appropriées en fonction de différents critères tels que le niveau de compétence, la localisation géographique ou les préférences de jeu. Cela garantit une expérience de jeu équilibrée et agréable pour tous les joueurs impliqués.

**Backend**

Vous ne voulez pas que votre joueur communique directement avec votre backend et vous souhaitez offrir un point centralisé auquel il puisse accéder. Imaginez que vous avez un jeton API qui démarre une VM chez un certain fournisseur : vous ne voulez pas que le jeton soit intégré en dur dans le client du jeu, accessible à tous les joueurs !

**Sécurité**

L'utilisation d'un système centralisé de lobby ou d'entremetteur aide à maintenir le contrôle sur la sécurité du jeu. En filtrant et en validant les connexions des joueurs, un entremetteur peut empêcher les accès non autorisés, protéger les données des utilisateurs et atténuer les tentatives de triche ou de piratage.

**Gestion des sessions de jeu**

Un système de lobby ou d'entremetteur gère les sessions de jeu en les créant, en les mettant à jour et en les terminant selon les besoins. Cela garantit que les joueurs peuvent rejoindre ou quitter les parties sans heurts et que les instances de jeu peuvent être efficacement gérées par le système.

<figure><img src="https://3008966946-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2Fgit-blob-b5db2255168c7ceca08fdbeca00c51f7e967a045%2FLobby.png?alt=media" alt=""><figcaption></figcaption></figure>

### Vous n'en avez pas besoin tout de suite ! (Mode développement)

Pendant la phase de développement, vous n'avez peut-être pas besoin d'un système complet de lobby ou d'entremetteur pour plusieurs raisons techniques :

**Environnement de test simplifié**

Aux premières étapes du développement, vous pouvez vous concentrer sur la mise en œuvre et le test des mécaniques de jeu principales et des fonctionnalités réseau. En évitant la complexité d'un système de lobby ou d'entremetteur, vous pouvez tester et déboguer votre jeu plus facilement avec un groupe plus restreint de joueurs, souvent au sein de votre équipe de développement.

**Itération plus rapide**

Sans lobby ni entremetteur, vous pouvez apporter rapidement des modifications à votre code de jeu et tester de nouvelles fonctionnalités ou corrections sans vous soucier de l'impact sur le processus de matchmaking. Cela permet une approche de développement plus agile, permettant à votre équipe d'itérer et d'affiner plus rapidement les mécaniques de jeu.

**Allocation des ressources**

Développer un système de lobby ou d'entremetteur à grande échelle nécessite beaucoup de temps et de ressources. En retardant la mise en œuvre de ces composants, vous pouvez allouer vos ressources plus efficacement, en vous concentrant d'abord sur le gameplay et les fonctionnalités réseau de base.

**Préoccupations de scalabilité**

Aux premiers stades du développement, vous n'aurez probablement pas un grand nombre de joueurs à gérer. Par conséquent, un système basique de connexion des joueurs ou même des connexions manuelles pour les tests peut être suffisant. Cependant, à mesure que votre jeu grandit et attire plus de joueurs, un système de lobby ou d'entremetteur deviendra de plus en plus nécessaire pour gérer les connexions et assurer une expérience de jeu fluide.

Il est crucial de concevoir l'architecture de votre jeu pour pouvoir accueillir un système de lobby ou d'entremetteur à l'avenir. Cette approche prospective facilitera l'intégration de ces composants lorsque vous serez prêt à tester votre jeu avec un plus grand nombre de joueurs, garantissant une transition plus douce et un produit final plus abouti.

### Interagir avec l'API d'Edgegap

Edgegap propose une API simple pour interagir avec les sessions de relais afin d'autoriser vos joueurs à se connecter au relais le plus proche pour une faible latence.

<figure><img src="https://3008966946-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2Fgit-blob-d9e302f8f6c3d299760dd8ad5416a5d47965cb1b%2FDistributed_Relay_P2P.png?alt=media" alt=""><figcaption></figcaption></figure>

Pour interagir avec l'API, vous devrez fournir un `jeton d'en-tête d'autorisation` dans vos requêtes.

{% hint style="info" %}
Vous pouvez obtenir un jeton en vous inscrivant pour un compte et en générant un profil de relais. [**Inscrivez-vous ici**](https://app.edgegap.com/auth/register)

Veuillez noter que vous avez besoin d'un jeton exclusivement destiné aux relais. Si vous disposez déjà d'un jeton API standard, il ne fonctionnera pas.
{% endhint %}

Ceci est accessible depuis la barre latérale du tableau de bord.

<figure><img src="https://3008966946-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsR0dHSFv9ymoC0DO5G8J%2Fuploads%2Fgit-blob-52bbb7251013ce023d5ceb59e7a078c1755312cb%2Fcreatetoken.png?alt=media" alt=""><figcaption></figcaption></figure>

Une fois que vous avez le jeton, incluez-le dans les en-têtes de requête pour tous les appels API. N'oubliez pas de préfixer votre clé API par `jeton`.

{% hint style="success" %}
Si vous n'êtes pas familier avec le travail avec une API, vous pouvez vous référer à [cette section](#interacting-with-api-curl-or-postman) pour vous aider à démarrer.
{% endhint %}

### Créer une session de relais

Pour utiliser le relais distribué, vous devez créer une session de relais. Cela se fait en envoyant une `requête POST` au `/v1/relays/sessions` endpoint avec une charge utile JSON. Les sessions peuvent être créées manuellement, avec un entremetteur, avec un lobby ou avec votre propre service personnalisé.

Cela sélectionnera dynamiquement le meilleur relais disponible pour vos joueurs en temps réel et créera une autorisation pour accéder au relais. Cependant, nous recommandons de pré-filtrer votre matchmaking pour regrouper les joueurs dans la même région afin d'éviter des distances extrêmes entre eux.

{% hint style="info" %}
Cette étape ne connectera pas directement vos joueurs au relais ; vous devrez prendre en charge cela à une étape ultérieure du processus. Cette étape vous fournit uniquement un relais avec lequel établir une connexion.
{% endhint %}

Exemple de requête :

```bash
POST - /v1/relays/sessions
```

La charge utile doit contenir un tableau d'objets utilisateur, où chaque objet contient l'adresse IP d'un utilisateur. Vous pouvez également inclure un `webhook_url`, qui est l'URL qui recevra les notifications liées à la session.

Exemple de payload :

```json
{
  "users": [
    {
      "ip": "1.1.1.1"
    },
    {
      "ip": "2.2.2.2"
    }
  ],
  "webhook_url": "https://webhook.example.com/notify"
}
```

{% hint style="info" %}
Où `"users"` est un tableau d'objets utilisateur contenant la `"ip"` de chaque utilisateur dans la session, et `"webhook_url"` est une URL optionnelle pour recevoir des mises à jour de la session.

Après avoir envoyé la `requête POST` requête, vous recevrez une réponse JSON contenant le `session_id`, qui est nécessaire pour récupérer les informations de la session ultérieurement.
{% endhint %}

Exemple de réponse :

```json
{
  "session_id": "3960c873aafd-S",
  "authorization_token": null,
  "status": "Initializing",
  "ready": false,
  "linked": false,
  "error": null,
  "session_users": [],
  "relay": null,
  "webhook_url": "https://webhook.example.com/notify"
}
```

### Obtenir des informations sur la session de relais

Pour récupérer les informations de session, envoyez une `requête GET` au `/v1/relays/sessions/{session_id}` à l'endpoint avec le `session_id` obtenu depuis la `requête POST` requête.

Exemple de requête :

```bash
GET - /v1/relays/sessions/3960c873aafd-S
```

La réponse contiendra des informations sur la session, y compris le statut de la session, les informations des utilisateurs et les informations du relais.

La réponse attendue contiendra des informations de session comme ceci :

```json
{
  "session_id": "3960c873aafd-S",
  "authorization_token": 1031196689,
  "status": "Linked",
  "ready": true,
  "linked": true,
  "error": null,
  "session_users": [
    {
      "ip_address": "2.2.2.2",
      "latitude": 48.8602294921875,
      "longitude": 2.34106993675232,
      "authorization_token": 3499933322
    },
    {
      "ip_address": "1.1.1.1",
      "latitude": -37.7036018371582,
      "longitude": 145.180633544922,
      "authorization_token": 4261594560
    }
  ],
  "relay": {
    "ip": "178.79.131.238",
    "host": "cc84b011777b.pr.edgegap.net",
    "ports": {
      "server": {
        "port": 31527,
        "protocol": "UDP",
        "link": "cc84b011777b.pr.edgegap.net:31527"
      },
      "client": {
        "port": 32089,
        "protocol": "UDP",
        "link": "cc84b011777b.pr.edgegap.net:32089"
      }
    }
  },
  "webhook_url": "https://webhook.example.com/notify"
}
```

L'obtention de l'autorisation pour le relais le plus proche peut prendre un peu de temps, donc lorsque le champ `ready` est `true` vous pouvez extraire les données JSON pour les utiliser.

[Plus de détails ici](https://docs.edgegap.com/docs/api)

{% hint style="success" %}
Alternativement, vous pouvez utiliser le paramètre \`webhook\_url\` lors de la création d'une session de relais pour être notifié lorsque la session a été soit attribuée à un relais avec succès, soit a échoué.
{% endhint %}

### Terminer une session de relais

Lorsque vous décidez de mettre fin à votre connexion au relais, vous pouvez facilement terminer une session de relais. Vous devez envoyer une `requête DELETE` au endpoint suivant :

```bash
DELETE - /v1/relays/sessions/{session_id}
```

{% hint style="info" %}
Remplacez `{session_id}` par l'identifiant de session réel que vous souhaitez terminer.
{% endhint %}

Une réponse avec le statut 204 no content signifie que la session a été supprimée avec succès. Les joueurs perdront l'accès au relais et vous ne serez plus facturé pour cette session.

{% hint style="warning" %}
Il est important de terminer correctement les sessions afin d'éviter de laisser des ressources inutilisées allouées, ce qui peut affecter les performances et entraîner des coûts inutiles.
{% endhint %}

***

### Exemple en C\#

Ceci est un exemple en C# que votre Lobby ou Matchmaker pourrait exécuter pour créer une session de relais et extraire les données que vous devrez renvoyer à votre client de jeu.

{% hint style="info" %}
Cet exemple utilise C# version > 7.0
{% endhint %}

```csharp
using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Net.Http.Json;
using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;

namespace LobbyNamespace
{
    public class EdgegapAPI
    {
        private readonly HttpClient _httpClient;

        public EdgegapAPI(string apiToken)
        {
            _httpClient = new HttpClient();
            _httpClient.DefaultRequestHeaders.Add("Authorization", $"Token {apiToken}");
        }

        public async Task<RelaySessionAuthorization> CreateRelaySession(List<string> ips)
        {
            var jsonBody = new
            {
                users = ips.ConvertAll(ip => new { ip })
            };

            var postResponse = await _httpClient.PostAsJsonAsync("https://api.edgegap.com/v1/relays/sessions", jsonBody);
            var postJsonData = await postResponse.Content.ReadFromJsonAsync<Dictionary<string, object>>();

            if (!postJsonData.ContainsKey("session_id"))
            {
                throw new Exception("Échec de la création de la session de relais");
            }

            var sessionId = postJsonData["session_id"].ToString();

            var retries = 5;
            while (retries > 0)
            {
                var getResponse = await _httpClient.GetAsync($"https://api.edgegap.com/v1/relays/sessions/{sessionId}");
                var getJsonData = await getResponse.Content.ReadFromJsonAsync<Dictionary<string, object>>();
                var ready = (JsonElement)getJsonData["ready"];

                if (ready.ValueKind == JsonValueKind.True)
                {
                    var usersData = (JsonElement)getJsonData["session_users"];
                    var userAuthorizationTokens = new Dictionary<string, UInt32>();
                    foreach (var user in usersData.EnumerateArray())
                    {
                        var ipAddress = user.GetProperty("ip_address").GetString();
                        var userAuthorizationToken = user.GetProperty("authorization_token").GetUInt32();
                        userAuthorizationTokens[ipAddress] = userAuthorizationToken;
                    }

                    var relayData = (JsonElement)getJsonData["relay"];
                    var relayAddress = relayData.GetProperty("host").GetString();
                    var relayServerPort = relayData.GetProperty("ports").GetProperty("server").GetProperty("port").GetInt32();
                    var relayClientPort = relayData.GetProperty("ports").GetProperty("client").GetProperty("port").GetInt32();

                    return new RelaySessionAuthorization
                    {
                        SessionAuthorizationToken = sessionId,
                        UserAuthorizationTokens = userAuthorizationTokens,
                        RelayAddress = relayAddress,
                        RelayServerPort = relayServerPort,
                        RelayClientPort = relayClientPort
                    };
                }

                retries--;
                await Task.Delay(2000); // attendre 2 secondes avant de réessayer
            }

            throw new Exception("Échec pour obtenir une session de relais prête");
        }
    }

    public class RelaySessionAuthorization
    {
        public string? SessionAuthorizationToken { get; set; }
        public Dictionary<string, UInt32>? UserAuthorizationTokens { get; set; }
        public string? RelayAddress { get; set; }
        public int RelayServerPort { get; set; }
        public int RelayClientPort { get; set; }
    }
}
```

Vous devrez renvoyer ces informations au joueur concerné.

Le joueur agissant en tant que serveur aura besoin du `RelayServerPort` et tous les autres auront besoin du `RelayClientPort`

```csharp
using System.Text.Json;
using LobbyNamespace;

class Program
{
    static async Task Main(string[] args)
    {
        // Remplacez YOUR_API_TOKEN par votre jeton API réel
        var apiToken = "YOUR_API_TOKEN";

        // 1.1.1.1 est votre joueur agissant comme serveur
        // 2.2.2.2 est votre joueur agissant comme client
        var ips = new List<string> { "1.1.1.1", "2.2.2.2" };

        var edgegapAPI = new EdgegapAPI(apiToken);
        var relaySessionAuthorization = await edgegapAPI.CreateRelaySession(ips);

        // Générer le corps JSON pour le serveur (1.1.1.1)
        var serverJsonBody = new
        {
            relay_address = relaySessionAuthorization.RelayAddress,
            port = relaySessionAuthorization.RelayServerPort,
            session_authorization_token = relaySessionAuthorization.SessionAuthorizationToken,
            user_authorization_token = relaySessionAuthorization.UserAuthorizationTokens["1.1.1.1"]
        };
        var serverJson = JsonSerializer.Serialize(serverJsonBody);
        Console.WriteLine($"Corps JSON pour le serveur (1.1.1.1):\n{serverJson}");

        // Générer le corps JSON pour le client (2.2.2.2)
        var clientJsonBody = new
        {
            relay_address = relaySessionAuthorization.RelayAddress,
            port = relaySessionAuthorization.RelayClientPort,
            session_authorization_token = relaySessionAuthorization.SessionAuthorizationToken,
            user_authorization_token = relaySessionAuthorization.UserAuthorizationTokens["2.2.2.2"]
        };
        var clientJson = JsonSerializer.Serialize(clientJsonBody);
        Console.WriteLine($"Corps JSON pour le client (2.2.2.2):\n{clientJson}");
    }
}
```

### Interagir avec l'API (cURL ou POSTMAN)

Pendant le développement de votre jeu, vous devrez interagir avec l'API pour créer, gérer et supprimer des sessions de relais. Vous pouvez utiliser des outils comme cURL ou POSTMAN pour envoyer des requêtes HTTP à l'API.

cURL est un outil en ligne de commande qui vous permet d'effectuer des requêtes HTTP et d'interagir avec des API directement depuis le terminal. POSTMAN est une application GUI populaire qui simplifie les tests d'API en fournissant une interface conviviale pour créer, envoyer et analyser des requêtes HTTP.

Voici un exemple de création d'une session de relais en utilisant cURL :

```bash
curl -X POST -H "Content-Type: application/json" -H "Authorization: Token API_TOKEN" -d '{
  "users": [
    {
      "ip": "1.1.1.1"
    },
    {
      "ip": "2.2.2.2"
    }
  ],
  "webhook_url": "https://webhook.example.com/notify"
}' "https://api.edgegap.com/v1/relays/sessions"
```

{% hint style="info" %}
N'oubliez pas de remplacer `API_TOKEN` par votre jeton API de relais réel.
{% endhint %}

L'API vous renverra également une réponse contenant des données. Vous devrez analyser cette réponse et extraire les données dont vous avez besoin.


# Exemples de transport

Après avoir géré vos joueurs avec un matchmaker ou des lobbys puis créé une session de relais pour eux en utilisant l'API Edgegap, vous devrez connecter vos joueurs au relais une fois qu'il est prêt. Edgegap propose un transport spécifique pour faire cela, et ce guide vous montrera comment l'implémenter dans votre projet. Le transport est disponible [ici sur notre GitHub](https://github.com/edgegap/distributed-relay-examples/tree/main).

Avec Unity, il existe actuellement une version du transport pour les netcodes suivants :

* Mirror ;
* Fishnet ;
* Unity Netcode for GameObjects (NGO).

### Ajout du transport

Après avoir téléchargé le transport approprié pour votre netcode, vous devez l'inclure dans votre projet. Tout d'abord, ajoutez-le à vos fichiers de projet à l'emplacement suivant :

* **Mirror** : ajoutez le `Edgegap` dossier sous `Assets/Mirror/Transports`;
* **Fishnet** : ajoutez le `Edgegap KcpTransport` dossier sous `Assets/Fishnet/Plugins`;
* **NGO** : ajoutez le `EdgegapRelay` et `kcp2k` dossiers sous `Assets/Edgegap`.

Ensuite, ajoutez le `EdgegapKcpTransport` script à votre `NetworkManager` gameObject, assurez-vous également de faire glisser ce nouveau composant dans la `propriété Transport` du gameObject.

{% hint style="info" %}
Si l'option est présente, assurez-vous de désactiver `la GUI Relay` dans le `EdgegapKcpTransport` composant du `NetworkManager`. Sinon, il interférera lors de la tentative de connexion au relais.

Cette option est notamment présente dans les versions Mirror et NGO du transport.
{% endhint %}

### Connexion au relais

Après le matchmaking et la création de la session de relais, utilisez l'API Edgegap pour déterminer quand le relais est prêt à accepter des connexions. Une fois prêt, utilisez les données fournies dans la réponse de l'API pour définir les valeurs du transport. Vous aurez besoin des valeurs suivantes dans les champs appropriés :

* le `IP` adresse est utilisée comme `l'adresse du relais du transport`;
* le `token d'autorisation de session` est utilisé comme `l'ID de session du transport`;
* le `token d'autorisation de l'utilisateur` est utilisé comme `ID utilisateur du transport`.

#### Connexion Serveur/Hôte

* le `port du serveur` la valeur est utilisée comme `le port du relais du transport` .

#### Connexion Client

* le `port client` la valeur est utilisée comme `le port du relais du transport` .

{% hint style="info" %}
Chaque joueur aura son propre token d'autorisation unique, mais le token de session restera identique pour chaque joueur de la session.
{% endhint %}

### Utilisation avec Mirror

```cs
// `data` est la réponse API désérialisée convertie en JSON
// `_EdgegapTransport` est l'EdgegapKcpTransport

// Convertir uint? en uint
uint sessionAuthorizationToken = data.authorization_token ?? 0;

//TODO trouver quel utilisateur de session correspond au joueur, `i` étant sa position dans la liste
uint userAuthorizationToken = data.session_users?[i].authorization_token ?? 0;

_EdgegapTransport.ChangeValue(
    data.relay.ip,
    data.relay.ports.client.port,
    data.relay.ports.server.port,
    data.session_id,
    sessionAuthorizationToken,
    userAuthorizationToken
);

// puis `NetworkManager.Singleton.StartHost();` si joueur hôte
// OU `NetworkManager.Singleton.StartClient();` si client 
```

### Utilisation avec Fishnet

```cs
// `data` est la réponse API désérialisée convertie en JSON
// `_transport` est l'EdgegapKcpTransport

// Convertir uint? en uint
uint sessionAuthorizationToken = data.authorization_token ?? 0;

//TODO trouver quel utilisateur de session correspond au joueur, `i` étant sa position dans la liste
uint userAuthorizationToken = data.session_users?[i].authorization_token ?? 0;

Relay relay = data.relay;
string address = relay.ip;
ushort serverPort = relay.ports.server.port;
ushort clientPort = relay.ports.client.port;

var relayData = new EdgegapRelayData(
    address,
    serverPort,
    clientPort,
    userAuthorizationToken,
    sessionAuthorizationToken
);
_transport.SetEdgegapRelayData(relayData);

// puis `_transport.StartConnection(true);` si hôte
// OU `_transport.StartConnection(false);` si client
```

### Utilisation avec NGO

```cs
// `data` est la réponse API désérialisée convertie en JSON
// `_EdgegapTransport` est l'EdgegapKcpTransport

// Convertir uint? en uint
uint sessionAuthorizationToken = data.authorization_token ?? 0;

//TODO trouver quel utilisateur de session correspond au joueur, `i` étant sa position dans la liste
uint userAuthorizationToken = data.session_users?[i].authorization_token ?? 0;

_EdgegapTransport.relayAddress = data.relay.ip;
_EdgegapTransport.relayGameClientPort = data.relay.ports.client.port;
_EdgegapTransport.relayGameServerPort = data.relay.ports.server.port;
_EdgegapTransport.sessionId = sessionAuthorizationToken;
_EdgegapTransport.userId = userAuthorizationToken;

// puis `NetworkManager.Singleton.StartHost();` si joueur hôte
// OU `NetworkManager.Singleton.StartClient();` si client 
```

### Utilisation d'ApiResponse

```cs
public class ApiResponse
{
    public string session_id { get; set; }
    public uint? authorization_token { get; set; }
    public string status { get; set; }
    public bool ready { get; set; }
    public bool linked { get; set; }
    public object? error { get; set; }
    public List<SessionUser>? session_users { get; set; }
    public Relay relay { get; set; }
    public object? webhook_url { get; set; }
}
```

Une fois que les valeurs sont correctement définies, utilisez le transport pour connecter chaque joueur au relais. Après un court instant, vous pourrez jouer au jeu !

### Projets d'exemple

Les projets suivants sont de simples exemples qui utilisent le transport de relais Edgegap.

Pour qu'ils fonctionnent correctement, ouvrez un terminal de commande et téléchargez le projet via la commande `git clone [URL]` Ouvrez le dossier du projet dans l'éditeur via Unity Hub, puis modifiez la `valeur RelayProfileToken` dans le `HelloWorldManager` composant du `NetworkManager` gameObject par votre propre token de profil de relais.

* [Exemple Mirror](https://github.com/edgegap/unity-mirror-relay-sample)
* [Exemple Fishnet](https://github.com/edgegap/unity-fishnet-relay-sample)
* [Exemple NGO](https://github.com/edgegap/unity-ngo-relay-sample)

{% hint style="info" %}
Utilisez votre [token de profil de relais](https://app.edgegap.com/relay-management/dashboard) dans l’en-tête `HelloWorldManager.cs` ou `EdgegapRelayService.cs`.
{% endhint %}


# Référence API

Accédez aux fonctions de gestion de vos ressources Edgegap en utilisant des requêtes HTTP.

<a href="https://raw.githubusercontent.com/edgegap/openapi-specification/refs/heads/main/edgegap-v2-openapi.yaml" class="button primary" data-icon="square-down">Télécharger openapi \[v2]</a> <a href="https://api.edgegap.com/swagger.json" class="button secondary" data-icon="square-down">Télécharger openapi \[v1]</a>&#x20;

### Jeton d'authentification

Générez (et consultez) vos jetons secrets pour l'API Edgegap dans [Tableau de bord - Paramètres utilisateur / Jetons](https://app.edgegap.com/user-settings?tab=tokens).

Ajoutez votre jeton secret à chaque requête API en tant qu'en-tête HTTP (incluez le mot `jeton`):

`Authorization: token xxxxxxxx-e458-4592-b607-c2c28afd8b62`

{% hint style="danger" %}
**N'intégrez pas les endpoints de l'API Edgegap dans le client du jeu, car votre jeton API offre un accès illimité à votre compte. Voir** [Broken link](https://docs.edgegap.com/docs/broken-reference "mention") **pour des endpoints et des fonctions sécurisés destinés au client.**
{% endhint %}

{% hint style="success" %}
Si vos jetons secrets sont compromis, supprimez-les et mettez à jour les mots de passe des membres de l'organisation.
{% endhint %}

### Pagination des réponses

Si une réponse contient trop d'éléments, nous renvoyons un sous-ensemble de données avec des informations de pagination :

<pre class="language-json"><code class="lang-json">{
  "count": 100,
  "data": ["foo-0", "[...]", "bar-9"],
  "<a data-footnote-ref href="#user-content-fn-1">pagination</a>": {
    "number": 1,
    "next_page_number": 2,
    "previous_page_number": null
    "paginator": {
      "num_pages": 10
    },
    "has_next": true,
    "has_previous": false
  }
}
</code></pre>

Pour les réponses paginées, utilisez les paramètres `page` et `limit`  pour récupérer plus de résultats :

* deuxième page : `https://api.edgegap.com/v1/apps?`**`page=2`**
* plus de résultats : `https://api.edgegap.com/v1/apps?`**`limit=20`**
* combiné : `https://api.edgegap.com/v1/apps?`**`page=2&limit=20`**

### Limitation du débit

Pour assurer la stabilité de la plateforme et éviter les factures inattendues, nous limitons le taux d'utilisation de l'API de votre organisation :

* [deployments](https://docs.edgegap.com/learn/orchestration/deployments "mention") à 40 requêtes par seconde,
* [#context-and-status](https://docs.edgegap.com/learn/orchestration/deployments#context-and-status "mention") à 20 requêtes par seconde.

{% hint style="info" %}
[Contactez-nous](mailto:info@edgegap.com) pour **planifier des sorties, effectuer des tests de charge, estimer le trafic de lancement et vous préparer au succès.**
{% endhint %}

[^1]: contient des informations de pagination


# Serveurs dédiés

## ⚡ Déploiements

## \[v2] Deploy

> \<strong>\[Rate Limit: 40/seconds]\</strong> Initiate a new deployment. A deployment is a containerized server instance of an application version running on the Edgegap platform.

```json
{"openapi":"3.0.1","info":{"title":"Edgegap v2 API","version":"2026.02.20"},"servers":[{"url":"https://api.edgegap.com/v2","description":"Edgegap V2"}],"security":[{"api-token":[]}],"components":{"securitySchemes":{"api-token":{"type":"apiKey","in":"header","name":"Authorization"}},"schemas":{"DeploymentCreate":{"required":["application","users","version"],"properties":{"application":{"type":"string","description":"Name of the application that will be deployed"},"version":{"type":"string","description":"Name of the version within the application that will be deployed"},"require_cached_locations":{"type":"boolean","default":false,"description":"Deploy faster by limiting placement to locations with cached image.","nullable":true},"users":{"type":"array","description":"List of users. These users will be used to select the locations for the deployment","minItems":1,"items":{"$ref":"#/components/schemas/User"}},"environment_variables":{"type":"array","description":"List of environment variables to inject into the deployment","items":{"$ref":"#/components/schemas/DeploymentEnvironmentVariable"}},"tags":{"type":"array","description":"List of tags to associate with the deployment","items":{"type":"string"}},"webhook_on_ready":{"description":"Webhook to call when the deployment is ready","allOf":[{"$ref":"#/components/schemas/BasicWebhook"}]},"webhook_on_error":{"description":"Webhook to call when the deployment is in error","allOf":[{"$ref":"#/components/schemas/BasicWebhook"}]},"webhook_on_terminated":{"description":"Webhook to call when the deployment is terminated","allOf":[{"$ref":"#/components/schemas/BasicWebhook"}]}},"type":"object"},"User":{"required":["user_data","user_type"],"properties":{"user_type":{"type":"string","description":"Type of user (e.g., ip_address or geo_coordinates)"},"user_data":{"type":"object","description":"Dynamic user data depending on user_type","properties":{}}},"type":"object"},"DeploymentEnvironmentVariable":{"required":["is_hidden","key","value"],"properties":{"key":{"type":"string","description":"Environment variable key"},"value":{"type":"string","description":"Environment variable value"},"is_hidden":{"type":"boolean","description":"An hidden environment variable is not shown in the UI"}},"type":"object"},"BasicWebhook":{"required":["url"],"properties":{"url":{"type":"string","description":"Webhook URL"}},"type":"object"}}},"paths":{"/deployments":{"post":{"summary":"[v2] Deploy","deprecated":false,"description":"<strong>[Rate Limit: 40/seconds]</strong> Initiate a new deployment. A deployment is a containerized server instance of an application version running on the Edgegap platform.","operationId":"deployment-create","tags":[],"parameters":[],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeploymentCreate"}}}},"responses":{"202":{"description":"Deployment Request Accepted","content":{"application/json":{"schema":{"title":"","type":"object","properties":{"request_id":{"type":"string","description":"Request ID. Unique identifier of the deployment request"}},"required":["request_id"]}}},"headers":{}},"400":{"description":"Client Side Request Error","content":{"application/json":{"schema":{"title":"","type":"object","properties":{"message":{"type":"string","description":"Error message"},"details":{"type":"object","description":"Additional error details","properties":{}}},"required":["message"]}}},"headers":{}},"401":{"description":"Unauthorized - Missing Token","content":{"application/json":{"schema":{"title":"","type":"object","properties":{"message":{"type":"string","description":"Error message"},"details":{"type":"object","description":"Additional error details","properties":{}}},"required":["message"]}}},"headers":{}},"422":{"description":"Couldn't Allocate Server","content":{"application/json":{"schema":{"title":"","type":"object","properties":{"request_id":{"type":"string","description":"Request ID. Unique identifier of the deployment request"},"message":{"type":"string","description":"Error message"}},"required":["request_id","message"]}}},"headers":{}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"title":"","type":"object","properties":{"message":{"type":"string","description":"Error message"},"details":{"type":"object","description":"Additional error details","properties":{}}},"required":["message"]}}},"headers":{}}}}}}}
```

{% openapi src="<https://api.edgegap.com/swagger.json>" path="/v1/status/{request\_id}" method="get" %}
<https://api.edgegap.com/swagger.json>
{% endopenapi %}

{% openapi src="<https://api.edgegap.com/swagger.json>" path="/v1/stop/{request\_id}" method="delete" %}
<https://api.edgegap.com/swagger.json>
{% endopenapi %}

{% openapi src="<https://api.edgegap.com/swagger.json>" path="/v1/self/stop/{request\_id}/{access\_point\_id}" method="delete" %}
<https://api.edgegap.com/swagger.json>
{% endopenapi %}

{% openapi src="<https://api.edgegap.com/swagger.json>" path="/v1/deployments/bulk-stop" method="post" %}
<https://api.edgegap.com/swagger.json>
{% endopenapi %}

{% openapi src="<https://api.edgegap.com/swagger.json>" path="/v1/deployments" method="get" %}
<https://api.edgegap.com/swagger.json>
{% endopenapi %}

{% openapi src="<https://api.edgegap.com/swagger.json>" path="/v1/locations" method="get" %}
<https://api.edgegap.com/swagger.json>
{% endopenapi %}

{% openapi src="<https://api.edgegap.com/swagger.json>" path="/v1/deployment/{request\_id}/container-logs" method="get" %}
<https://api.edgegap.com/swagger.json>
{% endopenapi %}

{% openapi src="<https://api.edgegap.com/swagger.json>" path="/v1/metrics/deployment/{request\_id}" method="get" %}
<https://api.edgegap.com/swagger.json>
{% endopenapi %}

### Ancien \[v1]

{% hint style="warning" %}
Le point d'accès API Legacy v1/deploy est **obsolète, et a été remplacé par l'API v2** - voir [#deployments](#deployments "mention").
{% endhint %}

## Create a Deployment request.

> \[Rate Limit: 40/second] Create a new deployment. A deployment is a containerized instance of an application version running on the Edgegap platform.

```json
{"openapi":"3.1.1","info":{"title":"Edgegap V1","version":"0.0.0"},"tags":[{"name":"Deployments","description":"Deployments Control API - Please refer to <a href='https://docs.edgegap.com/docs/deployment' target='_blank'>this documentation</a> to get started with deployments."}],"servers":[{"url":"https://api.edgegap.com"}],"security":[{"apiKey":[]}],"components":{"securitySchemes":{"apiKey":{"type":"apiKey","in":"header","name":"authorization","description":"To access Edgegap API, generate (and view) your secret tokens in Dashboard - User Settings / Tokens. Add your secret token with each API request as an HTTP header (include the word token): `Authorization: token xxxxxxxx-e458-4592-b607-c2c28afd8b62`"}},"schemas":{"Request":{"required":["request_app","request_dns","request_id","request_user_count","request_version"],"properties":{"request_id":{"type":"string","description":"The identifier of the deployment request. This is used to track the deployment."},"request_dns":{"type":"string","description":"This is the FQDN that allow to connect to your Deployment. It will not resolve until the deployment is ready."},"request_app":{"type":"string","description":"The application that has been deployed."},"filters":{"type":"array","description":"List of filters applied to choose the location of the deployment.","items":{"$ref":"#/components/schemas/DeploymentFilterModel"}},"request_version":{"type":"string","description":"The version of the application that has been deployed."},"request_user_count":{"type":"integer","description":"This is the number of IP you have provided in the deployment request."},"tags":{"type":"array","description":"List of tags that have been injected in the deployment request. This field will only be present if tags were provided in the request.","items":{"type":"string"}},"container_log_storage":{"description":"Endpoint storage configuration that will be used to store the container logs when the deployment will be deleted. This field will only be present if container log storage was provided in the request.","$ref":"#/components/schemas/ContainerLogStorageModel"},"location":{"description":"The desired location centroid of the deployment. This field will only be present if a location was provided in the request.","$ref":"#/components/schemas/LocationModel"},"ap_sort_strategy":{"type":"string","description":"(DEPRECATED) - Will only be present if the request was made with the ap_sort_strategy field.","enum":["basic","weighted"]}},"type":"object"},"DeploymentFilterModel":{"required":["field","filter_type","values"],"properties":{"field":{"type":"string","description":"The deployment's field to filter on. See https://docs.edgegap.com/learn/advanced-features/deployments#filter-deployments for more details."},"values":{"type":"array","description":"The values to filter on.","items":{"type":"string"}},"filter_type":{"type":"string","description":"The type of filter.","enum":["any","all","not"]}},"type":"object"},"ContainerLogStorageModel":{"required":["enabled"],"properties":{"enabled":{"type":"boolean","description":"If true, the container logs will be stored in the provided endpoint storage at the end of the request. If false, the container logs will not be stored, even if set up in the app version."},"endpoint_storage":{"type":"string","description":"The name of the endpoint storage to be used. It must be the same as the one set on the dashboard when created. If container log storage is enabled without this parameter, we will try to take the app version endpoint storage. If there is no endpoint storage in your app version, the container logs will not be stored. If we don't find any endpointstorage associated with this name, the container logs will not be stored."}},"type":"object"},"LocationModel":{"required":["latitude","longitude"],"properties":{"latitude":{"type":"number","description":"Desired Latitude"},"longitude":{"type":"number","description":"Desired Longitude"}},"type":"object"},"Error":{"required":["message"],"properties":{"message":{"type":"string","description":"A message depending of the request termination"}},"type":"object"},"DeployModel":{"required":["app_name"],"properties":{"app_name":{"type":"string","description":"The application you want to deploy a version of."},"version_name":{"type":"string","description":"The application version you want to deploy a container, if not present, the last version created is automatically chosen."},"is_public_app":{"type":"boolean","description":"(DEPRECATED) - No longer used and you don't need to set it.","default":false},"ip_list":{"type":"array","description":"This parameter is not optional, but mutually exclusive with the geo_ip_list parameter. One of them is required. List of IP representing your users. These will be used to determine the best location for your deployment.","items":{"type":"string"}},"geo_ip_list":{"type":"array","description":"This parameter is not optional, but mutually exclusive with the ip_list parameter. One of them is required. List of IP of your user with their location (latitude, longitude). We will use the coordinates instead of the IPs to determine the best location for your deployment.","items":{"$ref":"#/components/schemas/GeoIpListModel"}},"telemetry_profile_uuid_list":{"type":"array","description":"(DEPRECATED)","items":{"type":"string"}},"env_vars":{"type":"array","description":"List of environment variables to set in your deployment instance. These variables will be available in your container.","items":{"$ref":"#/components/schemas/DeployEnvModel"}},"skip_telemetry":{"type":"boolean","description":"If true, the deployment will skip the telemetry measurement. This result in a faster time to deploy.","default":true},"location":{"description":"Specify the centroid of the deployment instead of letting the system choose the best location. The system will do a best effort to deploy the container in the closest location to the specified coordinates.","$ref":"#/components/schemas/LocationModel"},"webhook_url":{"type":"string","description":"A URL to send a POST request when the deployment is ready. The request will contain the deployment status. The content of the request is the same as the `v1/status/{request_id}` endpoint."},"tags":{"type":"array","description":"List of tags associated with the deployment. These tags will be shown in the dashboard.","items":{"type":"string"}},"container_log_storage":{"description":"Configuration for the container log storage. This will override the app version default configuration if set.","$ref":"#/components/schemas/ContainerLogStorageModel"},"filters":{"type":"array","description":"List of filters to apply to the deployment. The deployment will be deployed in a location that match the filters.","items":{"$ref":"#/components/schemas/DeploymentFilterModel"}},"ap_sort_strategy":{"type":"string","description":"(DEPRECATED) - No longer used and you don't need to set it.","enum":["basic","weighted"]},"command":{"type":["string","null"],"description":"Allows to override the container command for this deployment. This is an advanced feature and should be used with caution.If set to null, the default command of the container will be used."},"arguments":{"type":["string","null"],"description":"Allows to override the container arguments for this deployment. This is an advanced feature and should be used with caution.If set to null, the default arguments of the container will be used."}},"type":"object"},"GeoIpListModel":{"required":["ip","latitude","longitude"],"properties":{"ip":{"type":"string","description":"IP address"},"latitude":{"type":"number","description":"Latitude of the IP/User"},"longitude":{"type":"number","description":"Longitude of the IP/User"}},"type":"object"},"DeployEnvModel":{"required":["key","value"],"properties":{"key":{"type":"string","description":"Key of the environment variable. This key will be used to access the value in your container."},"value":{"type":"string","description":"Value of the environment variable. This value will be set in your container. Max 4096 characters."},"is_hidden":{"type":"boolean","description":"If true, the environment variable will be encrypted and only decrypted in the container."}},"type":"object"}}},"paths":{"/v1/deploy":{"post":{"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Request"}}}},"400":{"description":"Bad Request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Conflict","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Unprocessable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"summary":"Create a Deployment request.","description":"[Rate Limit: 40/second] Create a new deployment. A deployment is a containerized instance of an application version running on the Edgegap platform.","operationId":"deploy","tags":["Deployments"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeployModel"}}},"required":true}}}}}
```

## 🗺️ Flottes privées

## Deploy to Fleet

> \<strong>\[Rate Limit: 40/seconds]\</strong> Initiate a new private fleet deployment. A deployment is a containerized server instance of an application version running on the Edgegap platform.

```json
{"openapi":"3.0.1","info":{"title":"Edgegap v2 API","version":"2026.02.20"},"servers":[{"url":"https://api.edgegap.com/v2","description":"Edgegap V2"}],"security":[{"api-token":[]}],"components":{"securitySchemes":{"api-token":{"type":"apiKey","in":"header","name":"Authorization"}},"schemas":{"PrivateFleetDeploymentCreate":{"type":"object","properties":{"application":{"type":"string","description":"Name of the application that will be deployed"},"version":{"type":"string","description":"Name of the version within the application that will be deployed"},"require_cached_locations":{"type":"boolean","default":false,"description":"Deploy faster by limiting placement to locations with cached image.","nullable":true},"private_host_ids":{"type":"array","items":{"type":"string"},"description":"Preferred and prioritized Private Host IDs to try before overflowing to cloud.","minItems":1,"uniqueItems":true},"users":{"type":"array","description":"List of users. These users will be used to select the locations for the deployment","minItems":1,"items":{"$ref":"#/components/schemas/User"}},"environment_variables":{"type":"array","description":"List of environment variables to inject into the deployment","items":{"$ref":"#/components/schemas/DeploymentEnvironmentVariable"}},"tags":{"type":"array","description":"List of tags to associate with the deployment","items":{"type":"string"}},"webhook_on_ready":{"description":"Webhook to call when the deployment is ready","allOf":[{"$ref":"#/components/schemas/BasicWebhook"}]},"webhook_on_error":{"description":"Webhook to call when the deployment is in error","allOf":[{"$ref":"#/components/schemas/BasicWebhook"}]},"webhook_on_terminated":{"description":"Webhook to call when the deployment is terminated","allOf":[{"$ref":"#/components/schemas/BasicWebhook"}]}},"required":["application","users","version","private_host_ids"]},"User":{"required":["user_data","user_type"],"properties":{"user_type":{"type":"string","description":"Type of user (e.g., ip_address or geo_coordinates)"},"user_data":{"type":"object","description":"Dynamic user data depending on user_type","properties":{}}},"type":"object"},"DeploymentEnvironmentVariable":{"required":["is_hidden","key","value"],"properties":{"key":{"type":"string","description":"Environment variable key"},"value":{"type":"string","description":"Environment variable value"},"is_hidden":{"type":"boolean","description":"An hidden environment variable is not shown in the UI"}},"type":"object"},"BasicWebhook":{"required":["url"],"properties":{"url":{"type":"string","description":"Webhook URL"}},"type":"object"},"Error":{"required":["message"],"properties":{"message":{"type":"string","description":"Error message"},"details":{"type":"object","description":"Additional error details","properties":{}}},"type":"object"},"ParameterError422":{"required":["message","request_id"],"properties":{"request_id":{"type":"string","description":"Request ID. Unique identifier of the deployment request"},"message":{"type":"string","description":"Error message"}},"type":"object"}}},"paths":{"/private-fleets/deployments":{"post":{"summary":"Deploy to Fleet","deprecated":false,"description":"<strong>[Rate Limit: 40/seconds]</strong> Initiate a new private fleet deployment. A deployment is a containerized server instance of an application version running on the Edgegap platform.","operationId":"private-fleets-deployment-create","tags":[],"parameters":[],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PrivateFleetDeploymentCreate"}}}},"responses":{"202":{"description":"","content":{"application/json":{"schema":{"title":"","type":"object","properties":{"request_id":{"type":"string","description":"Request ID. Unique identifier of the deployment request"}},"required":["request_id"]}}},"headers":{}},"400":{"description":"Invalid Application or Application Version. No deployment has been created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{}},"401":{"description":"Unauthorized. No deployment has been created.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{}},"422":{"description":"Could not allocate an Edge Server for the deployment. A deployment has been created. Deployment is in error state. You can delete it manually or it will be deleted automatically by our system after some some times","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ParameterError422"}}},"headers":{}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{}}}}}}}
```

## List Private Fleet Hosts

> \<strong>\[Rate Limit: 10/seconds]\</strong> List all hosts in a private fleet.

```json
{"openapi":"3.0.1","info":{"title":"Edgegap v2 API","version":"2026.02.20"},"servers":[{"url":"https://api.edgegap.com/v2","description":"Edgegap V2"}],"security":[{"api-token":[]}],"components":{"securitySchemes":{"api-token":{"type":"apiKey","in":"header","name":"Authorization"}}},"paths":{"/private-fleets/{fleet-name}/hosts":{"get":{"summary":"List Private Fleet Hosts","deprecated":false,"description":"<strong>[Rate Limit: 10/seconds]</strong> List all hosts in a private fleet.","operationId":"private-fleet-hosts-list","tags":[],"parameters":[{"name":"fleet-name","in":"path","description":"Name of your private fleet.","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"host_id":{"type":"string","description":"Unique private fleet host identifier, used to deploy on this host."},"status":{"type":"string","description":"Lifecycle stage of the host, only ACTIVE hosts accept deployments.","enum":["PENDING","ACTIVE"]},"ip_address":{"type":"string","description":"Public IP address of the host.","nullable":true},"latitude":{"type":"number","description":"Approximate geographic latitude of the host.","nullable":true},"longitude":{"type":"number","description":"Approximate geographic longitude of the host.","nullable":true},"city":{"type":"string","description":"City in which the host is located.","nullable":true},"country":{"type":"string","description":"Country in which the host is located.","nullable":true},"continent":{"type":"string","description":"Continent in which the host is located.","nullable":true},"allocated_cpu_units":{"type":"integer","description":"Total virtual CPU units currently in use for deployments, beacons, and orchestration.","nullable":true},"allocated_memory_mb":{"type":"integer","description":"Total memory in MB currently in use for deployments, beacons, and orchestration."},"allocatable_cpu_units":{"type":"integer","description":"Total available virtual CPU units for deployments.","nullable":true},"allocatable_memory_mb":{"type":"integer","description":"Total available memory in MB for deployments.","nullable":true},"beacon":{"type":"object","properties":{"tcp_port":{"type":"integer","description":"External beacon TCP port used to perform TCP ping."},"udp_port":{"type":"integer","description":"External beacon UDP port used to perform UDP ping."},"ip_address":{"type":"string","description":"Public IP address used to perform ping measurement."}},"required":["tcp_port","udp_port","ip_address"],"description":"Assigned beacon information, if enabled for this fleet.","nullable":true},"created_at":{"type":"string","description":"Timestamp of creation in UTC, ISO 8601 format."},"updated_at":{"type":"string","description":"Timestamp of last update in UTC, ISO 8601 format."},"centroid":{"type":"object","properties":{"label":{"type":"string","description":"Human readable label."},"latitude":{"type":"number","description":"Approximate geographic latitude of the centroid."},"longitude":{"type":"number","description":"Approximate geographic longitude of the centroid."},"radius_km":{"type":"integer","description":"Approximate geographic radius used to pick primary and fallback locations."},"desired_host_count":{"type":"integer","description":"Requested amount of hosts to be started under this centroid."}},"required":["label","latitude","longitude","radius_km","desired_host_count"],"description":"Centroid information used to orchestrate placement of the host."},"delete_schedule":{"type":"object","properties":{"uuid":{"type":"string","description":"Unique identifier of deletion schedule."},"scheduled_at":{"type":"string","description":"Timestamp of scheduled deletion in UTC, ISO 8601 format."}},"description":"If defined, specified when the host will be deleted.","required":["uuid","scheduled_at"],"nullable":true},"fleet_host_specifications":{"type":"object","properties":{"cpu_units":{"type":"integer","description":"Host specification vCPU units selected during fleet creation."},"memory_mb":{"type":"integer","description":"Host specification memory MB selected during fleet creation."},"base_clock_speed_mhz":{"type":"integer","description":"Host specification base CPU clock frequency selected during fleet creation."}},"required":["cpu_units","memory_mb","base_clock_speed_mhz"]}},"description":"List of private fleet hosts.","required":["host_id","status","allocated_cpu_units","allocated_memory_mb","created_at","updated_at","centroid","fleet_host_specifications"]}}},"required":["data"]}}},"headers":{}},"400":{"description":"","content":{"application/json":{"schema":{"title":"","type":"object","properties":{"message":{"type":"string","description":"Error message"},"details":{"type":"object","description":"Additional error details","properties":{}}},"required":["message"]}}},"headers":{}},"401":{"description":"","content":{"application/json":{"schema":{"title":"","type":"object","properties":{"message":{"type":"string","description":"Error message"},"details":{"type":"object","description":"Additional error details","properties":{}}},"required":["message"]}}},"headers":{}},"500":{"description":"","content":{"application/json":{"schema":{"title":"","type":"object","properties":{"message":{"type":"string","description":"Error message"},"details":{"type":"object","description":"Additional error details","properties":{}}},"required":["message"]}}},"headers":{}}}}}}}
```

## &#x20;🔖 Étiquettes

{% openapi src="<https://api.edgegap.com/swagger.json>" path="/v1/deployments/{request\_id}/tags" method="get" %}
<https://api.edgegap.com/swagger.json>
{% endopenapi %}

{% openapi src="<https://api.edgegap.com/swagger.json>" path="/v1/deployments/{request\_id}/tags/{tag\_name}" method="get" %}
<https://api.edgegap.com/swagger.json>
{% endopenapi %}

{% openapi src="<https://api.edgegap.com/swagger.json>" path="/v1/deployments/{request\_id}/tags" method="post" %}
<https://api.edgegap.com/swagger.json>
{% endopenapi %}

{% openapi src="<https://api.edgegap.com/swagger.json>" path="/v1/deployments/{request\_id}/tags/{tag\_name}" method="delete" %}
<https://api.edgegap.com/swagger.json>
{% endopenapi %}

{% openapi src="<https://api.edgegap.com/swagger.json>" path="/v1/deployments/{request\_id}/tags/{tag\_name}" method="patch" %}
<https://api.edgegap.com/swagger.json>
{% endopenapi %}


# Gestion des versions

## 📦 Applications

{% openapi src="<https://api.edgegap.com/swagger.json>" path="/v1/app" method="post" %}
<https://api.edgegap.com/swagger.json>
{% endopenapi %}

{% openapi src="<https://api.edgegap.com/swagger.json>" path="/v1/app/{app\_name}" method="patch" %}
<https://api.edgegap.com/swagger.json>
{% endopenapi %}

{% openapi src="<https://api.edgegap.com/swagger.json>" path="/v1/app/{app\_name}" method="get" %}
<https://api.edgegap.com/swagger.json>
{% endopenapi %}

{% openapi src="<https://api.edgegap.com/swagger.json>" path="/v1/app/{app\_name}" method="delete" %}
<https://api.edgegap.com/swagger.json>
{% endopenapi %}

{% openapi src="<https://api.edgegap.com/swagger.json>" path="/v1/app/{app\_name}/version" method="post" %}
<https://api.edgegap.com/swagger.json>
{% endopenapi %}

{% openapi src="<https://api.edgegap.com/swagger.json>" path="/v1/app/{app\_name}/version/{version\_name}" method="delete" %}
<https://api.edgegap.com/swagger.json>
{% endopenapi %}

{% openapi src="<https://api.edgegap.com/swagger.json>" path="/v1/app/{app\_name}/version/{version\_name}" method="get" %}
<https://api.edgegap.com/swagger.json>
{% endopenapi %}

{% openapi src="<https://api.edgegap.com/swagger.json>" path="/v1/app/{app\_name}/version/{version\_name}" method="patch" %}
<https://api.edgegap.com/swagger.json>
{% endopenapi %}

{% openapi src="<https://api.edgegap.com/swagger.json>" path="/v1/app/{app\_name}/versions" method="get" %}
<https://api.edgegap.com/swagger.json>
{% endopenapi %}

{% openapi src="<https://api.edgegap.com/swagger.json>" path="/v1/apps" method="get" %}
<https://api.edgegap.com/swagger.json>
{% endopenapi %}

## 💾 Registre de conteneurs

{% openapi src="<https://api.edgegap.com/swagger.json>" path="/v1/container-registry/images/{image\_name}/tags" method="get" %}
<https://api.edgegap.com/swagger.json>
{% endopenapi %}

{% openapi src="<https://api.edgegap.com/swagger.json>" path="/v1/container-registry/images/{image\_name}/tags/{tag\_name}" method="delete" %}
<https://api.edgegap.com/swagger.json>
{% endopenapi %}

## Create a New Pull Profile

> Create a pull profile. Pull profile will upload data from an endpoint storage to a deployment container on boot. You must link the application version to the pull profile first.

```json
{"openapi":"3.1.1","info":{"title":"Edgegap V1","version":"0.0.0"},"tags":[{"name":"Endpoint Storage","description":"Endpoint Storage Control API - Please refer to <a href='https://docs.edgegap.com/docs/deployment/endpoint-storage' target='_blank'>this documentation</a> to get started with storage."}],"servers":[{"url":"https://api.edgegap.com"}],"security":[{"apiKey":[]}],"components":{"securitySchemes":{"apiKey":{"type":"apiKey","in":"header","name":"authorization","description":"To access Edgegap API, generate (and view) your secret tokens in Dashboard - User Settings / Tokens. Add your secret token with each API request as an HTTP header (include the word token): `Authorization: token xxxxxxxx-e458-4592-b607-c2c28afd8b62`"}},"schemas":{"PullProfilePostResponse":{"required":["destination","name","source","source_type"],"properties":{"name":{"type":"string","description":"Name of the pull profile"},"source":{"type":"string","description":"Source in the S3 bucket to fetch from"},"source_type":{"type":"string","description":"If the source is a File or a Directory","enum":["File","Folder"]},"destination":{"type":"string","description":"Destination path where your source will be uploaded in your container. Make sure to avoid protected destinations, such as `/etc/`, as this will prevent the files from being copied to your deployment, and will make your deployment fail. Make sure a normal user can write to the destination folder."},"create_time":{"type":"string","description":"UTC time of pull profile creation"},"last_updated":{"type":"string","description":"UTC time of pull profile last update"}},"type":"object"},"Error":{"required":["message"],"properties":{"message":{"type":"string","description":"A message depending of the request termination"}},"type":"object"},"PullProfilePostPayload":{"required":["destination","name","source","source_type"],"properties":{"name":{"type":"string","description":"Name of the pull profile"},"source":{"type":"string","description":"Source in the S3 bucket to fetch from"},"source_type":{"type":"string","description":"If the source is a File or a Directory","enum":["File","Folder"]},"destination":{"type":"string","description":"Destination path where your source will be uploaded in your container. Make sure to avoid protected destinations, such as `/etc/`, as this will prevent the files from being copied to your deployment, and will make your deployment fail. Make sure a normal user can write to the destination folder."}},"type":"object"}}},"paths":{"/v1/storage/endpoint/{endpoint_name}/pull-profile":{"post":{"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PullProfilePostResponse"}}}},"400":{"description":"Bad Request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"summary":"Create a New Pull Profile","description":"Create a pull profile. Pull profile will upload data from an endpoint storage to a deployment container on boot. You must link the application version to the pull profile first.","operationId":"pull-profile-create","tags":["Endpoint Storage"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PullProfilePostPayload"}}},"required":true}}}}}
```

## Get a Pull Profile

> Retrieve a pull profile and its specifications.

```json
{"openapi":"3.1.1","info":{"title":"Edgegap V1","version":"0.0.0"},"tags":[{"name":"Endpoint Storage","description":"Endpoint Storage Control API - Please refer to <a href='https://docs.edgegap.com/docs/deployment/endpoint-storage' target='_blank'>this documentation</a> to get started with storage."}],"servers":[{"url":"https://api.edgegap.com"}],"security":[{"apiKey":[]}],"components":{"securitySchemes":{"apiKey":{"type":"apiKey","in":"header","name":"authorization","description":"To access Edgegap API, generate (and view) your secret tokens in Dashboard - User Settings / Tokens. Add your secret token with each API request as an HTTP header (include the word token): `Authorization: token xxxxxxxx-e458-4592-b607-c2c28afd8b62`"}},"schemas":{"PullProfileGetResponse":{"required":["destination","name","source","source_type"],"properties":{"name":{"type":"string","description":"Name of the pull profile"},"source":{"type":"string","description":"Source in the S3 bucket to fetch from"},"source_type":{"type":"string","description":"If the source is a File or a Directory","enum":["File","Folder"]},"destination":{"type":"string","description":"Destination path where your source will be uploaded in your container. Make sure to avoid protected destinations, such as `/etc/`, as this will prevent the files from being copied to your deployment, and will make your deployment fail. Make sure a normal user can write to the destination folder."},"create_time":{"type":"string","description":"UTC time of pull profile creation"},"last_updated":{"type":"string","description":"UTC time of pull profile last update"}},"type":"object"},"Error":{"required":["message"],"properties":{"message":{"type":"string","description":"A message depending of the request termination"}},"type":"object"}}},"paths":{"/v1/storage/endpoint/{endpoint_name}/pull-profile/{pull_profile_name}":{"get":{"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PullProfileGetResponse"}}}},"400":{"description":"Bad Request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"summary":"Get a Pull Profile","description":"Retrieve a pull profile and its specifications.","operationId":"pull-profile-get","tags":["Endpoint Storage"]}}}}
```

## Update a Pull Profile

> Update a pull profile with new specifications.

```json
{"openapi":"3.1.1","info":{"title":"Edgegap V1","version":"0.0.0"},"tags":[{"name":"Endpoint Storage","description":"Endpoint Storage Control API - Please refer to <a href='https://docs.edgegap.com/docs/deployment/endpoint-storage' target='_blank'>this documentation</a> to get started with storage."}],"servers":[{"url":"https://api.edgegap.com"}],"security":[{"apiKey":[]}],"components":{"securitySchemes":{"apiKey":{"type":"apiKey","in":"header","name":"authorization","description":"To access Edgegap API, generate (and view) your secret tokens in Dashboard - User Settings / Tokens. Add your secret token with each API request as an HTTP header (include the word token): `Authorization: token xxxxxxxx-e458-4592-b607-c2c28afd8b62`"}},"schemas":{"PulloProfilePatchResponse":{"properties":{"name":{"type":"string","description":"Name of the pull profile"},"source":{"type":"string","description":"Source in the S3 bucket to fetch from"},"source_type":{"type":"string","description":"If the source is a File or a Directory","enum":["File","Folder"]},"destination":{"type":"string","description":"Destination path where your source will be uploaded in your container. Make sure to avoid protected destinations, such as `/etc/`, as this will prevent the files from being copied to your deployment, and will make your deployment fail. Make sure a normal user can write to the destination folder."},"create_time":{"type":"string","description":"UTC time of pull profile creation"},"last_updated":{"type":"string","description":"UTC time of pull profile last update"}},"type":"object"},"Error":{"required":["message"],"properties":{"message":{"type":"string","description":"A message depending of the request termination"}},"type":"object"},"PullProfilePatchPayload":{"properties":{"name":{"type":"string","description":"Name of the pull profile"},"source":{"type":"string","description":"Source in the S3 bucket to fetch from"},"source_type":{"type":"string","description":"If the source is a File or a Directory","enum":["File","Folder"]},"destination":{"type":"string","description":"Destination path where your source will be uploaded in your container. Make sure to avoid protected destinations, such as `/etc/`, as this will prevent the files from being copied to your deployment, and will make your deployment fail. Make sure a normal user can write to the destination folder."}},"type":"object"}}},"paths":{"/v1/storage/endpoint/{endpoint_name}/pull-profile/{pull_profile_name}":{"patch":{"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PulloProfilePatchResponse"}}}},"400":{"description":"Bad Request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"summary":"Update a Pull Profile","description":"Update a pull profile with new specifications.","operationId":"pull-profile-update","tags":["Endpoint Storage"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PullProfilePatchPayload"}}},"required":true}}}}}
```

## Delete a Pull Profile

> Delete a pull profile. All the application versions linked won't receive the data upload anymore. It will not delete your endpoint storage.

```json
{"openapi":"3.1.1","info":{"title":"Edgegap V1","version":"0.0.0"},"tags":[{"name":"Endpoint Storage","description":"Endpoint Storage Control API - Please refer to <a href='https://docs.edgegap.com/docs/deployment/endpoint-storage' target='_blank'>this documentation</a> to get started with storage."}],"servers":[{"url":"https://api.edgegap.com"}],"security":[{"apiKey":[]}],"components":{"securitySchemes":{"apiKey":{"type":"apiKey","in":"header","name":"authorization","description":"To access Edgegap API, generate (and view) your secret tokens in Dashboard - User Settings / Tokens. Add your secret token with each API request as an HTTP header (include the word token): `Authorization: token xxxxxxxx-e458-4592-b607-c2c28afd8b62`"}},"schemas":{"Error":{"required":["message"],"properties":{"message":{"type":"string","description":"A message depending of the request termination"}},"type":"object"}}},"paths":{"/v1/storage/endpoint/{endpoint_name}/pull-profile/{pull_profile_name}":{"delete":{"responses":{"204":{"description":"No Content"},"400":{"description":"Bad Request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"summary":"Delete a Pull Profile","description":"Delete a pull profile. All the application versions linked won't receive the data upload anymore. It will not delete your endpoint storage.","operationId":"pull-profile-delete","tags":["Endpoint Storage"]}}}}
```

## List All Pull Profile of an Endpoint Storage

> List all pull profiles of an endpoint storage.

```json
{"openapi":"3.1.1","info":{"title":"Edgegap V1","version":"0.0.0"},"tags":[{"name":"Endpoint Storage","description":"Endpoint Storage Control API - Please refer to <a href='https://docs.edgegap.com/docs/deployment/endpoint-storage' target='_blank'>this documentation</a> to get started with storage."}],"servers":[{"url":"https://api.edgegap.com"}],"security":[{"apiKey":[]}],"components":{"securitySchemes":{"apiKey":{"type":"apiKey","in":"header","name":"authorization","description":"To access Edgegap API, generate (and view) your secret tokens in Dashboard - User Settings / Tokens. Add your secret token with each API request as an HTTP header (include the word token): `Authorization: token xxxxxxxx-e458-4592-b607-c2c28afd8b62`"}},"schemas":{"PullProfilesListResponse":{"properties":{"pull_profiles":{"type":"array","items":{"$ref":"#/components/schemas/PullProfileGetResponse"}},"pagination":{"description":"Pagination Object","$ref":"#/components/schemas/Pagination"}},"type":"object"},"PullProfileGetResponse":{"required":["destination","name","source","source_type"],"properties":{"name":{"type":"string","description":"Name of the pull profile"},"source":{"type":"string","description":"Source in the S3 bucket to fetch from"},"source_type":{"type":"string","description":"If the source is a File or a Directory","enum":["File","Folder"]},"destination":{"type":"string","description":"Destination path where your source will be uploaded in your container. Make sure to avoid protected destinations, such as `/etc/`, as this will prevent the files from being copied to your deployment, and will make your deployment fail. Make sure a normal user can write to the destination folder."},"create_time":{"type":"string","description":"UTC time of pull profile creation"},"last_updated":{"type":"string","description":"UTC time of pull profile last update"}},"type":"object"},"Pagination":{"properties":{"number":{"type":"integer","description":"Current page number"},"next_page_number":{"type":"integer","description":"Next page number"},"previous_page_number":{"type":"integer","description":"Previous page number"},"paginator":{"$ref":"#/components/schemas/Paginator"},"has_next":{"type":"boolean","description":"If there is a next page"},"has_previous":{"type":"boolean","description":"If there is a previous page"}},"type":"object"},"Paginator":{"properties":{"num_pages":{"type":"integer","description":"Total pages count"}},"type":"object"},"Error":{"required":["message"],"properties":{"message":{"type":"string","description":"A message depending of the request termination"}},"type":"object"}}},"paths":{"/v1/storage/endpoint/{endpoint_name}/pull-profiles":{"get":{"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PullProfilesListResponse"}}}},"400":{"description":"Bad Request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"summary":"List All Pull Profile of an Endpoint Storage","description":"List all pull profiles of an endpoint storage.","operationId":"pull-profile-list","parameters":[{"schema":{"type":"integer","default":1},"name":"page","in":"query","description":"Page number for pagination"},{"schema":{"type":"integer","default":10},"name":"limit","in":"query","description":"Limit of pull profiles for each page"}],"tags":["Endpoint Storage"]}}}}
```

## Link a Pull Profile to an Application Version

> Link a pull profile to an app version. Without a link, the pull profile by itself will do nothing.

```json
{"openapi":"3.1.1","info":{"title":"Edgegap V1","version":"0.0.0"},"tags":[{"name":"Endpoint Storage","description":"Endpoint Storage Control API - Please refer to <a href='https://docs.edgegap.com/docs/deployment/endpoint-storage' target='_blank'>this documentation</a> to get started with storage."}],"servers":[{"url":"https://api.edgegap.com"}],"security":[{"apiKey":[]}],"components":{"securitySchemes":{"apiKey":{"type":"apiKey","in":"header","name":"authorization","description":"To access Edgegap API, generate (and view) your secret tokens in Dashboard - User Settings / Tokens. Add your secret token with each API request as an HTTP header (include the word token): `Authorization: token xxxxxxxx-e458-4592-b607-c2c28afd8b62`"}},"schemas":{"PullProfileAppVersionLinkResponse":{"required":["app","app_version","endpoint","pull_profile"],"properties":{"app":{"type":"string","description":"Name of the linked app of the linked version"},"app_version":{"type":"string","description":"Name of the linked app version."},"endpoint":{"type":"string","description":"Name of the endpoint storage"},"pull_profile":{"type":"string","description":"Name of the pull profile the app version is linked to."},"create_time":{"type":"string","description":"UTC time of link creation"},"last_updated":{"type":"string","description":"UTC time of link last update"}},"type":"object"},"Error":{"required":["message"],"properties":{"message":{"type":"string","description":"A message depending of the request termination"}},"type":"object"}}},"paths":{"/v1/storage/endpoint/{endpoint_name}/pull-profile/{pull_profile_name}/app/{app_name}/version/{version_name}":{"put":{"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PullProfileAppVersionLinkResponse"}}}},"400":{"description":"Bad Request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"summary":"Link a Pull Profile to an Application Version","description":"Link a pull profile to an app version. Without a link, the pull profile by itself will do nothing.","operationId":"pull-profile-link-app-version","tags":["Endpoint Storage"]}}}}
```

## Unlink a Pull Profile From an Application Version

> Unlink a pull profile from an app version. It will not delete the pull profile.

```json
{"openapi":"3.1.1","info":{"title":"Edgegap V1","version":"0.0.0"},"tags":[{"name":"Endpoint Storage","description":"Endpoint Storage Control API - Please refer to <a href='https://docs.edgegap.com/docs/deployment/endpoint-storage' target='_blank'>this documentation</a> to get started with storage."}],"servers":[{"url":"https://api.edgegap.com"}],"security":[{"apiKey":[]}],"components":{"securitySchemes":{"apiKey":{"type":"apiKey","in":"header","name":"authorization","description":"To access Edgegap API, generate (and view) your secret tokens in Dashboard - User Settings / Tokens. Add your secret token with each API request as an HTTP header (include the word token): `Authorization: token xxxxxxxx-e458-4592-b607-c2c28afd8b62`"}},"schemas":{"Error":{"required":["message"],"properties":{"message":{"type":"string","description":"A message depending of the request termination"}},"type":"object"}}},"paths":{"/v1/storage/endpoint/{endpoint_name}/pull-profile/{pull_profile_name}/app/{app_name}/version/{version_name}":{"delete":{"responses":{"204":{"description":"Success"},"400":{"description":"Bad Request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"summary":"Unlink a Pull Profile From an Application Version","description":"Unlink a pull profile from an app version. It will not delete the pull profile.","operationId":"pull-profile-unlink-app-version","tags":["Endpoint Storage"]}}}}
```

## 🗒️ Stockage des journaux

{% openapi src="<https://api.edgegap.com/swagger.json>" path="/v1/storage/endpoint" method="post" %}
<https://api.edgegap.com/swagger.json>
{% endopenapi %}

{% openapi src="<https://api.edgegap.com/swagger.json>" path="/v1/storage/endpoint/{endpoint\_name}" method="delete" %}
<https://api.edgegap.com/swagger.json>
{% endopenapi %}

{% openapi src="<https://api.edgegap.com/swagger.json>" path="/v1/storage/endpoints" method="get" %}
<https://api.edgegap.com/swagger.json>
{% endopenapi %}

{% openapi src="<https://api.edgegap.com/swagger.json>" path="/v1/storage/endpoint/{endpoint\_name}" method="get" %}
<https://api.edgegap.com/swagger.json>
{% endopenapi %}

{% openapi src="<https://api.edgegap.com/swagger.json>" path="/v1/storage/endpoint/{endpoint\_name}" method="patch" %}
<https://api.edgegap.com/swagger.json>
{% endopenapi %}


# Intégration

## ⭐ Mise en relation

Chaque entremetteur gère sa propre API privée, distincte de l'API Edgegap de votre organisation.

## 🧭 Navigateur de serveurs

Chaque entremetteur gère sa propre API privée, distincte de l'API Edgegap de votre organisation.

{% file src="broken-reference" %}

## 🗼 Balises

{% openapi src="<https://api.edgegap.com/swagger.json>" path="/v1/locations/beacons" method="get" %}
<https://api.edgegap.com/swagger.json>
{% endopenapi %}


# Relais

## 📫 Relais

{% openapi src="<https://api.edgegap.com/swagger.json>" path="/v1/relays/sessions" method="post" %}
<https://api.edgegap.com/swagger.json>
{% endopenapi %}

{% openapi src="<https://api.edgegap.com/swagger.json>" path="/v1/relays/sessions" method="get" %}
<https://api.edgegap.com/swagger.json>
{% endopenapi %}

{% openapi src="<https://api.edgegap.com/swagger.json>" path="/v1/relays/sessions/{session\_id}" method="delete" %}
<https://api.edgegap.com/swagger.json>
{% endopenapi %}

{% openapi src="<https://api.edgegap.com/swagger.json>" path="/v1/relays/sessions/{session\_id}" method="get" %}
<https://api.edgegap.com/swagger.json>
{% endopenapi %}

{% openapi src="<https://api.edgegap.com/swagger.json>" path="/v1/relays/sessions:authorize-user" method="post" %}
<https://api.edgegap.com/swagger.json>
{% endopenapi %}

{% openapi src="<https://api.edgegap.com/swagger.json>" path="/v1/relays/sessions:revoke-user" method="post" %}
<https://api.edgegap.com/swagger.json>
{% endopenapi %}


# Notes de version

{% hint style="info" %}
Voir les notes de version précédentes dans notre [archive](https://docs.edgegap.com/docs/release-notes/archive "mention").
{% endhint %}

### 2026.03.11 (Dernière)

**Nouveau ✨**

* Accédez à la documentation pertinente directement depuis le tableau de bord grâce à notre nouveau widget.
* Consultez les notes de version et les annonces de nouvelles fonctionnalités directement sur la page d'accueil du tableau de bord.
* Copiez les sorties désormais en un seul clic dans notre [unreal-engine](https://docs.edgegap.com/unreal-engine "mention") extension docker.

**Corrigé ✔**

* Correction d'un bug où la mise en cache restait active lorsqu'une application était désactivée.
* Correction d'un bug où l'utilisation de variables d'environnement secrètes contenant des caractères non ASCII renvoyait une erreur lors de la création d'un déploiement.
* Correction d'un bug où le solde de crédits ne se mettait pas à jour pour refléter les crédits utilisés ou expirés.

### 2026.02.24

**Améliorations 💪**

* Amélioration des états au survol sur la [Liste des déploiements](https://app.edgegap.com/deployment-management/deployments/list?deployments-table-limit=50\&deployments-table-page=1) page pour une meilleure clarté sur les actions disponibles au clic.
* Mise à niveau du framework du tableau de bord pour améliorer les performances et la stabilité. Si vous remarquez un comportement inattendu, veuillez le signaler dans notre [Discord communautaire](https://discord.gg/NgCnkHbsGp).

**Corrigé ✔**

* Correction d'un bug où les résultats des webhooks dans la page de détails du déploiement indiquaient incorrectement le code d'état HTTP 0 lorsque le gestionnaire de webhook ne renvoyait aucun corps JSON.

### 2026.02.16

**Nouveau ✨**

* Créer [versions d'application persistantes](https://docs.edgegap.com/learn/orchestration/persistance) depuis le tableau de bord, ne peuvent être déployées que dans [flottes privées](https://docs.edgegap.com/learn/orchestration/flottes-privees).

### 2026.02.10

**Nouveau ✨**

* Mesurez votre egress total de déploiement avec une nouvelle métrique dans l'historique des métriques du déploiement.
* Aperçu de l'adresse IP publique de votre déploiement et [webhook](https://docs.edgegap.com/learn/orchestration/deployments#webhooks-and-postbacks) réponses dans les détails du déploiement.

**Améliorations 💪**

* Amélioré [v2/deployments](https://docs.edgegap.com/docs/api/dedicated-servers#post-deployments) payloads de webhook avec :
  * ressources disponibles du déploiement : `vcpu_units`, `memory_mib` ; et
  * contexte de flotte privée : `host_id`, `host_in_private_fleet`, `private_fleet_id`  champs.

{% hint style="success" %}
**Passez à v2/deployments dès aujourd'hui pour débloquer des améliorations d'observabilité !** Les services gérés d'Edgegap (Matchmaker et Server Browser) utilisent automatiquement les dernières API de déploiement.
{% endhint %}

* Le tableau de bord indique désormais quand les modifications de version de l'application réinitialiseront la mise en cache active.
* Mise à jour de la disposition de la page de détails du déploiement dans le tableau de bord pour afficher les informations importantes en haut.
* Mise à jour de la métrique du nombre de joueurs dans le tableau de bord pour exclure les utilisateurs provenant de déploiements non prêts.
* Séparation des éléments de facturation pour Matchmaker, Server Browser et les Clusters pour plus de transparence.
* Clarification [page de tarification](https://app.edgegap.com/user-settings?tab=memberships) expliquant les produits et services inclus dans chaque niveau.
* Précision de la chronologie de tarification et de l'engagement pour les flottes privées dans la fenêtre de confirmation.

### 2026.01.27

**Nouveau ✨**

* Ajouté [notifications du tableau de bord](https://app.edgegap.com/notifications) pour les horaires de flotte privée, avec un résumé des hôtes provisionnés.

**Améliorations 💪**

* Améliorations majeures pour [Déploiements dans le tableau de bord](https://app.edgegap.com/deployment-management/deployments/list), rendant la numérisation rapide plus pratique.
* Augmentation de la taille par défaut de la liste des déploiements à 50 pour une meilleure visibilité des déploiements récents.
* Amélioration de [Flotte privée](https://app.edgegap.com/private-fleet-management/private-fleets/list) sélecteur de date du calendrier pour qu'il s'enregistre automatiquement lorsqu'on clique en dehors du sélecteur.
* Ajouté `caching_percent` attribut (toujours renvoyé) lors de la récupération d'une [version d'application avec l'API](https://docs.edgegap.com/docs/api/versioning#get-v1-app-app_name-version-version_name).
* Réactivation et amélioration de [la fonctionnalité des destinataires de facturation dans les paramètres du tableau de bord](https://app.edgegap.com/user-settings?tab=general).
* Ajout d'une indication de fuseau horaire pour [notifications du tableau de bord](https://app.edgegap.com/notifications) pour aider à aligner les équipes multinationales.

**Corrigé ✔**

* Correction de l'autocomplétion des tags d'image lors de [la création ou la modification d'une version d'application dans le tableau de bord](https://app.edgegap.com/application-management/applications/list).


# Archive

## 2026

<details>

<summary>Voir les notes de version 2026</summary>

### 2026.01.12

**Améliorations 💪**

* Amélioration des messages sur la page des détails de déploiement lorsqu'aucun [stockage des journaux](https://docs.edgegap.com/docs/endpoint-storage/save-container-logs) n'est configuré, affichant une explication claire au lieu d'une erreur générique.
* Validation renforcée des images de conteneur sur le tableau de bord pour mieux empêcher la création de versions d'application avec des images de conteneur invalides.

**Corrigé ✔**

* Correction d'un problème où la section crédits disponibles sur le tableau de bord affichait incorrectement « Non disponible. »
* Correction du [graphe d'aperçus de mémoire insuffisante (Out of Memory)](https://app.edgegap.com/analytics/dashboards/list) introduit dans la version précédente, qui n'affichait pas correctement les données.

### 2026.01.07

**Nouveau ✨**

* [**Flottes privées**](https://docs.edgegap.com/learn/orchestration/flottes-privees) — Réservez et gérez votre propre flotte de serveurs persistants (bare metal ou VM) dans les emplacements Edgegap du monde entier via notre plateforme en libre-service. Edgegap orchestre entièrement votre flotte et s'étend automatiquement vers notre cloud sans région lorsque le trafic dépasse la capacité, optimisant l'expérience des joueurs et les coûts d'infrastructure.
* [**Navigateur de serveurs**](https://docs.edgegap.com/learn/navigateur-de-serveurs) — Permettez aux joueurs de parcourir et rejoindre facilement des serveurs persistants. Conçu pour les MMO et jeux sociaux, il inclut l'authentification prête pour le jeu, la gestion automatisée des sessions avec optimisation de la latence, et une architecture de cluster privé évolutive.

</details>

***

## 2025

<details>

<summary>Voir les notes de version 2025</summary>

### 2025.12.16

**Améliorations 💪**

* Ajout de nouvelles informations pour les déploiements hors mémoire (OOM) dans [Analytique](https://app.edgegap.com/analytics/dashboards/list).

**Corrigé ✔**

* Ajout de la [prise en charge de la pagination](https://docs.edgegap.com/api#response-pagination) pour [API du registre - méthode de listing des tags d'image](https://docs.edgegap.com/api/gestion-des-versions#get-v1-container-registry-images-image_name-tags).

### 2025.11.03

**Améliorations 💪**

* Ajout du support SSO sur la page d'inscription du compte.
* Amélioration des erreurs de mise en cache pour [Déploiements en erreur](https://docs.edgegap.com/learn/orchestration/deployments#id-4.-deployment-error) pour [API de déploiement V2](https://docs.edgegap.com/api/serveurs-dedies#post-deployments).
* Amélioration des notifications pour les auto-nettoyages [Déploiements en erreur](https://docs.edgegap.com/learn/orchestration/deployments#id-4.-deployment-error) précisant qu'aucun frais n'a été ajouté.
* Amélioration des critères de l'indicateur de mise en cache, le statut de mise en cache vert est désormais plus fiable.

**Corrigé ✔**

* Correction de la traduction automatique incorrecte du jeton de démarrage rapide par le navigateur.
* Correction d'un problème empêchant les matchmakers ou clusters de démarrer dans certaines régions.

### 2025.09.11

**Nouveau ✨**

* Changez facilement le propriétaire de votre organisation sous [**Paramètres > Organisations > Gérer les rôles**](https://app.edgegap.com/user-settings?tab=organizations).

**Corrigé ✔**

* Correction des métriques en direct affichant la somme de l'utilisation par cœur au lieu du pourcentage global.
* Correction d'un problème où un avertissement d'authentification s'affichait parfois lors de la connexion au tableau de bord.

### 2025.09.09

**Nouveau ✨**

* Liez votre compte Discord pour un support plus rapide et une intégration facilitée.
* Ajout d'un nouvel emplacement de serveur à Berlin, Allemagne.

**Corrigé ✔**

* Correction des déploiements bloqués par une variable d'environnement vide et `is_hidden=true`.
* Correction d'un bug où un e-mail « pas de connexion » était envoyé par erreur après un nouvel abonnement à un niveau.

### 2025.08.27

**Améliorations 💪**

* Le tableau de bord se souvient désormais de votre appareil connecté pendant 7 jours avant de vous déconnecter.

**Corrigé ✔**

* Correction d'un bug empêchant la réutilisation des déploiements pour les sessions après 500x sessions.
* Correction d'une erreur levée lors de la suppression du stockage d'endpoint d'une version d'application.
* Correction d'une erreur causée par des filtres de déploiement plus complexes sur le tableau de bord avec des horodatages.
* Correction d'une erreur où certaines notifications du tableau de bord n'affichaient pas correctement les descriptions.

### 2025.08.20

**Nouveau ✨**

* [Spécifiez votre région de cluster préférée](https://app.edgegap.com/cluster-management/clusters/list) pour les clusters privés (services personnalisés) via le tableau de bord !

**Améliorations 💪**

* Les alertes de limitation de débit ne sont désormais envoyées que si elles sont dépassées plusieurs fois par minute.
* Mis à jour [registre Edgegap](https://app.edgegap.com/registry-management/repositories/list) URL vers `registry.edgegap.com`. Préfixe `registry2` conservé comme alias.

**Corrigé ✔**

* Correction des erreurs de métriques en direct sur la page du tableau de bord de déploiement dues à la récupération des données trop tôt.

### 2025.08.14

**Nouveau ✨**

* Spécifiez votre région de matchmaker préférée pour [niveaux de matchmaker privés](https://docs.edgegap.com/learn/matchmaking/matchmaker-in-depth#hosting-cluster) via le tableau de bord ! [Changez la région de votre cluster en cours d'exécution](https://app.edgegap.com/matchmaker-management-v2/matchmakers/list) avec un arrêt-démarrage. [En savoir plus sur les mises à jour sans temps d'arrêt.](https://docs.edgegap.com/learn/matchmaking/matchmaker-in-depth#rolling-updates-and-ab-tests)
* Demandez la disponibilité de la région Chine continentale pour votre [version d'application](https://app.edgegap.com/application-management/applications/list), sous réserve de l'examen par Edgegap.

**Améliorations 💪**

* [Les métriques d'historique de déploiement](https://docs.edgegap.com/learn/advanced-features/deployments#container-metrics) l'intervalle est désormais de 2 minutes, correspondant à la période d'agrégation des métriques. Les métriques en direct restent non agrégées avec des mesures à intervalle de 1 seconde.

**Corrigé ✔**

* Correction des tags de déploiement manquants dans la liste des déploiements et le filtrage pour [Flottes intelligentes](https://app.edgegap.com/fleet-management/smart-fleets/list).

### 2025.08.07

**Améliorations 💪**

* Échantillons de jeu mis à jour [fishnet-on-edgegap](https://docs.edgegap.com/docs/sample-projects/unity-netcodes/fishnet-on-edgegap "mention") et [unity-netcode-on-edgegap](https://docs.edgegap.com/docs/sample-projects/unity-netcodes/unity-netcode-on-edgegap "mention") pour la dernière LTS Unity 6.
* Ajout de la légende des métriques réseau aux métriques en direct du déploiement.
* Ajout du schéma de sécurité à la spécification openapi v2 pour simplifier les tests.

**Corrigé ✔**

* Correction d'une erreur interne dans [API des métriques](https://docs.edgegap.com/api/serveurs-dedies#get-v1-metrics-deployment-request_id) pour les déploiements n'atteignant pas [le statut Prêt](https://docs.edgegap.com/learn/orchestration/deployments#id-3.-deployment-ready)

### 2025.07.23

**Nouveau ✨**

* Créez des versions d'application avec jusqu'à **4 vCPU et 8 Go de RAM** depuis le tableau de bord.

**Corrigé ✔**

* Correction d'un problème occasionnel avec des points de données manquants dans les graphiques d'historique des détails de déploiement.
* Correction d'un bug empêchant la création de profils de registre tiers avec un jeton de plus de 1000 caractères (par ex. pour Google Registry).

### 2025.07.08

**Nouveau ✨**

* **La capacité du registre de conteneurs Edgegap a été augmentée à 10 Go pour tous les utilisateurs**, y compris le niveau gratuit !

**Améliorations 💪**

* Amélioration de l'expérience utilisateur de la page de création d'applications sur le tableau de bord.

**Corrigé ✔**

* Correction d'un bug où le nombre total de joueurs n'était pas affiché correctement sur la page d'accueil du tableau de bord dans certains cas. Cela représente la somme de toutes les adresses IP et coordonnées dans les requêtes de déploiement, y compris les déploiements matchmaker.
* Correction d'un problème sur la nouvelle page de version d'application où les champs n'étaient pas correctement préremplis lorsqu'on était redirigé depuis le plugin Unity.

***

### 2025.07.02

**Nouveau ✨**

* Créez et modifiez les versions d'apps plus facilement, désormais avec des suggestions d'entrée automatiques pour les conteneurs !
* Filtrez vos [analyses](https://app.edgegap.com/analytics/dashboards/list) rapports par version d'application, pour surveiller plus facilement l'utilisation des ressources pour des versions ayant des exigences de ressources différentes et la même image docker.
* Essayez nos exemples de jeu simplifiés et mis à jour sans construire de serveurs :
  * Unreal Engine 5.5.4 : [exemple-lyra](https://docs.edgegap.com/docs/sample-projects/unreal-engine/exemple-lyra "mention")
  * Unity 6 : [Photon Fusion 2 Asteroids](https://docs.edgegap.com/docs/sample-projects/unity-netcodes/photon-fusion-2-on-edgegap) | [mirror-pong](https://docs.edgegap.com/docs/sample-projects/unity-netcodes/mirror-pong "mention") | [FishNet HashGrid](https://docs.edgegap.com/docs/sample-projects/unity-netcodes/fishnet-on-edgegap)
* Exportez les journaux de déploiement vers [stockage d'endpoint](https://app.edgegap.com/endpoint-storage-management/endpoint-storages/list) sous forme de JSON délimités par nouvelle ligne (NDJSON).

**Améliorations 💪**

* Spécification API mise à jour et améliorée pour [Créer une version d'application](https://docs.edgegap.com/api/gestion-des-versions#post-v1-app-app_name-version) et [Mettre à jour une version d'application](https://docs.edgegap.com/api/gestion-des-versions#patch-v1-app-app_name-version-version_name). Aucun changement n'a été apporté aux payloads des requêtes/réponses des endpoints API.
* Ajout de plus d'indices pour [mise à niveau des niveaux de matchmaker](https://docs.edgegap.com/learn/matchmaking/matchmaker-in-depth#rolling-updates-and-ab-tests) dans le tableau de bord.
* Voir la date d'expiration de vos crédits gratuits dans les paramètres.

**Corrigé ✔**

* Correction d'un bug où les tags de déploiement n'étaient pas affichés sur la page de détails d'un déploiement archivé.

***

### 2025.06.30

**Nouveau ✨**

* **Déployez des serveurs plus facilement, plus rapidement et de manière plus fiable que jamais** avec `v2/deployments` .
  * Les plugins matchmaker et moteur seront prochainement mis à jour pour utiliser cette API (dans une nouvelle version).
  * Nous gardons `v1/deploy`  fonctionnel pour les intégrations legacy, aucune modification n'est requise.

**Améliorations 💪**

* [Flottes intelligentes](https://docs.edgegap.com/docs/fleet) dorénavant augmentent plus progressivement lorsqu'ils sont démarrés avec une valeur minimale élevée dans la politique. Vous ne devriez plus voir d'erreurs dues à un grand nombre de tentatives rapides de déploiement dans un tel scénario.
* Mis à jour [visuels des prix d'abonnement dans le tableau de bord](https://app.edgegap.com/user-settings?tab=memberships). Aucun changement n'a été apporté aux tarifs de la plateforme.

**Corrigé ✔**

* Correction de la désactivation du stockage des logs de conteneur par paramètre de requête pour [endpoint API de self-stop de déploiement](https://docs.edgegap.com/api/serveurs-dedies#delete-v1-self-stop-request_id-access_point_id).

***

### 2025.05.21

{% hint style="success" %}
🚀 **Matchmaker 3.0.0 est là !**

Cette mise à jour majeure introduit un remplissage d'équipe plus intelligent avec taille min/max d'équipe (changement incompatible), un matchmaking plus rapide et plus efficace, et une meilleure gestion des backfills et de la latence. [Voir le changelog complet...](https://docs.edgegap.com/learn/matchmaking/matchmaker-in-depth#id-3.0.0-may-20-2025)\
\
Pour effectuer la mise à jour, arrêtez votre matchmaker, modifiez la configuration et redémarrez. Un redémarrage rapide n'appliquera pas les mises à jour de version.
{% endhint %}

**Nouveau ✨**

* [**Tests et sorties :**](https://app.edgegap.com/test-and-release-management/test-and-release) Vous pouvez désormais planifier des sorties, playtests, démos et autres événements clés directement depuis le tableau de bord. Cela vous donne accès au support en direct et à une salle de réunion dédiée le jour de votre lancement, vous n'êtes donc jamais seul quand cela compte le plus.

**Améliorations 💪**

* Les nouveaux matchmakers utiliseront désormais automatiquement la version de Kubernetes mise à jour. Nous contacterons les propriétaires des matchmakers en cours d'exécution pour programmer les mises à jour à l'avance.

**Corrigé ✔**

* Correction d'un bug où un `attribut` label

***

### 2025.05.14

**Nouveau ✨**

* Un avis d'avertissement s'affiche désormais lors de la création ou mise à jour d'une version d'application utilisant le `dernière` étiquette Docker, ce qui est [fortement déconseillé pour éviter un comportement de mise en cache imprévisible](https://docs.edgegap.com/learn/orchestration/application-and-versions#container-parameters-required).
* Consulter :green\_circle: [disponible](https://docs.edgegap.com/learn/orchestration/deployments#high-availability) et :blue\_circle: [déploiements](https://docs.edgegap.com/learn/orchestration/deployments#high-availability) burstables [emplacements sur la carte du tableau de bord en temps réel](https://app.edgegap.com/).

**Corrigé ✔**

* La page des détails de déploiement affiche désormais tous les tags de déploiement (affichait auparavant seulement 10 résultats).

***

### 2025.05.01

**Nouveau ✨**

* Voir tous les tags associés qui seront supprimés lors de la suppression d'un artefact dans [Tableau de bord du registre](https://app.edgegap.com/registry-management/repositories/list).
* Ajout d'un lien direct « Payer la facture » dans la [section facturation](https://app.edgegap.com/user-settings?tab=invoices) pour faciliter le paiement manuel.

**Améliorations 💪**

* [Le graphique des déploiements récents dans le tableau de bord](https://app.edgegap.com/) n'affiche plus le dernier intervalle incomplet de 5 minutes.
* Toutes les préférences de tri des tableaux sur le tableau de bord sont désormais sauvegardées entre les sessions.
* Suppression des messages de suppression en double dans le tableau de bord pour certains cas limites.

***

### 2025.04.28

**Nouveau ✨**

* **Voir les métriques en direct rafraîchies toutes les 1 seconde depuis la page du déploiement !** Dépannez et optimisez l'utilisation des ressources plus facilement en surveillant l'utilisation du CPU et de la mémoire en temps réel.
* **Activez/désactivez la mise en cache et inspectez l'état de mise en cache** facilement dans votre [page liste des versions d'app sur le tableau de bord](https://app.edgegap.com/application-management/applications/list).
* **Évitez les déploiements lents dus à des erreurs de configuration** lors de la sortie de mises à jour. Vous serez maintenant [automatiquement notifié](https://app.edgegap.com/notifications) lorsque plus de 5 déploiements non mis en cache sont effectués en 1 minute.

**Améliorations 💪**

* Ouvrez les liens des ressources récemment mises à jour dans le tableau de bord dans un nouvel onglet avec un clic du milieu.
* Amélioration de la mise en page de connexion et d'inscription pour une expérience d'intégration plus fluide et intuitive.

**Corrigé ✔**

* Correction d'un bug où les logs de conteneur stockés sur votre endpoint S3 n'étaient pas affichés correctement si le nom de la version d'application contenait des caractères spéciaux sur la page de détails du déploiement archivé.
* Correction de l'affichage dupliqué des logs pour certains déploiements en cours.

***

### 2025.04.15

{% hint style="success" %}
**Le niveau gratuit a été augmenté pour permettre** [application-and-versions](https://docs.edgegap.com/learn/orchestration/application-and-versions "mention") **avec 1.5 vCPU et 3 Go de mémoire**, pour permettre de tester des serveurs plus exigeants (par ex. [exemple Unreal Engine Lyra](https://dev.epicgames.com/documentation/en-us/unreal-engine/lyra-sample-game-in-unreal-engine)) avant de passer au niveau payant à l'utilisation.
{% endhint %}

**Améliorations 💪**

* Amélioration de l'inscription et de l'intégration pour offrir une expérience plus fluide.
* Amélioration de la lecture rapide des ressources récentes - les icônes sont désormais placées sur la gauche.
* Mis à jour [`/v1/stop/{request_id}`](https://docs.edgegap.com/api/serveurs-dedies#v1-stop-request_id) Référence API avec explications plus claires et terminologie affinée pour la rendre plus facile à comprendre. Aucun changement n'a été apporté à l'endpoint API réel.

***

### 2025.04.10

**Nouveau ✨**

* Un tout nouveau tableau est désormais disponible sur l'écran d'accueil du tableau de bord ! Il affiche vos ressources récemment mises à jour — versions d'application, matchmakers et clusters — pour que vous puissiez voir d'un coup d'œil ce qui se passe et accéder directement à ce qui importe.

**Corrigé ✔**

* Correction d'un problème où les utilisateurs s'inscrivant avec un lien d'invitation expiré étaient invitées à créer une organisation par erreur. Le flux affiche désormais clairement une erreur si le lien n'est plus valide.
* Correction d'un cas rare où les logs des conteneurs de déploiement n'étaient pas visibles sur le tableau de bord, même lorsqu'ils auraient dû l'être.
* Correction d'un bug où la notification de mise en cache affichait un format d'heure erroné, entraînant des informations confuses.

***

### 2025.04.02

**Nouveau ✨**

* Notre toute nouvelle section d'analytique est désormais en ligne sur le tableau de bord ! Pour les utilisateurs Pay-as-You-Go, obtenez des informations approfondies sur vos conteneurs en cours d'exécution avec des métriques quasi temps réel sur l'utilisation du vCPU et de la RAM, la bande passante réseau, et plus encore. Optimisez les performances et gardez une longueur d'avance avec une meilleure surveillance des ressources !

**Améliorations 💪**

* Vous pouvez désormais trier la liste des versions de vos applications par nom sur le tableau de bord, ce qui facilite leur organisation et gestion.

***

### 2025.03.27

**Nouveau ✨**

* Les tags de déploiement sont désormais affichés sur la page de liste des sessions, et vous pouvez filtrer les sessions par tags de déploiement. &#x20;
* Nous appliquons désormais les mêmes validations lors du démarrage d'un matchmaker que lors de sa création. Ce changement clarifie si un matchmaker pourrait entraîner un matchmaking instable en raison d'une mauvaise configuration.&#x20;

**Améliorations 💪**

* Nous avons rafraîchi la [`/v1/deploy`](https://docs.edgegap.com/api/serveurs-dedies#v1-deploy) Référence API avec explications plus claires et terminologie améliorée pour une meilleure compréhension. Aucune modification n'a été apportée aux spécifications.
* Ajout de bannières visuelles pour les nouveaux utilisateurs afin de les guider vers la documentation lorsqu'ils arrivent sur le tableau de bord. &#x20;

***

### 2025.03.20

**Améliorations 💪**

* Le formulaire de création de matchmaker a été amélioré pour accélérer la création de nouveaux matchmakers en utilisant des modèles. De plus, des modifications ont été apportées pour garantir que la progression en cours n'est pas perdue lors de l'édition de la configuration dans la fenêtre de création. Nous essayons également de préremplir le formulaire avec votre dernière version d'application lors de l'utilisation de modèles.
* Le processus d'inscription via liens d'invitation a été amélioré pour utiliser automatiquement l'e-mail fourni par le propriétaire de l'organisation, garantissant que le flux n'est pas perturbé par un e-mail différent lors de l'inscription.

***

### 2025.03.17

**Nouveau ✨**

* [Présentation des Flottes auto-réparantes](https://docs.edgegap.com/docs/fleet): Edgegap réessaie désormais vos déploiements de Flotte en erreur jusqu'à 5 fois par jour, si le nombre de déploiements en cours est inférieur à votre capacité cible. [En savoir plus sur les raisons pour lesquelles votre déploiement peut se retrouver en erreur.](https://docs.edgegap.com/learn/advanced-features/deployments#id-4.-deployment-error)

**Améliorations 💪**

* Libellé du bouton du tableau de bord de matchmaker renommé en « Forcer l'arrêt » au lieu de « Supprimer » pour les matchmakers en erreur. Cette action ne change pas l'URL du matchmaker ni le token d'auth.

***

### 2025.03.05

**Nouveau ✨**

* Augmentation de la limite de déploiements en erreur simultanés pour les utilisateurs du niveau gratuit de 1 à 10. Nous avons observé que certains utilisateurs atteignaient la limite précédente, ce qui entraînait une mauvaise expérience. Ce changement offre plus de flexibilité lors des tests sur la plateforme.
* Les propriétaires d'organisation peuvent désormais voir les invitations de membres en attente sur la page des paramètres de l'organisation.

**Améliorations 💪**

* Ajout d'une validation supplémentaire lors de la création d'un matchmaker pour aider à prévenir l'utilisation de versions d'application invalides ou non mises en cache.
* Réorganisation de la mise en page de la page des paramètres de l'organisation pour améliorer la navigation et faciliter la gestion de votre organisation et l'ajout de membres.

***

### 2025.02.19

Hébergement pour Matchmaker Géré Legacy et [Matchmaker Avancé Legacy](https://docs.edgegap.com/learn/advanced-features/managed-clusters) a été déprécié et n'est plus disponible dans l'API ni le tableau de bord. Voir [Matchmaker Géré Gen2](https://docs.edgegap.com/docs/release-notes/broken-reference) ou [Matchmaker Avancé sur Clusters Gérés](https://docs.edgegap.com/learn/advanced-features/managed-clusters#advanced-matchmaker) pour notre dernière génération de produits de matchmaking.

**Améliorations 💪**

* Amélioration de la visibilité du bouton de redémarrage rapide pour le matchmaker sur le tableau de bord.
* Amélioration de l'affichage des identifiants utilisés pour pousser des images sur la page du registre.

**Corrigé ✔**

* Correction d'un bug où le même nom de version d'application pouvait être utilisé lors de la duplication d'une version d'application sur le tableau de bord.
* Correction d'un bug où certains contenus, tels que les tokens, variables d'environnement et exigences de conteneur, étaient incorrectement traduits par les fonctions de traduction automatique du navigateur.

***

### 2025.02.12

**Nouveau ✨**

* Refonte de la disposition de la barre latérale sur le tableau de bord pour la rendre plus conviviale et plus facile à naviguer.

**Améliorations 💪**

* Amélioration de la validation de disponibilité du matchmaker pour Gen2 au démarrage, réduisant la probabilité d'erreurs durant le déploiement.
* Amélioration de la mise en page de la page d'accueil avec une expérience de chargement plus fluide et de meilleures transitions d'éléments.

**Corrigé ✔**

* Correction d'un problème de validation où les caractères majuscules pouvaient être utilisés dans la configuration du conteneur d'une version d'application. Ce changement impose désormais uniquement des caractères en minuscules.
* Correction d'un bug où le temps restant d'un déploiement affiché sur le tableau de bord était inexact dans certains cas.
* Correction d'un bug où la documentation Swagger du matchmaker n'était pas régénérée après une mise à jour de configuration.

***

### 2025.02.06

**Nouveau ✨**

* Ajout d'un mécanisme de verrouillage empêchant la suppression d'une version d'application si elle est actuellement utilisée par un matchmaker. Ce changement s'applique à la fois à l'API et au tableau de bord.

**Corrigé ✔**

* Correction des incohérences dans les spécifications de l'API.

***

### 2025.01.30

**Corrigé ✔**

* Correction d'un problème où le rafraîchissement de la page de détails du matchmaker sur le tableau de bord entraînait une erreur 500.
* Correction d'une occurrence où le cache de certaines versions d'app pouvait être désactivé lorsque la communication avec Docker était peu fiable.
* Correction d'un bug où la liste des beacons provenant de l'API pouvait inclure des villes en double.

***

### 2025.01.21

**Nouveau ✨**

* Nous avons ajouté plus d'emplacements à notre réseau, offrant une meilleure couverture et des performances améliorées pour vos déploiements.

**Améliorations 💪**

* Amélioration de la gestion des profils de registre par défaut pour plus de clarté.

**Corrigé ✔**

* Correction d'un bug où la page du registre de conteneurs affichait « DateTime invalide » au lieu de la date réelle dans la section dernier pull/push.
* Correction d'un bug sur la page de détails de la version d'app où la progression de la mise en cache s'affichait toujours comme « faible (rouge) » même lorsque la couverture réelle était « élevée (vert) ».

***

### 2025.01.15

**Nouveau ✨**

* Lors de l'utilisation d'un [profil de registre Docker](https://docs.edgegap.com/learn/orchestration/application-and-versions#container-parameters-required), la création d'une nouvelle version d'app récupérera automatiquement les images et tags disponibles depuis votre dépôt pour sélection.
* [Les variables d'environnement de déploiement](https://docs.edgegap.com/learn/advanced-features/application-and-versions/#other-parameters-optional) peuvent désormais atteindre jusqu'à 4 Ko en taille.

**Corrigé ✔**

* Correction d'un problème où le plugin d'initialisation du registre de conteneurs ne fonctionnait pas et ne fournissait pas un accès approprié.
* Correction du code de statut de retour de 401 Unauthorized à 400 Bad Request lors de l'envoi d'une variable d'environnement trop longue dans une requête de déploiement.
* Correction d'un problème de mise en page sur le tableau de bord à travers plusieurs pages.
* Correction du flux de démarrage du matchmaker Gen2 pour réduire les erreurs potentielles lors du déploiement.

***

### 2025.01.13

{% hint style="info" %}
À partir de cette version, l'API imposera un ratio CPU/Mémoire de 1:2. Ce changement vise à maintenir les coûts au plus bas pour tous et améliorer l'orchestration de l'utilisation des ressources pour tous les utilisateurs.
{% endhint %}

**Nouveau ✨**

* Vous pouvez désormais utiliser des variables d'environnement d'application jusqu'à 4 Ko en taille.
* Notre chatbot Mava AI est désormais disponible dans le tableau de bord, en plus de Discord, permettant l'accès depuis plusieurs emplacements.
* Nous avons ajouté une nouvelle heatmap dans les détails de la version d'app affichant les points d'équilibre de vos requêtes de déploiement.
* La carte de la page d'accueil affiche désormais nos beacons disponibles.
* Nous avons ajouté une option pour effectuer un redémarrage rapide de votre matchmaker Gen2 sans avoir à changer quoi que ce soit dans la configuration. Notez que cela supprimera tous les tickets actuels et rendra temporairement l'API inaccessible.

**Améliorations 💪**

* La page de relais affiche désormais l'état de vos sessions de relais.
* L'ajout de tags depuis le tableau de bord utilise désormais la même validation que l'API, permettant une gamme de valeurs plus large.
* Amélioration de la validation de disponibilité du matchmaker lors du démarrage d'un Gen2, réduisant les faux positifs où le statut s'affichait comme prêt alors que le matchmaker restait inaccessible pendant un court instant.
* Accélération du temps de rechargement pour un matchmaker Gen2.
* Optimisations backend effectuées sur le tableau de bord pour une expérience légèrement plus rapide. Si vous rencontrez des erreurs inattendues sur certaines pages, veuillez nous le signaler via notre [Discord](https://discord.com/invite/NgCnkHbsGp).

**Corrigé ✔**

* Correction d'un problème où les graphiques de métriques ne s'affichaient parfois pas sur la page des détails du déploiement.
* Correction d'un problème où les sockets de session utilisés s'affichaient toujours à 0, même lorsque des sessions étaient présentes dans la page des détails du déploiement sous l'onglet session.

**Documentation 📚**

* nouveau : [centre d'apprentissage Unreal Engine](https://docs.edgegap.com/docs/release-notes/broken-reference) - [Outils pour développeurs](https://docs.edgegap.com/unreal-engine/developer-tools) et [Premiers pas avec les serveurs](https://docs.edgegap.com/unreal-engine)
* mis à jour [Documentation Gen2 Unity SDK dans Unity Developer Tools](https://docs.edgegap.com/unity/developer-tools#matchmaking-sdk)
* ajouté [Configuration d'exemple avancée ajoutée à Premiers pas avec Gen2](https://docs.edgegap.com/docs/release-notes/broken-reference)
* ajouté et mis à jour des requêtes/réponses d'exemple pour [Gen2 Matchmaker Approfondi](https://docs.edgegap.com/learn/matchmaking/gen2-matchmaker-in-depth)
* ajouté et mis à jour des astuces pour l'utilisation de [Ping Beacons](https://docs.edgegap.com/learn/orchestration/ping-beacons)

</details>

***

## 2024

<details>

<summary>Voir les notes de version 2024</summary>

### 2024.12.09

{% hint style="info" %}
Faites matcher les joueurs et lancez des jeux instantanément, facilement

Le Matchmaker « Gen 2 » d'Edgegap est désormais sorti de l'accès anticipé ! Qu'est-ce qui peut justifier un tel changement, vous demandez-vous ?

**Nouvelles fonctionnalités puissantes !**

En plus de l'appariement basé sur la latence sans région (le seul matchmaker avec cette fonctionnalité, à notre connaissance) et du matchmaking par équipe, nous avons :

* [Backfill automatisé](https://docs.edgegap.com/docs/release-notes/broken-reference): À la demande (populaire), nous ajoutons le backfill avec assignation automatique de tickets, ce qui vous permet de réutiliser des places serveur lorsque des joueurs quittent la session.
  * Idéal pour remplir des sièges joueurs vides après le début d'un match, ou pour remplacer des joueurs partis pendant un match.
* [Matchmaking de groupe](https://docs.edgegap.com/docs/release-notes/broken-reference): Nous ajoutons la possibilité de rejoindre en groupe à la capacité déjà disponible de remplir plusieurs équipes avec des joueurs.
  * Idéal pour rejoindre une file d'attente de matchmaking avec un groupe d'amis ou venant d'un lobby commun.
    {% endhint %}

**Nouveau ✨**

* Le tableau de bord impose désormais un minimum de 1/4 vCPU lors de la création d'une version d'application. Ce changement vise à réduire les problèmes d'intégration observés avec des instances plus petites et à améliorer l'expérience des nouveaux utilisateurs. Si vous avez besoin d'accéder à des incréments plus petits, veuillez nous contacter.
* L'API impose désormais un minimum de 1/4 vCPU lors de la création d'une version d'application. **Les utilisateurs utilisant auparavant des instances plus petites ne seront pas affectés par ce changement.** Si vous avez besoin d'accéder à des incréments plus petits, veuillez nous contacter.
* Nous avons ajouté un message d'avertissement lors de la mise à jour de la durée maximale d'une version d'application. Modifier cette valeur peut entraîner l'arrêt immédiat des déploiements en cours.
* Vous pouvez désormais modifier votre configuration pendant que le matchmaker est en cours d'exécution. Cela déclenche un rechargement rapide de votre configuration sans nécessiter un cycle complet on/off pour votre matchmaker. Remarque : cette fonctionnalité n'est pas recommandée en production, car elle supprime tous les tickets en cours et rend temporairement l'API non réactive.

**Améliorations 💪**

* La taille minimale pour Matchmaker Gen2 a été réduite à 1 CPU & 2 Go de mémoire, et son tarif a été réduit à 0,0312 $/heure. Ce changement réduit les coûts pour les environnements de développement et de test.
* Nous avons amélioré le flux pour les invitations d'organisation lorsque l'utilisateur invité est déjà enregistré sur la plateforme.
* Nous avons amélioré l'état de santé du matchmaker Gen2 pour prévenir les faux positifs.

**Corrigé ✔**

* Correction d'un bug où les sessions relais n'étaient pas automatiquement supprimées lorsque les joueurs dépassaient le temps imparti ou se déconnectaient du relais.
* Correction d'un bug où l'option de désactiver une application n'empêchait pas la création de déploiements.
* Correction d'un bug avec les graphiques de métriques de déploiement qui les faisait afficher des données incorrectes sur le tableau de bord.

**Documentation 📚**

* Nous avons corrigé la barre de recherche pour qu'elle fonctionne également dans le Learning Center.
* Ajout de documentation pour les nouvelles fonctionnalités du matchmaker Gen2 : [Backfill automatisé](https://docs.edgegap.com/docs/release-notes/broken-reference) et [Matchmaking de groupe](https://docs.edgegap.com/docs/release-notes/broken-reference).

***

### 2024.11.21

**Nouveau ✨**

* Nous avons ajouté la fonctionnalité permettant de demander notre nouveau Service de Consultation Premium, disponible via le modal utilisateur sur le tableau de bord.
* À partir de cette version, les versions d'application qui n'utilisent pas la mise en cache seront déployées sur un sous-ensemble d'emplacements. En conséquence, vos déploiements sans mise en cache activée peuvent être plus éloignés qu'auparavant. Ce changement n'a aucun effet sur les déploiements mis en cache. Cela fait partie de notre effort pour optimiser l'utilisation des ressources et fournir un meilleur service à tous les utilisateurs.
* La page d'accueil du tableau de bord affiche désormais une nouvelle boîte d'annonce en haut pour vous tenir informé des mises à jour et changements importants.
* Nous avons ajouté une barre de progression au processus de création et de suppression du matchmaker Gen2 pour vous donner une meilleure idée du temps restant.
* Vous pouvez désormais sauvegarder des identifiants provenant de registres de conteneurs externes et les utiliser comme identifiants par défaut lors de la création d'une nouvelle version d'application sur le tableau de bord. Cette fonctionnalité sera intégrée à nos plugins à l'avenir. Les identifiants par défaut fonctionnent également avec notre registre.
* Nous avons ajouté un bouton pour copier votre ID de requête sur la page du déploiement. Cette fonctionnalité vous aidera à fournir les informations nécessaires lors de la prise de contact avec le support.
* Pour améliorer l'expérience utilisateur, toutes les versions d'application doivent désormais avoir un temps de vie maximum (TTL) défini de 24 heures. Bien que ce TTL maximum ait été appliqué en interne depuis la version 2024.09.09, ce changement le rend visible sur le tableau de bord, réduisant la confusion concernant la suppression inattendue des déploiements.
* Vous pouvez désormais utiliser des filtres dans la route API de listing des déploiements pour filtrer les déploiements. Certains filtres disponibles sont le statut, la version, l'ID de requête, les tags, et plus encore. La documentation sera mise à jour prochainement avec des détails supplémentaires.
* Nous avons ajouté une [route API pour supprimer un lobby](https://docs.edgegap.com/docs/api).
* Nous avons ajouté une [route API pour lister tous les lobbies](https://docs.edgegap.com/docs/api).

**Améliorations 💪**

* Les espaces sont désormais pris en charge dans la création des noms d'organisation.
* Validation du nom de lobby mise à jour pour prévenir des erreurs de sortie inattendues.
* Nous prenons désormais en charge les buckets S3 d'AWS, en plus de la plupart des autres services de stockage compatibles S3 déjà pris en charge.

**Corrigé ✔**

* Correction d'un bug d'interface sur la page de déploiement où l'utilisation d'un grand nombre de tags cassait la mise en page.
* Correction d'un bug où appeler une API sur un lobby peu de temps après sa création retournait une erreur 503 Service Unavailable.
* Correction d'un bug où certaines variables d'environnement de port individuelles n'étaient pas correctement injectées dans le conteneur du déploiement.
* Correction d'un bug où les logs de déploiement du tableau de bord n'affichaient pas de messages d'erreur détaillés lorsqu'un déploiement échouait.
* Correction d'un bug où les ports des versions d'application étaient supprimés de manière inattendue lors de la mise à jour de la version d'application.
* Correction d'un bug qui rendait la création de sessions et de sessions relais plus lente que prévu.
* Correction d'un bug où il était impossible de supprimer un matchmaker Gen2 lorsque trop d'erreurs s'étaient produites lors de sa mise en ligne.

**Documentation 📚**

* Ajout d'un [exemple Unreal Top-Down](https://docs.edgegap.com/docs/sample-projects/unreal-engine/top-down-sample) de projet d'exemple.
* Corrections de cohérence pour la documentation du matchmaker Gen2.
* Mise à jour du Learning Center avec du nouveau contenu et des améliorations mineures de cohérence.

***

### 2024.10.30

**Nouveau ✨**

* Vous recevrez désormais une notification sur le tableau de bord lorsque vous atteignez une limite de rythme API. Cette notification vous aide à éviter un comportement inattendu lors de l'interaction avec l'API et vous alerte sur des problèmes potentiels et des coûts imprévus.
* Vous pouvez désormais filtrer vos déploiements par ville, pays et continent sur le tableau de bord.
* Les erreurs JSON du Matchmaker Gen2 sont désormais plus descriptives et plus faciles à comprendre lors de la création ou mise à jour d'un matchmaker.
* L'éditeur de configuration JSON pour le matchmaker Gen2 prend désormais en charge le copier-coller, annuler/rétablir, réduire/agrandir, la mise en évidence des erreurs JSON et l'auto-correction.

**Améliorations 💪**

* Nous avons amélioré le processus de création de matchmaker privé pour le rendre plus convivial et intuitif. Le flux de création et suppression d'un matchmaker privé sera légèrement plus long, mais nous prévoyons d'ajouter une fonction de rechargement, vous permettant de modifier votre configuration sans devoir arrêter et démarrer le matchmaker.

**Corrigé ✔**

* Correction d'un bug avec la fonctionnalité de suppression en masse des versions d'application qui ne fonctionnait pas correctement sur le tableau de bord.
* Correction d'un bug où la durée maximale de déploiement n'était pas correctement appliquée lors du déploiement d'une version d'application avec la mise en cache désactivée.
* Correction d'un bug où la validation du stockage d'endpoint sur le tableau de bord retournait des faux positifs pour des buckets mal configurés.

**Documentation 📚**

* Nous avons introduit notre nouveau [Learning Center](https://docs.edgegap.com/learn), où vous pouvez trouver toutes les ressources dont vous avez besoin pour commencer avec Edgegap.

***

### 2024.10.08

{% hint style="info" %}
Matchmaker Gen2 Nous peaufinons encore des bugs et ajoutons de nouvelles fonctionnalités à notre Matchmaker Gen2. Nous avons désormais un changelog dédié, que vous pouvez trouver \[ici]\(/docs/gen2-matchmaker-changelog).
{% endhint %}

**Nouveau ✨**

* Le tableau de bord définira par défaut la durée maximale d'un déploiement à 60 minutes lors de la création d'une nouvelle version d'application. Ce changement aidera à prévenir des coûts inattendus. Vous pouvez toujours ajuster la durée selon vos besoins.

**Corrigé ✔**

* Correction d'un problème avec les lobbies où ils ne démarraient pas correctement et renvoyaient un message d'erreur lors de la récupération du statut.
* Correction de la section temps moyen de déploiement sur la page d'accueil du tableau de bord qui affichait parfois un message d'erreur.

***

### 2024.09.25

{% hint style="info" %}
Matchmaker Gen2 Notre nouveau Matchmaker Gen2 est désormais en ligne et disponible pour tout le monde ! Vous pouvez y accéder directement via le tableau de bord au même endroit que le matchmaker précédent.

Cette dernière version offre une flexibilité et un contrôle accrus sur votre processus de matchmaking, tout en étant plus facile à utiliser. Vous pouvez commencer par créer des matchmakers sur notre cluster gratuit pour des tests précoces, puis passer sans heurt à votre propre cluster dédié pour des jeux en direct ou des tests ininterrompus.

Matchmaker Gen2 est actuellement en accès anticipé jusqu'à ce que nous supprimions complètement la version précédente, et nous sommes très heureux d'avoir tout le monde à bord ! Consultez notre [documentation](https://docs.edgegap.com/docs/release-notes/broken-reference) pour commencer, et n'hésitez pas à partager vos retours avec nous sur [Discord](https://discord.com/invite/NgCnkHbsGp).
{% endhint %}

**Nouveau ✨**

* Nous présentons une fonctionnalité « apportez votre propre DNS ». Cela vous permettra d'utiliser votre propre nom de domaine pour vos déploiements. Cette fonctionnalité est actuellement en accès anticipé, si vous souhaitez la tester, veuillez contacter notre équipe de support.
* À compter de cette version, nous supprimerons désormais les déploiements protégés après une période de 48h.

**Améliorations 💪**

* Notre plugin pour Unity a été mis à jour et est désormais disponible sur le [asset store](https://assetstore.unity.com/packages/tools/network/edgegap-game-server-hosting-212563).

**Corrigé ✔**

* Correction de certains problèmes de formatage des couleurs avec les logs de session sur le tableau de bord.

***

### 2024.09.09

{% hint style="info" %}
Nous avons lancé notre BÊTA fermée pour Matchmaker Gen 2 ! Cette nouvelle version est une refonte complète du matchmaker géré actuel, offrant une plus grande flexibilité et un meilleur contrôle sur votre processus de matchmaking.
{% endhint %}

{% hint style="success" %}
Gestion des ressources Pour améliorer la gestion des ressources et aider à prévenir des coûts inutiles de votre côté, nous fermerons désormais automatiquement les déploiements qui tournent depuis plus de 24 heures. Si vous avez besoin qu'un déploiement reste actif plus longtemps, faites-le nous savoir et nous serons ravis de vous aider.
{% endhint %}

**Nouveau ✨**

* Les sessions relais vides seront désormais automatiquement supprimées après 10 minutes. Ce changement aide à gérer les ressources plus efficacement et réduit la quantité de code nécessaire pour gérer vos sessions relais.

**Améliorations 💪**

* La page du registre de conteneurs sur le tableau de bord affiche désormais correctement les dépôts avec sous-dossiers.
* Les endpoints API de gestion du registre prennent désormais en charge les dépôts avec sous-dossiers.
* Lors de la création d'une nouvelle version d'application de type session, la fonction d'auto-déploiement sera désormais activée par défaut. Cela devrait réduire la confusion autour du processus de déploiement. Vous pouvez toujours désactiver l'auto-déploiement si votre flux de travail l'exige.
* Nous avons ajouté davantage d'emplacements à notre réseau pour offrir encore plus de couverture et de meilleures performances pour vos déploiements.

**Corrigé ✔**

* Correction d'un bug où certains emplacements n'étaient pas affichés correctement sur la page des détails du déploiement lorsqu'ils avaient été supprimés. Cela se produisait avec des anciens déploiements terminés.
* Correction d'un petit bug d'interface avec les champs de formulaire sur le tableau de bord.

**Documentation 📚**

* Ajout d'une boîte d'information sur l'utilisation de l' `en-tête X-Real-IP` dans la création de tickets lors de l'utilisation du matchmaker géré ([doc](https://docs.edgegap.com/docs/release-notes/broken-reference)).
* Corrigez l'exemple de sélecteur injecté dans la configuration du matchmaker géré ([doc](https://docs.edgegap.com/docs/release-notes/broken-reference)).

***

### 2024.08.13

**Nouveau ✨**

* Vous pouvez désormais supprimer votre session relais directement depuis la page de détails du relais sur le tableau de bord.
* Nous avons ajouté une fonctionnalité pour la **session relais** pour détecter automatiquement lorsque vos joueurs sont déconnectés et les supprimer de la session relais. Cette fonctionnalité vous aidera à gérer vos sessions plus efficacement. Nous ajouterons bientôt une fonctionnalité pour supprimer automatiquement les sessions vides.
* Les lobbies se fermeront désormais automatiquement après 3 heures pour les utilisateurs du niveau gratuit. Ce changement aidera à gérer les ressources plus efficacement et assurera des performances optimales pour tous les utilisateurs.

**Améliorations 💪**

* Le délai de vérification par défaut du port de déploiement a été augmenté à 30 secondes. Ce changement n'allongera pas votre processus de déploiement mais évitera des erreurs pour les clients ayant des temps de démarrage plus longs pour leurs conteneurs.
* Nous avons réactivé la connexion OAuth pour le tableau de bord. Ce changement vous permettra d'utiliser votre compte Google ou GitHub pour vous connecter au tableau de bord.

**Corrigé ✔**

* Correction d'un problème où l'utilisation d'une IP invalide cassait la page de détails du déploiement sur le tableau de bord.
* Correction d'un problème où l'onglet sessions à l'intérieur de la page des détails du déploiement n'était pas accessible.
* Correction d'un problème où les infobulles et les visites guidées sur le tableau de bord ne fonctionnaient pas correctement après le rafraîchissement de la page.
* Correction d'un problème provoquant des temps de chargement plus longs que prévu pour la page de connexion du tableau de bord.

**Documentation 📚**

* Documentation étendue pour la gestion des sessions avec les intégrations Fishnet netcode ([doc](https://docs.edgegap.com/docs/sample-projects/unity-netcodes/fishnet-on-edgegap)).
* Documentation étendue pour la gestion des sessions avec les intégrations Mirror netcode ([doc](https://docs.edgegap.com/docs/sample-projects/unity-netcodes/mirror-on-edgegap)).
* Ajout de plus d'avertissements et d'étapes de dépannage pour la configuration d'exemple du matchmaker géré.
* Ajout de plus d'informations sur la compatibilité du service Lobby avec nos services .
* Ajout de l'étape pour définir autodeploy à true lors de l'utilisation du matchmaker géré.

***

### 2024.07.24

**Nouveau ✨**

* Nous fournissons désormais à la fois l'IP et le FQDN de nos beacons lors de leur listing. Cela vous permettra de choisir entre les deux options lors du codage de votre intégration. Nous introduisons une limitation de débit permissive pour l'API. Ce changement vise à assurer une utilisation équitable et maintenir des performances optimales tout en offrant de la flexibilité pour la plupart des cas d'utilisation.

**Améliorations 💪**

* Nous avons ajusté le graphique d'utilisation de la mémoire sur le tableau de bord et l'API pour fournir des données plus précises lorsque la RAM subit des pics. Cela aidera à surveiller les problèmes potentiels et optimiser vos déploiements.
* Nous avons supprimé la création automatique de l'application de démonstration lors de l'utilisation du bouton d'initialisation sur nos plugins. Ce comportement causait de la confusion et des problèmes lorsqu'il était combiné avec les limites de notre niveau gratuit.
* Petites améliorations de cohérence sur l'interface du tableau de bord.
* Amélioration de la surveillance de nos emplacements pour assurer les meilleures performances pour vos déploiements.

**Documentation 📚**

* Ajout d'un exemple pour la gestion des sessions de sièges avec l'intégration Fishnet netcode ([doc](https://docs.edgegap.com/docs/sample-projects/unity-netcodes/fishnet-on-edgegap))

***

### 2024.07.11

**Améliorations 💪**

* Nous avons mis à jour notre application interne utilisée pour le ping des beacons. Cette mise à jour utilise un langage plus performant, garantissant une surcharge minimale d'application pour une mesure de latence la plus précise. L'utilisation reste la même et aucune modification n'est requise de votre côté.
* Nous avons mis à jour la page de tarification sur le tableau de bord pour la faire correspondre à la page de tarification de notre site web. Cette mise à jour inclut une ventilation plus détaillée des fonctionnalités disponibles dans chaque niveau.

**Corrigé ✔**

* Correction d'un problème où la création d'un token oneClick via le tableau de bord générait correctement le token mais ne l'affichait pas correctement dans la fenêtre de création.

**Documentation 📚**

* Ajout d'un exemple pour la gestion des sessions de sièges avec l'intégration Mirror netcode ([doc](https://docs.edgegap.com/docs/sample-projects/unity-netcodes/mirror-on-edgegap)).

***

### 2024.07.03

{% hint style="warning" %}
**Avis à tous les utilisateurs de Matchmaker :** Dans le cadre de nos efforts continus pour améliorer notre infrastructure, nous allons migrer les clusters du matchmaker vers un nouveau fournisseur. Ce changement est nécessaire pour garantir de meilleures performances et fiabilité pour vos services.

Pour faciliter cette transition, vous devrez relancer votre matchmaker. L'URL restera la même, donc aucune modification n'est requise à ce niveau. Veuillez noter qu'il y aura une brève interruption d'environ 5 minutes pendant ce processus.

Si vous souhaitez effectuer la migration en utilisant une stratégie A/B, vous pouvez simplement démarrer un nouveau matchmaker. Il sera sur le nouveau cluster avec une nouvelle URL. Une fois que vous aurez remplacé l'URL dans vos clients de jeu, supprimez l'ancien. Cette approche minimise toute perturbation potentielle et assure une transition fluide.

**Date limite : veuillez compléter cette transition d'ici le vendredi 12 juillet. Après cette date, nous relancerons tous les matchmakers encore actifs chez l'ancien fournisseur.**
{% endhint %}

**Nouveau ✨**

* Nous avons ajouté la pagination à la liste des artefacts sur la page du registre de conteneurs, facilitant la visualisation de toutes vos images.
* Nous avons ajouté des routes API pour obtenir et supprimer les tags d'image du registre de conteneurs, vous permettant de gérer vos tags directement depuis vos scripts, CI/CD ou applications.

**Corrigé ✔**

* Correction d'un comportement inattendu avec la pagination dans les tableaux du tableau de bord.

**Documentation 📚**

* Documentation PlayFab matchmaker bridge mise à jour pour l'intégration Edgegap. ([doc](https://github.com/edgegap/docs-gitbook/blob/main/docs/playfab-bridge/README.md)).
* Documentation pour la suppression des tags d'artefact via l'API ([doc ](https://github.com/edgegap/docs-gitbook/blob/main/docs/container/edgegap-container-registry/README.md#delete-build-artifacts-via-api), [API](https://github.com/edgegap/docs-gitbook/blob/main/api/README.md#tag/Container-Registry)).
* Ajout d'un avertissement d'erreur commun dans l'exemple d'intégration Fishnet ([doc](https://github.com/edgegap/docs-gitbook/blob/main/docs/sample-projects/fishnet-on-edgegap/README.md#configure-the-client-build)).
* Liens de documentation mis à jour pour les intégrations netcode avec nos relais ([doc](https://github.com/edgegap/docs-gitbook/blob/main/docs/distributed-relay-manager/README.md#getting-started)).

***

### 2024.06.27

{% hint style="info" %}
Un bref avis sur notre cycle de sortie actuel : Nous travaillons actuellement sur une mise à jour majeure de notre matchmaker, concentrant nos efforts sur l'amélioration des performances, de la flexibilité et de la fiabilité. Nous introduisons également de nouvelles fonctionnalités pour faciliter la création de règles personnalisées de matchmaker. Cela explique le rythme plus lent de sorties de fonctionnalités que vous avez pu remarquer.

Nous visons à publier cette mise à jour au trimestre prochain. Restez à l'écoute pour plus d'informations.
{% endhint %}

**Nouveau ✨**

* La facturation journalière est désormais disponible pour toutes les organisations. Vous pouvez désormais voir le coût de vos déploiements sur une base quotidienne. Cette fonctionnalité est disponible dans la section facturation de la page des paramètres.
* Les utilisateurs de relais sont désormais automatiquement retirés de la session lorsque le relais détecte qu'un joueur s'est déconnecté.

**Corrigé ✔**

* Bug où le fichier de téléchargement des logs de conteneurs n'était pas correctement généré sur la page de détails du déploiement.
* Bug où les utilisateurs du niveau gratuit ne pouvaient pas utiliser les sessions avec notre matchmaker.
* Bug lors de la suppression d'un utilisateur lorsqu'un lobby est démarré.

***

### 2024.05.06

**Nouveau ✨**

* Le propriétaire de l'organisation peut désormais activer l'authentification à deux facteurs (2FA) pour tous les membres de l'organisation. Une fois activée, tous les membres devront configurer la 2FA lors de leur prochaine connexion.
* Nous avons ajouté une option de suppression en masse pour les versions d'application sur le tableau de bord. Vous pouvez désormais sélectionner plusieurs versions et les supprimer simultanément.

**Améliorations 💪**

* La liste des dépôts sur la page du registre est désormais paginée.

**Corrigé ✔**

* Bug où l'unité d'egress n'était pas correctement affichée sur les graphiques des relais.
* Bug où l'option de mappage de port un-à-un n'était pas correctement affichée sur le formulaire de création de port.

***

### 2024.04.29

**Nouveau ✨**

* Une option est désormais disponible pour faire défiler automatiquement vers le bas des logs des conteneurs sur la page des détails du déploiement.

**Améliorations 💪**

* Auparavant, le `verify_image` l’option ne pouvait être appliquée qu’à la route API de création d’une version d’application. Désormais, vous pouvez également l’utiliser avec la route API de mise à jour d’une version d’application.

**Corrigé ✔**

* Correction d’un bug où l’application d’un filtre sur le tableau du tableau de bord supprimait le paramètre de pagination en cours.
* Correction d’un bug où il n’était pas possible de supprimer une image depuis la page du dépôt du tableau de bord lorsqu’il y a plusieurs images pour un même tag.

***

### 2024.04.03

**Nouveau ✨**

* Voyez le montant dû de votre prochain cycle de facturation directement sur le tableau de bord. Cette fonctionnalité est disponible pour les propriétaires d’organisation dans la section facturation de la page des paramètres.
* Vous pouvez désormais filtrer la liste des déploiements par tags directement sur le tableau de bord. La version API sera disponible prochainement.
* Vous pouvez désormais choisir distinctement entre l’affichage de vos joueurs actuels ou des emplacements Edgegap sur la carte de la page d’accueil. Nous travaillons actuellement pour la rendre disponible pour vos déploiements également.

**Améliorations 💪**

* Clarification améliorée des champs du formulaire du composant matchmaker pour une meilleure utilisabilité.
* Informations supplémentaires fournies sur les étapes suivantes après la création d’un token en un clic pour les plugins.
* Mise en œuvre de diverses petites améliorations de l’interface utilisateur sur le tableau de bord pour améliorer l’expérience des utilisateurs débutants.

**Corrigé ✔**

* Résolution de plusieurs problèmes mineurs de mise en page et de formulaires sur l’ensemble du tableau de bord.

***

### 2024.02.29

**Nouveau ✨**

* Les propriétaires d’organisations peuvent désormais ajouter des destinataires supplémentaires aux e-mails de facturation. Cette fonctionnalité est disponible sur la page des paramètres généraux.
* Vous pouvez désormais sélectionner une section d’atterrissage par défaut pour la page des détails du déploiement. Choisissez entre la carte, les détails, les logs du conteneur et les sections graphiques pour être la première affichée lors de l’ouverture de la page des détails du déploiement.

{% hint style="info" %}
L’option \`inject\_context\_env\` dans les versions d’application sera dépréciée puisqu’un contexte sera injecté par défaut dans tous les déploiements. Ces variables sont préfixées par \`ARBITRIUM\_\` et sont disponibles dans l’environnement du conteneur. Cela ne changera aucun comportement et **sera transparent** pour l’utilisateur.&#x20;
{% endhint %}

**Améliorations 💪**

* Mise à jour des messages autour des add-ons de relais sur la page d’abonnement par niveau pour mieux expliquer les différences clés entre eux et notre offre de serveurs autoritaires.
* Ajout d’un avertissement pour informer les utilisateurs que le tableau de bord est moins optimisé pour les appareils mobiles.
* Les identifiants du registre seront désormais préremplis lors de la création d’une nouvelle version d’application sur le tableau de bord si vous utilisez notre registre, rendant le processus plus rapide et moins sujet aux erreurs.

**Corrigé ✔**

* Correction d’un bug où plusieurs `one-click` tokens pouvaient être créés au lieu d’utiliser celui existant avec les plugins.
* Correction d’un bug dans les variables d’environnement du matchmaker où la validation des valeurs était trop stricte. La clé et la valeur sont désormais validées selon les standards POSIX.
* Correction d’un bug où la création d’une session avec trop d’utilisateurs pour le nombre de sockets disponibles via l’assistant du tableau de bord échouait sans message d’erreur approprié.
* Correction d’un bug où les couleurs des graphiques sur les détails du déploiement n’étaient pas celles attendues.

***

### 2024.02.19

#### Annonce spéciale ❗

{% hint style="info" %}
Les utilisateurs du niveau Gratuit ont désormais accès à 1 CPU pour leur déploiement, contre 0,5 CPU auparavant. Avec ce changement, nous introduisons également une durée maximale de déploiement de 1 heure pour les utilisateurs du niveau Gratuit.

Ces changements sont introduits pour s’assurer que les utilisateurs du niveau Gratuit peuvent tester rapidement des serveurs de jeu plus gourmands en ressources sur Edgegap et pour garantir que ces ressources sont utilisées plus efficacement sur notre infrastructure.

Nos plans en libre-service continuent d’offrir un temps de déploiement illimité. Pour plus de détails, explorez la capacité étendue et les fonctionnalités de chaque option sur notre page de tarification. [Voir les niveaux](https://app.edgegap.com/user-settings?tab=memberships)
{% endhint %}

**Nouveau ✨**

* Questions supplémentaires d’intégration pour nous aider à mieux comprendre vos besoins et fournir une expérience plus personnalisée.
* Le temps restant d’un déploiement sera affiché sur la page des détails du déploiement et sur la liste des déploiements lorsque cela s’applique.
* Bouton pour créer un déploiement depuis la page d’accueil.
* Terminer plusieurs sessions directement depuis la page de liste des sessions.

**Améliorations 💪**

* Ajout de plus d’orientations lorsque la validation du conteneur échoue lors de la création d’une version d’application.
* Ajout de plus d’orientations pour les identifiants de version d’application lors de la création d’une version d’application.
* Ajout de plus d’orientations pour créer un stockage des logs des conteneurs depuis la section logs des conteneurs du déploiement.
* Ajout d’explications supplémentaires dans la fenêtre modale de création de port de version d’application pour aider les utilisateurs à mieux comprendre le processus.

**Corrigé ✔**

* Comportement inattendu sur la page des détails du déploiement lors de l’utilisation du bouton de retour.

***

### 2024.02.01

**Nouveau ✨**

* Voir l’état actuel du cache de vos versions d’application sur leur page de détails.
* Terminer plusieurs déploiements directement depuis la page de liste des déploiements.

**Corrigé ✔**

* Bug où le graphique de la page des détails du déploiement, les logs et les logs des conteneurs ne se chargeaient pas correctement dans certains cas.
* Petits bugs et améliorations de l’interface utilisateur sur tout le tableau de bord.

***

### 2024.01.23

**Nouveau ✨**

* La fenêtre modale pour créer des politiques sur la page de gestion des flottes affiche désormais les emplacements disponibles pour déployer vos serveurs.
* Vous pouvez désormais dupliquer une version d’application existante depuis le tableau de bord, y compris les ports et les variables d’environnement.
* Vous verrez désormais en un coup d’œil sur la page d’accueil du tableau de bord si vous avez un déploiement en erreur.
* La page de création de version d’application affiche désormais vos images disponibles si vous utilisez l’Edgegap Container Registry.

**Améliorations 💪**

* Standardisation des couleurs pour une meilleure expérience en mode clair et sombre.
* Standardisation des modales, elles utiliseront désormais le même format sur tout le tableau de bord pour améliorer l’expérience utilisateur.
* Standardisation de l’e-mail de demande d’accès au registre pour être plus en ligne avec les autres e-mails envoyés par le tableau de bord.

**Corrigé ✔**

* Bug où vous ne pouviez pas mettre à jour le port d’une version d’application. Notez que vous ne pouvez toujours pas mettre à jour un port lorsqu’un ou plusieurs déploiements sont en cours d’exécution.
* Correction d’une faute de frappe dans la commande pull sur la page Edgegap Container Registry.

</details>

***

## 2023

<details>

<summary>Voir les notes de version 2023</summary>

### 2023.12.13

**Nouveau ✨**

* La facture inclura désormais un résumé de l’utilisation de l’egress et des vCPU (groupés par taille) pour le mois.
* Nous enverrons une notification à votre centre de notifications du tableau de bord lorsqu’il y aura un déploiement que nous ne pouvons pas mettre en cache en raison d’une mauvaise configuration.

**Améliorations 💪**

* Amélioration de la statistique « Temps moyen de déploiement » de la page d’accueil pour refléter les 24 dernières heures de déploiements au lieu des déploiements en direct actuels.
* Vous pouvez désormais mettre à jour les noms de votre application et de votre version directement depuis le tableau de bord.
* Ajustements mineurs de l’interface du tableau de bord pour la cohérence et la clarté.

**Corrigé ✔**

* Résolution d’un bug qui causait des problèmes de padding avec le graphique « Déploiement récent » lors du redimensionnement de la page d’accueil.

***

### 2023.12.05

**Nouveau ✨**

* Nous avons ajouté des extraits JSON lors de la création de plusieurs objets dans le tableau de bord pour vous aider à intégrer plus rapidement notre API.
* Un bouton pour supprimer votre déploiement dans la liste des déploiements pour vous aider à gérer vos déploiements plus rapidement.
* Ajout d’un bouton pour créer un déploiement depuis la liste des déploiements. Vous pourrez sélectionner une version d’application spécifique.

**Améliorations 💪**

* Ajout de plus d’emplacements pour déployer vos applications.
* Vous pouvez désormais cliquer sur le nom de votre version d’application pour accéder plus rapidement à la page de détails de la version d’application depuis la page des détails du déploiement.
* Ajout d’un nouvel appel à l’action sur de nombreuses pages affichant une liste d’objets. L’appel à l’action sera affiché lorsque la liste est vide.
* Les modales de déploiement et de session ont reçu quelques ajustements d’interface pour être plus cohérentes avec le reste du tableau de bord. Elles affichent également un bouton pour créer une nouvelle version d’application si vous n’en avez pas.

**Corrigé ✔**

* Correction d’un petit bug où le nom de l’organisation n’était pas affiché correctement dans la barre de navigation du tableau de bord.
* Correction d’un comportement de chargement étrange lors de la connexion au tableau de bord et de la création de compte.
* Correction d’un bug où parfois le tableau de bord affichait deux pages différentes en même temps.
* Correction d’un bug où certaines pages du tableau de bord pouvaient défiler alors qu’elles ne le devraient pas.

***

### 2023.11.29

**Nouveau ✨**

* Bouton pour supprimer vos artefacts du registre de conteneurs sur le nouveau tableau de bord.
* Créez un compte avec votre compte Google ou GitHub sur le nouveau tableau de bord.

**Améliorations 💪**

* Optimisation du caching pour empêcher notre système de désactiver automatiquement l’option de cache sur une configuration invalide de dépôt et d’image de version d’application.
* Aperçus sur le nouveau tableau de bord lorsque la validation de l’image du conteneur de votre version d’application échoue.

***

### 2023.11.14

**Nouveau ✨**

* Les demandes d’accès au registre de conteneurs sont désormais auto-approuvées après validation réussie.

**Améliorations 💪**

* Ajustements mineurs sur le nouveau tableau de bord.
* Diverses optimisations backend pour améliorer en continu l’expérience lors du déploiement de vos serveurs de jeu.

**Corrigé ✔**

* Bug empêchant l’édition du nom d’utilisateur du registre ou du token sur le tableau de bord.
* Bug provoquant la fin des sessions relais dans des emplacements non prévus ou leur échec sans raisons claires.
* Bug dans l’API où les noms de versions d’application pouvaient être vides.

***

### 2023.10.25

Nous revenons avec une autre version monumentale 🎉, et cette fois nous comblons les pièces manquantes pour vous offrir une expérience complète du tableau de bord. Votre patience et vos retours ont été inestimables, et nous sommes ravis de dévoiler les fonctionnalités nouvellement incorporées. Ces ajouts sont conçus pour vous donner plus de contrôle et de visibilité sur vos processus d’orchestration. Plongeons dans les nouveautés !

**Nouveau ✨**

* **Intégration Matchmaker :** Optimisez l’expérience des joueurs avec nos capacités de matchmaking améliorées désormais disponibles directement depuis le tableau de bord. Personnalisez les processus de matchmaking avec des jeux de règles configurables pour répondre aux besoins uniques de votre base de joueurs.
* **Gestion des sessions :** Surveillez et gérez vos sessions directement depuis le tableau de bord, vous fournissant des informations en temps réel sur les interactions des joueurs. Exploitez des options de filtrage robustes pour parcourir facilement les données de sessions, rendant la gestion des déploiements simple.
* **Fleets intelligentes :** Gérez vos flottes plus intelligemment avec les nouvelles intégrations d’interface, assurant une allocation optimale des ressources et des performances. Obtenez une vue claire de l’état et des performances de votre flotte avec des métriques en temps réel et des graphiques interactifs.

**Bientôt disponible 🕒**

* **Plugin OneClick :** D’un simple clic, déployez vos serveurs de jeu directement depuis les moteurs Unity et Unreal grâce à notre plugin OneClick. Cette intégration vise à simplifier le processus.
* **Authentification 2F & intégration SSO :** Renforcez votre posture de sécurité avec l’authentification à deux facteurs et les capacités Single Sign-On, bientôt disponibles sur le tableau de bord.
* **Et plus encore :** Restez à l’écoute pour d’autres mises à jour alors que nous nous efforçons continuellement d’affiner et d’étendre nos offres en fonction de vos retours.

Nous sommes dédiés à vous fournir un tableau de bord puissant et convivial, et ces mises à jour marquent une avancée significative vers cet objectif. Vos retours continus sont une pierre angulaire de notre processus de développement, et nous attendons avec impatience vos impressions sur ces nouvelles fonctionnalités.

Comme toujours, merci pour votre confiance et votre partenariat. Bon déploiement !

***

### 2023.09.26

Cette version introduit une nouvelle interface utilisateur pour notre Connector du Container Registry et ajoute la gestion des factures à vos paramètres utilisateur. Nous sommes également ravis de prévisualiser les fonctionnalités à venir : Smart Fleets et Sessions seront bientôt accessibles via l’interface.

**Nouveau ✨**

* **Connector du Container Registry :** Maintenant disponible dans le nouveau tableau de bord. Offre un dépôt de conteneurs géré en privé avec sécurité renforcée, scans de connexion, et plus encore.
* **Factures dans les paramètres utilisateur :** Les utilisateurs peuvent désormais gérer et visualiser leurs factures directement depuis leurs paramètres.

**Bientôt disponible 🕒**

* **Fleets intelligentes :** Gérez vos flottes de manière plus intelligente, bientôt disponible dans l’interface.
* **Sessions :** Surveillez et gérez vos sessions directement depuis l’interface, bientôt disponible.

***

### 2023.08.23

🎉 **Nous sommes ravis d’annoncer la sortie du tableau de bord complètement repensé !**

Cela fait un moment depuis nos dernières notes de version, et nous souhaitons prendre un moment pour expliquer pourquoi. Notre équipe a travaillé sans relâche sur cette refonte majeure, en se concentrant sur la livraison d’un ensemble de fonctionnalités et d’améliorations révolutionnaires. Cette période de développement prolongée nous a permis de garantir que chaque aspect du nouveau tableau de bord respecte nos normes élevées de qualité et d’innovation. Cela marque le début d’un nouveau voyage alors que nous peaufinons et ajoutons des fonctionnalités géniales. Nous avons investi cœur et esprit dans ce projet, et nous sommes impatients de partager le résultat qui élèvera sans aucun doute votre expérience de gestion d’orchestration.

**Améliorations majeures**

**Amélioration de la vitesse, du contrôle et de la visibilité 🚀**

* **Expérience ultra-rapide :** Le nouveau tableau de bord a été complètement restructuré avec un framework de pointe, vous offrant une expérience utilisateur extrêmement rapide. Cette amélioration fondamentale réduit considérablement les temps de chargement, vous aidant à gérer vos Déploiements et Applications avec une efficacité sans précédent.
* **Options avancées de tri et de filtrage :** Profitez d’un meilleur contrôle et d’une plus grande flexibilité avec nos options avancées de tri et de filtrage pour vos Déploiements et Applications. Cette fonctionnalité optimisée vous permettra de trouver précisément ce dont vous avez besoin, libérant plus de temps pour vous concentrer sur l’amélioration de vos applications.
* **Métriques et graphiques en temps réel :** La console intègre désormais des métriques en temps réel et des graphiques interactifs, offrant une vue claire de l’état et des performances de vos Déploiements et Applications. Ces outils puissants vous aideront dans vos décisions et votre développement.
* **Historique des déploiements :** Nous introduisons la possibilité de trier et filtrer les déploiements passés, vous offrant un moyen simplifié de naviguer dans votre historique de déploiements. Cette fonctionnalité vous permettra de trouver rapidement et efficacement les informations dont vous avez besoin.

**Relais P2P distribués 🗼**

Nous introduisons les Relais Distribués, un réseau de relais pair-à-pair distribué innovant. Cette fonctionnalité passionnante rehausse la performance des applications et la fiabilité du réseau. Bien que le système de relais lui-même fonctionnera indépendamment de la console via l’API, les métriques et graphiques associés seront exclusifs à la nouvelle Console.

**Stockage Endpoint 🗃️**

Les logs de vos conteneurs sont désormais stockés en toute sécurité dans des buckets S3 distants, garantissant que les logs précédemment supprimés sont maintenant sauvegardés. Cette solution robuste et évolutive améliore la gestion et l’accessibilité des logs.

**Refonte de l’organisation et de la facturation 💼**

La gestion de vos organisations et de la facturation n’a jamais été aussi simple. Pour les utilisateurs ayant effectué une mise à niveau dans l’ancien tableau de bord, sachez que vous êtes rattachés à ce niveau d’adhésion. Cependant, passer au nouveau système de facturation pourrait potentiellement réduire vos coûts, offrant une opportunité d’économies. Contactez notre équipe de support pour transférer des applications entre organisations, et profitez d’une expérience de facturation plus transparente et conviviale.

**Bientôt disponible**

**Nouvelles fonctionnalités et améliorations 🎮**

* **Matchmaker**: Capacités de matchmaking améliorées pour des expériences de joueurs optimales.
* **Container Registry**: Un dépôt de conteneurs géré en privé qui fonctionne de manière similaire aux registres publics standards, mais avec l’avantage supplémentaire d’une sécurité accrue, de scans de vulnérabilités, et d’autres fonctionnalités !
* **Flottes intelligentes**: Auparavant disponible uniquement via l’API, désormais accessible via l’interface.
* **Sessions**: Auparavant disponible uniquement via l’API, désormais accessible via l’interface.
* **Authentification 2F & SSO**: Sécurité renforcée avec l’authentification à deux facteurs et le single sign-on.

Nous travaillons continuellement sur de nouvelles fonctionnalités et améliorations pour vous offrir la meilleure expérience possible. Restez à l’écoute pour davantage de mises à jour et d’annonces passionnantes dans un avenir proche !

Vos retours sont essentiels à notre développement continu, et nous vous encourageons à partager vos pensées et suggestions avec nous. 💡

Merci pour votre soutien continu et votre partenariat. Bon déploiement ! 🙏

L’équipe Edgegap

***

### 2023.05.16

**Nouveau ✨**

* Vous pouvez désormais ajouter et supprimer des tags à votre déploiement via l’API. De plus, vous avez la possibilité d’ajouter des tags depuis le conteneur de votre déploiement. Il était auparavant seulement possible d’ajouter des tags depuis le tableau de bord et au début de la requête de déploiement. Pour en savoir plus sur cette nouvelle fonctionnalité, veuillez consulter [cette documentation](https://github.com/edgegap/docs-gitbook/blob/main/docs/deployment/tags/README.md).
* Vous avez désormais accès à des options de filtrage plus robustes pour les sessions et les sessions relais, qui fonctionnent de manière similaire au filtre des déploiements.

**Améliorations 💪**

* Ajout de nouveaux emplacements pour déployer vos applications.

**Corrigé ✔**

* Une correction a été apportée pour résoudre une incohérence dans les emplacements. Certains emplacements étaient incorrectement identifiés comme « United States » au lieu de la désignation correcte « United States of America ».

***

### 2023.04.18

**Nouveau ✨**

* Un outil de feedback est disponible sur presque toutes les pages de la documentation. Vous pouvez désormais nous dire si les informations que vous venez de lire étaient utiles ou non.
* Nous sommes ravis d’annoncer une nouvelle façon de déployer en périphérie avec les relais distribués d’Edgegap. Avec cette mise à jour, vous pouvez désormais déployer des sessions relais sur plusieurs emplacements de notre infrastructure, vous offrant tous les avantages de la solution Edgegap, y compris une faible latence, une évolutivité et une intégration facile. Pour en savoir plus sur cette nouvelle fonctionnalité, veuillez consulter [cette documentation](https://github.com/edgegap/docs-gitbook/blob/main/docs/distributed-relay-manager/README.md).

**Améliorations 💪**

* Les déploiements et sessions en statut d’erreur seront automatiquement supprimés après une certaine période. Actuellement, cela est fixé à 24 heures. Les déploiements ou sessions en erreur n’ont pas de jeux ou d’applications actifs, donc les utilisateurs ne seront pas déconnectés de serveur.

***

### 2023.03.07

**Améliorations 💪**

* Nous avons augmenté la période de grâce maximale de terminaison de 180 secondes à 3600 secondes, permettant plus de temps pour que les processus post-suppression se terminent. Veuillez noter que cette période prolongée sera facturée, même si le déploiement est en cours de terminaison, car les ressources de calcul sont toujours utilisées pendant ce temps.

**Corrigé ✔**

* Bug où le bouton « Contactez-nous » sur la page de connexion ne fonctionnait pas correctement, redirigeant les utilisateurs vers la page de connexion.
* Bug où, lors de la spécification du stockage des logs des conteneurs pendant la création d’une version d’application via l’API, le stockage était associé mais pas activé par défaut. En conséquence, les utilisateurs devaient l’activer manuellement via le formulaire du tableau de bord.

***

### 2023.01.17

**Nouveau ✨**

* La documentation a été restructurée. Nous visons à faciliter l’intégration et la recherche des composants centraux de la solution Edgegap.

**Corrigé ✔**

* Bug sur la page Container Registry du tableau de bord où vous ne pouviez pas voir vos images si vous aviez précédemment poussé le même tag deux fois.
* Le `kind` dans le `session_config` clé du corps de la réponse de création d’une version d’application via l’API sera désormais `Seat` au lieu de `seat` pour être cohérent avec le paramètre nécessaire à la création.

</details>

***

## 2022

<details>

<summary>Voir les notes de version 2022</summary>

### 2022.12.06

**Nouveau ✨**

* Les administrateurs d’organisation ont désormais accès au coût approximatif du mois sur la page de facturation.

**Améliorations 💪**

* La documentation de l’API a été mise à jour avec des titres pertinents pour toutes les routes.
* Ajout de plus d’emplacements pour déployer vos applications.
* Notre documentation pour le plugin Unity a été mise à jour selon la dernière version.

**Corrigé ✔**

* Bug où la page des détails du déploiement renvoyait parfois un 500.

***

### 2022.11.21

**Nouveau ✨**

* Vous pouvez désormais remplacer votre Dockerfile *ENTRYPOINT* et *CMD* en ajoutant des commandes et des arguments dans votre version d’application ou déploiement. [lien](https://github.com/edgegap/docs-gitbook/blob/main/docs/application/command-override/README.md)
* Ajout de plus de variables d’environnement avec vos informations de port. Il est désormais plus facile de récupérer les données sans analyser une chaîne JSON. [lien](https://github.com/edgegap/docs-gitbook/blob/main/docs/deployment/injected-variables/README.md)

**Améliorations 💪**

* Ajout de plus d’emplacements pour déployer vos applications.

**Corrigé ✔**

* Bug où les ports n’étaient pas affichés correctement sur la page « Enregistrer comme nouveau » de la version d’application.

***

### 2022.11.08

**Nouveau ✨**

* Les notifications sur le tableau de bord sont désormais disponibles pour donner aux utilisateurs des retours et une visibilité sur l’état du système. Les notifications seront ajoutées progressivement au cours des mois suivants.

**Améliorations 💪**

* Amélioration de l’apparence de la page d’accueil de la documentation.
* Les images du tableau de bord ont été mises à jour dans la documentation.
* Ajout de plus d’emplacements pour déployer vos applications.

***

### 2022.10.24

**Nouveau ✨**

* Nouveaux balises d’emplacements qui peuvent être utilisées pour pinguer des emplacements au sein de notre réseau afin d’améliorer votre matchmaking et vos stratégies de déploiement. [lien](https://github.com/edgegap/docs-gitbook/blob/main/docs/deployment/locations/beacons/README.md)
* La suppression en masse est désormais disponible depuis le tableau de bord.
* Le mappage de port 1:1 est désormais disponible pour les serveurs de jeu legacy ou les jeux qui ne prennent pas en charge le NAT punching. [lien](https://github.com/edgegap/docs-gitbook/blob/main/docs/application/one-to-one-port-mapping/README.md)
* Le mappage de ports et l’IP de votre déploiement sont désormais accessibles en tant que variables d’environnement depuis votre conteneur déployé.
* Ajout de plusieurs exemples de netcode populaires et de documentation pour faciliter l’intégration.

**Corrigé ✔**

* Une rare occurrence d’erreur lors de l’accès aux pages de version d’application sur le tableau de bord.

***

### 2022.10.11

**Nouveau ✨**

* La liaison du stockage endpoint à une version d’application pour stocker vos logs sera désormais disponible via l’API.
* Tous les administrateurs d’une organisation pourront désormais voir ses factures.

**Améliorations 💪**

* Ajout de plus d’emplacements pour déployer vos applications.

**Corrigé ✔**

* Correction de l’interface du tableau de bord sur la page de gestion des e-mails.

***

### 2022.09.27

**Nouveau ✨**

* La facture de facturation contiendra désormais uniquement un résumé de votre utilisation des ressources. Vous pouvez toujours consulter une facture détaillée depuis le tableau de bord Edgegap.

**Améliorations 💪**

* Mises à jour de l’interface du tableau de bord pour améliorer l’expérience des nouveaux utilisateurs et la création d’applications.
* Ajout de plus d’emplacements pour déployer vos applications.

**Corrigé ✔**

* Corrections de bugs mineurs et améliorations.

***

### 2022.08.30

**Nouveau ✨**

* Route API pour obtenir des informations de géolocalisation sur une IP ou une liste d’IPs. lien
* La période de grâce de terminaison est désormais personnalisable dans les paramètres d’une version d’application. L’augmenter vous permet de terminer votre application en douceur avant que le conteneur ne soit complètement arrêté.
* Guide des bonnes pratiques CICD pour aider à intégrer Edgegap dans vos pipelines de développement. [lien](https://github.com/edgegap/docs-gitbook/blob/main/docs/tools-and-integrations/cicd-integration/README.md)

**Améliorations 💪**

* Ajout de boutons d’analyse d’informations dans la section Container Registry pour une manipulation plus facile des commandes du registre.

**Corrigé ✔**

* Bug où le Container Registry renvoyait un message d’erreur non pertinent sur le tableau de bord lorsque la limite de nombre d’applications du niveau était atteinte.

***

### 2022.08.16

**Nouveau ✨**

* Suppression en masse pour les déploiements et les sessions.

**Améliorations 💪**

* Plus d’emplacements ajoutés dans différentes parties du monde.
* Le déploiement créé par le gestionnaire de flotte sera automatiquement tagué avec le nom de la flotte et de la politique.

**Corrigé ✔**

* Bug où la politique de flotte avec des coordonnées sans décimales ne fonctionnait pas.

***

### 2022.08.02

**Nouveau ✨**

* Ajout d’une configuration par défaut lors de la création d’une nouvelle flotte dans le Fleet Manager.
* Le stockage de déploiement est désormais disponible pour les petits fichiers (limite de 5 Mo).

**Améliorations 💪**

* Ajustements UI du tableau de bord pour la cohérence.

**Corrigé ✔**

* Bug où les ports de la version d’application ne s’affichaient pas sur la page de la version d’application.

***

### 2022.07.19

**Nouveau ✨**

* Gestionnaire de flotte : le Deployment Scaler a été supprimé et remplacé par le Fleet Manager. Vous pouvez désormais créer vos flottes, politiques et filtres qui mettront automatiquement à l’échelle vos Sessions sur des sites spécifiques selon votre configuration. [Documentation](https://github.com/edgegap/docs-gitbook/blob/main/docs/deployment/session/fleet-manager/fleet/README.md)
* Vous pouvez désormais consulter le temps de fonctionnement des services d’Edgegap ici : <https://status.edgegap.com/>

**Améliorations 💪**

* Petit changement UI du tableau de bord pour la cohérence.

**Corrigé ✔**

* Validation de l’image du conteneur lors de la mise à jour d’une version d’application.
* Le FQDN du déploiement n’inclura plus le nom de l’application. Cela posait parfois des problèmes dans le processus de création du FQDN. Désormais, il n’aura que l’ID de requête du déploiement.

***

### 2022.06.21

**Nouveau ✨**

* Les logs de la plateforme ont été retravaillés pour être plus pertinents pour les utilisateurs.

**Corrigé ✔**

* Bug avec la vérification de l’image de la version d’application ne fonctionnant pas avec certains fournisseurs de dépôt.
* Bug où l’utilisation des paramètres de corps « filters » avec des déploiements sans IP renvoyait une mauvaise requête.

***

### 2022.06.07

**Nouveau ✨**

* Route API pour obtenir votre IP publique

**Corrigé ✔**

* Bug où les erreurs des versions d’application n’étaient pas nettoyées correctement lors d’une mise à jour, ce qui faisait que notre système de cache désactivait inutilement le cache pour ces versions.
* Bug où une erreur était renvoyée lors de la requête des métriques de déploiement via l’API trop tôt dans le cycle de vie du déploiement.
* Bug lors de la création d’une application où l’API demandait des paramètres optionnels lors de l’utilisation de l’option "verify\_image".
* Bug avec le registre de conteneurs créant des versions d’application dupliquées lors du push du même tag plusieurs fois.

***

### 2022.05.24

**Nouveau ✨**

* Il est désormais possible d’utiliser un webhook pour le déploiement de Sessions lorsqu’elles sont dans un état « ready ».
* Vous pouvez désormais déployer sur un emplacement spécifique en utilisant un filtre pour un tag d’emplacement.
* Ajout d’un formulaire de contact pour que vous puissiez joindre notre équipe directement depuis le tableau de bord.

**Améliorations 💪**

* Modifications mineures de l’API pour correspondre correctement à la documentation.

**Corrigé ✔**

* Bug d’API lors de la mise à jour d’une version d’application où des paramètres optionnels déclenchaient une erreur de validation.
* Bug où la route pour ajouter des joueurs à une session ne validait pas la capacité de la session.
* Bug qui entraînait la mise en erreur de la session lorsque le démarrage d’une application expirait.

***

### 2022.05.10

**Nouveau ✨**

* La chronologie du déploiement est désormais disponible depuis l’onglet « Platform Info » sur la page des détails du déploiement. Ce guide visuel facilitera la compréhension et l’amélioration de chaque étape d’un déploiement.

**Améliorations 💪**

* Un message d’avertissement sera désormais affiché sur la page du déploiement lorsqu’un déploiement utilise une IP réservée (par ex. 0.0.0.0). Étant donné que la géolocalisation ne peut pas être déterminée dans ce cas, l’emplacement par défaut de ce joueur sera lat/long 0.0.
* Amélioration de la gestion du cycle de vie des emplacements Edge.

***

### 2022.05.03

**Nouveau ✨**

* Edgegap Container Registry : Poussez et mettez à jour vos images de conteneurs directement vers l’Edgegap Container Registry entièrement intégré pour une expérience simple de gestion des versions ([lien](https://github.com/edgegap/docs-gitbook/blob/main/docs/container/edgegap-container-registry/README.md)).
* Vous pouvez désormais exclure région, ville, pays, etc. de votre requête de déploiement.
* Vous pouvez désormais valider l’image du conteneur pour une version d’application afin de vous assurer que nous pouvons la tirer depuis le registre sélectionné. Disponible via l’API et le tableau de bord.
* Vous pouvez désormais télécharger un fichier TOML préconfiguré pour notre CLI directement sur la page de détail de la version d’application.

**Améliorations 💪**

* Mise en accord des couleurs de l’interface du tableau de bord avec notre nouveau site web.
* Nouveau style pour les pages de connexion et d’inscription.
* L’arborescence de la documentation a été repensée pour faciliter le flux d’intégration.

**Corrigé ✔**

* Cas rares d’un statut 500 sur la page des déploiements.
* Bug où les nouveaux utilisateurs n’ayant pas vérifié leur e-mail obtenaient un statut 500 en essayant de se connecter.

***

### 2022.02.29

**Nouveau ✨**

* Vous pouvez désormais accéder aux logs des conteneurs des déploiements passés depuis l’historique des déploiements dans le tableau de bord si vous avez configuré un bucket Endpoint Storage S3 pour votre compte.
* Vous pouvez désormais demander la télémétrie pour une liste d’IPs sur des déploiements existants. (Documentation à venir)

**Améliorations 💪**

* Vérification de readiness avec des ports TLS activés.

**Corrigé ✔**

* Création de requête de session avec l’assistant du tableau de bord.

***

### 2022.02.14

**Nouveau ✨**

* Page pour suppression en masse des versions d’application.
* Barre de recherche dans la liste des applications.
* Bouton « Enregistrer comme nouveau » pour la version d’application.
* Documentation sur la façon de passer de Gamelift à Edgegap.
* Documentation sur la façon de créer un conteneur pour un projet Unreal Engine.

**Améliorations 💪**

* Suppression des logs trompeurs lors de l’utilisation de l’option de mise à niveau TLS sur les ports.
* Réponse plus compréhensible de l’API lors de l’envoi d’une mauvaise requête JSON.
* 23 emplacements instantanés supplémentaires disponibles pour les déploiements.

**Corrigé ✔**

* Le Matchmaker géré sans filtres plante parfois.

***

### 2022.02.01

**Nouveau ✨**

* CLI pour vous aider à gérer vos versions d’application et simplifier l’intégration avec votre pipeline CICD.
* Package Edgegap Unity pour vous aider à déployer et tester plus rapidement directement depuis Unity Engine.

**Améliorations 💪**

* Plus de flex locations sont désormais disponibles.

**Corrigé ✔**

* Formulaire de mise à jour du Matchmaker manquant le champ de nom

***

### 2022.01.18

**Améliorations 💪**

* Validation du nom du dépôt d’images avec une regex assurant une valeur valide.

**Corrigé ✔**

* Diverses corrections mineures.

***

### 2022.01.06

**Nouveau ✨**

* Matchmaker expérimental sans code.
* Les logs de crash sont désormais disponibles dans Arbitrium OpenMatch.
* Enregistrez vos logs de crash directement dans votre bucket S3.

**Améliorations 💪**

* Page d’enregistrement du tableau de bord plus détaillée.
* Application de démonstration mise à jour avec plus d’informations sur votre déploiement.
* Meilleure présentation des factures.

**Corrigé ✔**

* Correction d’un bug où le processus d’appariement de session ne choisissait pas le meilleur déploiement disponible.
* Les logs de la plateforme et des conteneurs affichés dans le tableau de bord n’affichaient parfois rien et/ou présentaient des comportements étranges.
* Télécharger les logs de pod dans Arbitrium OpenMatch.

</details>

***

## 2021

<details>

<summary>Voir les notes de version 2021</summary>

### 2021.12.08

**Nouveau ✨**

* Sélecteurs de sessions pour une meilleure gestion entre session et déploiement ([lien](https://github.com/edgegap/docs-gitbook/blob/main/docs/deployment/session/selectors/README.md)).

**Améliorations 💪**

* L’enregistrement de la plateforme est désormais protégé par reCAPTCHA.
* Ajout de plus de Flex Locations.

**Corrigé ✔**

* Problème de logging spammant une erreur pendant la mise en cache d’une application.

***

### 2021.11.23

**Nouveau ✨**

* Le système désactivera automatiquement le cache sur les versions d’app inutilisées ([lien](https://github.com/edgegap/docs-gitbook/blob/main/docs/application/version/README.md#optional-fields)).
* Goodies gratuits disponibles une fois inscrit sur la plateforme.
* Nettoyeur automatique de sessions. Plus besoin de supprimer manuellement les sessions non liées ([lien](https://github.com/edgegap/docs-gitbook/blob/main/docs/deployment/session/more-in-depth/README.md#empty-time-to-live)).

**Améliorations 💪**

* La gestion des niveaux a été simplifiée avec plus d’informations lorsque vous devez rétrograder ou monter en gamme.
* Vous pouvez désormais choisir de vous connecter automatiquement dans votre organisation au lieu de devoir changer à chaque connexion.
* Lors du changement en vue organisation, vous resterez sur la page sur laquelle vous étiez.
* Les propriétaires d’organisation peuvent désormais définir des admins qui peuvent inviter des personnes dans votre organisation.
* Les logs de déploiement indiqueront désormais si vous devez augmenter votre temps minimal de déploiement ou activer le caching en cas de déploiement en erreur.

**Corrigé ✔**

* Bug où vous ne pouviez pas éditer des env contenant "\n" pour les versions d’app et les matchmakers.
* Bug où l’outil d’extrait JSON dans la page de création d’app ne s’affichait pas. Amélioration de son contenu pour refléter les validations de l’API.
* Correction de certaines informations de localisation.

***

### 2021.11.02

**Nouveau ✨**

* Vous pouvez désormais tester un déploiement d’application plus rapidement avec notre création d’application en un clic.
* Accédez aux logs d’un conteneur planté directement depuis la page de déploiement.
* Mettez à niveau les connexions HTTP et Websocket vers HTTPS et WSS en un clic.

**Améliorations 💪**

* Les ports d’application prennent désormais en charge la nomination pour une récupération plus facile.
* Formulaire de création d’application simplifié pour une compréhension plus facile. Les paramètres avancés restent disponibles.
* Nous avons désormais un tutoriel C# pour l’intégration OpenMatch.
* Plus d’emplacements sont disponibles avec des paramètres avancés.

**Corrigé ✔**

* Comportement de caching inhabituel.

***

### 2021.10.05

**Nouveau ✨**

* Libre-service : vous pouvez désormais vous inscrire facilement et lancer quelques déploiements. Cependant, nous serons toujours là pour vous aider.
* La barre latérale affiche toutes les nouvelles piles technologiques prises en charge @ Edgegap.
* Intégration avec un processeur de paiement, vous aurez l’option de payer vos factures Edgegap dans Arbitrium directement.
* Nous intégrons le support Intercom directement sur votre tableau de bord.
* Edgegap Wallet.

**Améliorations 💪**

* Nous avons ajouté de nouveaux sites edge avec plus de fonctionnalités.
* D’un seul clic, vous pouvez voir le montant de crédit restant dans votre portefeuille Edgegap.

**Corrigé ✔**

* Ajout d’un timeout plus long dans ASD.
* Modifications cosmétiques mineures.

***

### 2021.08.18

**Nouveau ✨**

* Envoyez vos logs vers S3
  * Nous avons ajouté une nouvelle fonctionnalité qui vous permet de stocker automatiquement vos logs de conteneurs dans un stockage de type S3. Vous pouvez suivre notre documentation pour l’activer sur vos applications. [lien](https://github.com/edgegap/docs-gitbook/blob/main/docs/deployment/endpoint-storage/save-container-logs/README.md).

**Améliorations 💪**

* Arbitrium Open Match
  * Découvrez notre nouvelle fonctionnalité dans l’UI Matchmaker qui vous aide maintenant à dépanner votre déploiement avec les logs de conteneurs.
* Déploiement basé sur la session
  * Nous avons ajouté plus de façons de faire des déploiements basés sur les sessions pour faciliter votre travail.
  * Le bouton « Créer un déploiement » permet d’envoyer une instance de Session pour une application basée sur les sessions

**Corrigé ✔**

* Diverses corrections de bugs mineurs et améliorations dans le processus de prise de décision.
* Diverses mises à jour et durcissements ont été effectués sur l’infrastructure de calcul en périphérie.
* La fonctionnalité Arbitrium Webhook renverra si le déploiement est en erreur lors des premières étapes du processus.

***

### 2021.06.18

**Nouveau ✨**

* Arbitrium Open Match
  * Vous pouvez désormais créer votre Matchmaker directement dans le tableau de bord Arbitrium. Vous pouvez consulter la documentation sous Arbitrium Open Match.
* Générateur SDK dans le tableau de bord
  * Intégration accrue entre votre serveur de jeu et Arbitrium, vous pouvez désormais générer le SDK depuis notre tableau de bord.
* La protection de votre déploiement est automatiquement effectuée.
  * Si activé dans la configuration de votre application, Arbitrium protégera votre déploiement. Il ne sera ATTEINT QUE depuis les IP que vous avez autorisées.
* Support des organisations dans le tableau de bord.
  * Nous avons le support des Organisations intégré à votre tableau de bord. Invitez votre collègue dans l’organisation, puis naviguez pour profiter du même compte.
* Contexte du déploiement dans le conteneur
  * Nous avons ajouté plus d’informations dans votre conteneur. Lorsque vous avez besoin de scripts dans votre conteneur pour afficher des informations sur l’emplacement, consultez la documentation pour obtenir plus d’informations sur cette fonctionnalité.
* Déploiement basé sur la session
  * Nous supportons des parties auxquelles les joueurs entrent et sortent à tout moment. Nous ajouterons les joueurs dans la session qui est dans le meilleur emplacement pour vos joueurs.
  * L’outil horizontal Deployment Session garantira que vous ayez toujours des sessions prêtes à accueillir de nouveaux joueurs.

**Améliorations 💪**

* Nouvelles étapes lors de la terminaison d’un déploiement
  * Nous avons une nouvelle étape lors de l’arrêt d’un déploiement, Ready -> Terminating -> Terminated.
* SSO dans Arbitrium
  * Nous supportons l’utilisation d’Okta comme Single Sign-On sur tous les outils Edgegap.
* Tags du tableau de bord
  * Vous pouvez voir tous les tags assignés à votre déploiement d’application dans votre liste de déploiements.

**Corrigé ✔**

* Lors du démarrage de nouveaux processus dans votre conteneur, l’affichage de vos métriques CPU/RAM n’était pas rendu correctement dans le tableau de bord.
* Lorsqu’un seul point d’accès est disponible, une chaîne IP vide, le déploiement n’était pas traité correctement.

***

### 2021.04.30

**Nouveau ✨**

* Nous prenons en charge la gestion des niveaux par les clients.
* Nouvelle page d’atterrissage géniale avec des statistiques essentielles pour le studio sur vos déploiements.
* Sécurité du processus de connexion au tableau de bord.

**Améliorations 💪**

* Vous pouvez désactiver la validation des ports depuis la page de la version d’application.
* Ajoutez la flexibilité pour permettre plus de temps pour déployer l’application avant sa mise en cache sur les points d’accès.
* Le caching se fait désormais de manière passive au niveau Edge.

**Corrigé ✔**

* Correction d’incohérences dans les résultats de ping
* Correction de fautes de frappe dans la documentation.

***

### 2021.04.15

**Nouveau ✨**

* Support désormais d’AWS Local Zone

**Améliorations 💪**

* Améliorations apportées aux logs de console, ils reflètent désormais davantage ce à quoi une console devrait ressembler

**Corrigé ✔**

* Correction de petites fuites de mémoire
* Correction d’un petit bug de monitoring
* Correction d’une erreur gérée s’affichant comme erreur dans les logs

***

### 2021.03.09

**Nouveau ✨**

* Ajout de l’option de déployer sur un emplacement spécifique sans prendre en compte les données de télémétrie.
* Ajout d’une option « verrouiller le déploiement » si vous avez besoin qu’un déploiement reste actif. Tant qu’un déploiement est verrouillé, il ne peut être tué par aucune requête.
* Ajout d’un accès à plus d’informations dans notre dépôt BigData directement depuis le tableau de bord.
* Ajout du support pour renvoyer des informations à votre matchmaker via un webhook.
* Ajout de la possibilité de créer des tags sur vos déploiements pour les identifier plus facilement.

**Améliorations 💪**

* Améliorations apportées à la détection DDOS pour les serveurs de jeu.
* Améliorations sur la façon dont nous gérons le trafic entrant sur notre plateforme Arbitrium pour la rendre plus rapide et plus sécurisée.
* Amélioration de la documentation.

**Corrigé ✔**

* Correction de bugs mineurs pour la stabilité du backend.

</details>


# Projets exemples

Explorez nos projets d'exemple et construisez sur une base multijoueur solide :

<table data-view="cards"><thead><tr><th></th></tr></thead><tbody><tr><td><a href="sample-projects/unreal-engine/exemple-lyra">Lyra Sample<br>(Unreal Engine)</a></td></tr><tr><td><a href="sample-projects/unreal-engine/top-down-sample">Top-Down Sample<br>(Unreal Engine)</a></td></tr></tbody></table>

***

<table data-view="cards"><thead><tr><th></th></tr></thead><tbody><tr><td><a href="sample-projects/unity-netcodes/photon-fusion-2-on-edgegap">Asteroids Sample<br>(Unity + Photon Fusion 2)</a></td></tr><tr><td><a href="sample-projects/unity-netcodes/photon-fusion-on-edgegap">Tanknarok Sample<br>(Unity + Photon Fusion 1)</a></td></tr><tr><td><a href="sample-projects/unity-netcodes/unity-netcode-on-edgegap">2D Space Shooter<br>(Unity + NGO)</a></td></tr><tr><td><a href="sample-projects/unity-netcodes/mirror-pong">Pong Sample<br>(Unity + Mirror)</a></td></tr><tr><td><a href="sample-projects/unity-netcodes/fishnet-on-edgegap">Space Edge Sample<br>(Unity + FishNet)</a></td></tr><tr><td><a href="sample-projects/unity-netcodes/photon-bolt-on-arbitrium">Demo Sample<br>(Unity + Photon Bolt)</a></td></tr><tr><td><a href="sample-projects/unity-netcodes/mirror-on-edgegap-websocket">Tanks WebGL Sample<br>(Unity + Mirror)</a></td></tr><tr><td><a href="sample-projects/unity-netcodes/fishnet-on-edgegap-webgl">Space Edge WebGL Sample<br>(Unity + FishNet)</a></td></tr></tbody></table>

***

<table data-view="cards"><thead><tr><th></th></tr></thead><tbody><tr><td><a href="sample-projects/nuxt-on-edgegap">Single Page App Sample<br>(NuxtJS)</a></td></tr><tr><td><a href="sample-projects/ruby-on-rails">MVC Web App Sample<br>(Ruby on Rails)</a></td></tr></tbody></table>


# Unreal Engine


# Exemple Lyra

Découvrez comment héberger des projets Unreal Engine sur Edgegap en utilisant des techniques du [Lyra Sample](https://dev.epicgames.com/documentation/en-us/unreal-engine/lyra-sample-game-in-unreal-engine).

## ✔️ Préparation

Avant de commencer, vous aurez besoin de :

* Unreal Engine 5.5 - [télécharger via Epic Games Launcher](https://www.unrealengine.com/en-US/download),
* Lyra Starter Game - [télécharger depuis Fab](https://www.fab.com/listings/93faede1-4434-47c0-85f1-bf27c0820ad0).

Ouvrez votre lanceur Epic Games et allez dans Unreal Engine / Bibliothèque / Fab Library.

Recherchez « lyra », puis Créer un projet. Nous recommandons d'utiliser un SSD pour des compilations plus rapides.

## ⚡ Déployer et se connecter

### 1. Déployer un serveur sur Edgegap

☑️ Pour commencer, vous devrez [créer un compte gratuit chez Edgegap](https://app.edgegap.com/auth/register). Aucune carte de crédit requise.

☑️ [Créez une nouvelle version d'application pour votre application](https://app.edgegap.com/application-management/applications/lyra-sample/versions/create), choisissez Lyra Sample.

☑️ [Déployez un serveur avec la version de votre application Lyra Sample](https://app.edgegap.com/deployment-management/deployments/list).

☑️ [Ouvrez les détails de votre nouveau déploiement](https://app.edgegap.com/deployment-management/deployments/list).

☑️ Trouvez les informations de connexion uniques et à usage unique de votre déploiement :

* **URL de l'hôte** au format `780aa4260e83.pr.edgegap.net` ,
* **Port externe** au format `30854`  (5 chiffres).

✅ Vous pouvez maintenant passer à l'étape suivante.

### 2. Jouer dans l'éditeur (PIE)

☑️ Allez dans le dossier racine de votre nouveau projet Lyra Starter Game sur votre disque.

☑️ Éditez le fichier Config / DefaultEngine.ini avec un éditeur de texte (comme le Bloc-notes).

☑️ Pour chaque `[section]`  ci-dessous, ajoutez le contenu suivant si elle existe ou créez la section.

```
[ConsoleVariables]
net.IgnoreNetworkChecksumMismatch=1
net.CurrentHandshakeVersion=2
net.MinHandshakeVersion=2
net.VerifyNetSessionID=0
net.VerifyNetClientID=0

[/Script/Engine.GameEngine]
!NetDriverDefinitions=ClearArray
+NetDriverDefinitions(DefName="GameNetDriver",DriverClassName="OnlineSubsystemUtils.IpNetDriver",DriverClassNameFallback="OnlineSubsystemUtils.IpNetDriver")

[/Script/OnlineSubsystemUtils.IpNetDriver]
MaxClientRate=1000000000 
MaxInternetClientRate=1000000000
InitialConnectTimeout=120.0

[/Script/BuildSettings.BuildSettings]
DefaultServerTarget=LyraServer
```

☑️ Ouvrez votre nouveau projet dans Unreal Engine.

☑️ Appuyez sur le bouton ▶️ Play pour lancer votre client de jeu.

☑️ Appuyez sur la touche tilde `~`  et saisissez `open {host}:{port}`  avec les informations de connexion de l'étape précédente.&#x20;

🙌 Félicitations pour votre premier déploiement sur Edgegap !

## ✏️ Personnaliser la build du serveur

{% hint style="success" %}
Voir [unreal-engine](https://docs.edgegap.com/unreal-engine "mention") pour Unreal Engine afin de **apprendre comment construire et personnaliser des serveurs**.
{% endhint %}


# Exemple Top-Down

Lancer un jeu Unreal Engine avec des serveurs de jeu dédiés peut être un projet décourageant, pour des développeurs individuels comme pour des équipes moyennes expérimentées.

Heureusement, la plateforme Edgegap le rend facile, avec un processus d'intégration simple qui prend quelques minutes. Votre jeu sera alors en ligne, prêt à connecter des joueurs du monde entier. Cela vous aide à consacrer vos précieuses ressources de développement à ce que vous aimez – créer un excellent jeu.

Voici le tutoriel vidéo du plugin d'Edgegap :

{% embed url="<https://youtu.be/J8WNC6itYTE>" %}

***

{% hint style="success" %}
Voir nos [Projet d'exemple Unreal Engine](https://github.com/edgegap/unreal-sample) en utilisant l'exemple Top-Down pour l'inspiration.
{% endhint %}

{% hint style="info" %}
Voir [unreal-engine](https://docs.edgegap.com/unreal-engine "mention") pour Unreal Engine afin de **apprendre comment construire et personnaliser des serveurs**.
{% endhint %}


# Unity


# Photon Fusion 2

Découvrez comment héberger des projets Unity sur Edgegap en utilisant des techniques du [Exemple Fusion 2 Asteroids](https://doc.photonengine.com/fusion/current/game-samples/fusion-asteroids).

{% embed url="<https://youtu.be/bg41HpPmE3E>" %}

## ✔️ Préparation

Avant de commencer, vous aurez besoin de :

* Unity 6 - [télécharger via Unity Hub](https://unity.com/releases/unity-6),
* Projet exemple Fusion 2 Asteroids (modifié pour Edgegap) - [télécharger depuis GitHub](https://github.com/edgegap/netcode-sample-photon-fusion-2).

## ⚡ Déployer et se connecter

### 1. Déployer un serveur sur Edgegap

☑️ Pour commencer, vous devrez [créer un compte gratuit chez Edgegap](https://app.edgegap.com/auth/register). Aucune carte de crédit requise.

☑️ [Créez une nouvelle version d'application pour votre application](https://app.edgegap.com/application-management/applications/fusion-2-asteroids-sample/versions/create), choisissez Fusion 2 Asteroids Sample.

☑️ Ouvrez votre nouveau projet dans Unity.

☑️ Allez dans Tools / Edgegap Hosting, puis à l'étape 6. Déployer un serveur sur Edgegap.

☑️ Appuyez sur Deploy to cloud et [ouvrez les détails de votre nouveau déploiement](https://app.edgegap.com/deployment-management/deployments/list).

☑️ Trouvez les informations de connexion uniques et à usage unique de votre déploiement :

* **URL de l'hôte** au format `780aa4260e83.pr.edgegap.net` .

✅ Vous pouvez maintenant passer à l'étape suivante.

### 2. Se connecter depuis l'éditeur

☑️ Ouvrez votre nouveau projet dans Unity.

☑️ Appuyez sur le bouton ▶️ Play pour lancer votre client de jeu.

☑️ Saisissez l'URL de l'hôte (détails de connexion de l'étape précédente) comme nom de salle.

☑️ Appuyez sur le bouton Start Edgegap pour vous connecter à votre serveur.

☑️ Connectez un deuxième joueur virtuel avec [Multiplayer Play Mode](https://docs-multiplayer.unity3d.com/mppm/current/about/) ou [ParrelSync](https://github.com/VeriorPies/ParrelSync).

🙌 Félicitations pour votre premier déploiement sur Edgegap !

## ✏️ Personnaliser la build du serveur

{% hint style="success" %}
Voir [unity](https://docs.edgegap.com/unity "mention") pour Unity afin de **apprendre comment construire et personnaliser les serveurs**.
{% endhint %}

### Créer une application sur Photon

{% hint style="info" %}
Pour faciliter la démo initiale, nous avons utilisé un compte Photon Cloud gratuit détenu par Edgegap.
{% endhint %}

☑️ [Créez un compte gratuit chez Photon](https://dashboard.photonengine.com/).

☑️ [Créer une application sur Photon](https://dashboard.photonengine.com/app/create):

* `Jeu multijoueur`,
* `Fusion` SDK Photon,
* `Fusion 2` version du SDK.

☑️ Trouvez votre ID d'application au format `85314a99-56fc-4ab3-ba26-50efca09f303` .

☑️ Saisissez votre ID dans Photon Settings sous Tools / Fusion / Fusion Hub (Alt + F).

### Intégrer le projet Fusion 2 avec Edgegap

{% hint style="success" %}
Voir `EdgegapServerManager.cs`  script pour un exemple d'intégration de Fusion 2 avec Edgegap.
{% endhint %}

{% hint style="warning" %}
Votre `NetworkProjectConfig`  **doit utiliser `Peer Mode = Single` (Serveur déd.)**, pas `Multiple` (Client-Hôte) !
{% endhint %}

Les clients de jeu se connecteront aux serveurs de jeu via [Photon Fusion 2 ](https://doc.photonengine.com/fusion/current/manual/connection-and-matchmaking/matchmaking#creating-and-joining-a-game-session)[Session (salle) ](https://doc.photonengine.com/fusion/current/manual/connection-and-matchmaking/matchmaking#creating-and-joining-a-game-session)[fonctionnalité](https://doc.photonengine.com/fusion/current/manual/connection-and-matchmaking/matchmaking#creating-and-joining-a-game-session).

Votre serveur de jeu doit enregistrer son adresse IP et son port externe avec le nom de session, lors de l'appel de `_runnerInstance.StartGame(StartGameArgs args)`:

* utilisez `GameMode.Server`  pour vous assurer que votre connexion n'est pas relayée via Photon Cloud (ajoute de la latence),
* utilisez `NetAddress.CreateFromIpPort` méthode de Fusion,
* fournir l'adresse IP du serveur :\
  `Environment.GetEnvironmentVariable("ARBITRIUM_PUBLIC_IP")`
* fournir le port externe du serveur :\
  `Environment.GetEnvironmentVariable("ARBITRIUM_PORT_GAMEPORT_EXTERNAL")`
  * c'est le nom de mappage de port par défaut si vous utilisez notre [plugin Unity pour empaqueter votre serveur](https://docs.edgegap.com/unity).

Utilisez l'URL d'hôte du déploiement Edgegap comme nom de session :

* dans le serveur de jeu, obtenez-la avec\
  `$"{Environment.GetEnvironmentVariable("ARBITRIUM_REQUEST_ID")}.pr.edgegap.net"`
* lors du test du client de jeu, récupérez-la depuis le tableau de bord - page des détails du déploiement / URL de l'hôte
  * créez des déploiements pour tests depuis notre [plugin d'hébergement quickstart](https://docs.edgegap.com/unity/developer-tools#dedicated-servers-quickstart-plugin),
* en production dans le client de jeu, récupérez-la depuis [matchmaking / affectation de ticket / fqdn](https://docs.edgegap.com/learn/matchmaking/matchmaker-in-depth#player-api):
  * voir aussi [démarrage avec le Matchmaking](https://docs.edgegap.com/learn/matchmaking).

{% tabs %}
{% tab title="Intégration client" %}
{% code title="EdgegapClientManager.cs" %}

```csharp
// obtenir le network runner de fusion 2
_runnerInstance = FindFirstObjectByType<NetworkRunner>();
_runnerInstance.ProvideInput = true;

// obtenir cette valeur depuis l'assignation du matchmaker Edgegap ou l'API Sessions de Fusion 2
string sessionName = "<requestId.pr.edgegap.net>";

// trouver la session fusion 2 (en utilisant le nom de session)
var result = await _runnerInstance.StartGame(
    new StartGameArgs() {
        GameMode = GameMode.Client,
        SessionName = sessionName,
        ObjectProvider = _runnerInstance.GetComponent<NetworkObjectPoolDefault>(),
    }
);

// fusion récupérera maintenant l'IP et le port du serveur en fonction du nom de session et se connectera
```

{% endcode %}
{% endtab %}

{% tab title="Intégration serveur" %}
{% code title="EdgegapServerManager.cs" %}

```csharp
// lire les variables d'environnement injectées par Edgegap
string requestId = Environment.GetEnvironmentVariable("ARBITRIUM_REQUEST_ID");
string listenPort = Environment.GetEnvironmentVariable("ARBITRIUM_PORT_GAMEPORT_INTERNAL");
string connectIP = Environment.GetEnvironmentVariable("ARBITRIUM_PUBLIC_IP");
string connectPort = Environment.GetEnvironmentVariable("ARBITRIUM_PORT_GAMEPORT_EXTERNAL");

// obtenir le network runner de fusion 2
_runnerInstance = FindFirstObjectByType<NetworkRunner>();
_runnerInstance.ProvideInput = true;

// enregistrer la session fusion 2 pour que les clients puissent la retrouver plus tard (en utilisant le nom de session)
var result = await _runnerInstance.StartGame(
    new StartGameArgs() {
        GameMode = GameMode.Server,
        SessionName = $"{requestId}.pr.edgegap.net",
        ObjectProvider = _runnerInstance.GetComponent<NetworkObjectPoolDefault>(),
        Address = NetAddress.Any(listenPort),
        CustomPublicAddress = NetAddress.CreateFromIpPort(connectIP, connectPort),
    }
);

// charger la scène initiale
if (result.Ok && _runnerInstance.IsServer) {
    await _runnerInstance.LoadScene(sceneName);
}
```

{% endcode %}
{% endtab %}
{% endtabs %}

### Dépannage

<details>

<summary><code>Le jeu n'existe pas (32758)</code></summary>

* Les salles Photon exigent que le joueur se connecte à la région Photon Cloud où le déploiement est situé. Le déploiement depuis le tableau de bord utilise une IP de joueur aléatoire.
* Vous devrez peut-être trouver l'emplacement du déploiement sur la carte, et configurer votre client de jeu dans Assets / Photon / Fusion / Resources / PhotonAppSettings.asset avec la [région Photon Cloud](https://doc.photonengine.com/fusion/current/manual/connection-and-matchmaking/regions#photon-cloud-for-gaming).
* Edgegap [déploie aussi près que possible du joueur](https://docs.edgegap.com/learn/orchestration/deployments#id-1.-server-score-strategy-best-practice) lors de l'utilisation de nos [plugins](https://docs.edgegap.com/unity/developer-tools) ou [API](https://docs.edgegap.com/docs/api/serveurs-dedies) donc en production, définir la région Photon Cloud n'est pas requis.

</details>




---

[Next Page](/llms-full.txt/1)

