# 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 [matchmaking](https://docs.edgegap.com/learn/matchmaking "mention"),
* [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 %}
