Webgl cannot connect to the NGO server

Hi Unity community,

I am struggling to connect a WebGL build to a NGO build using Unity Transport. I am seeking guidance, sample code, and any tips on how to tackle this challenge.

To isolate the problem, I have created a simple project that:

  • Loads a dedicated Linux server build to Unity NGO.
  • Loads a WebGL build, which is then run by a server.
  • Tests if the WebGL build can connect to an already open server with a specified IP and Port.

Despite my best efforts and many long nights, I still fail to connect the WebGL client to the NGO server.

This post follows a previous I published. Precisely, a suggestion by CodeSmile to share a new post if I fail to connect to the NGO server with the WebGL build.

I would greatly appreciate any help or pointers from the community to resolve this issue.

Thank you!

Specs:

Unity Transport 2.1
Unity Editor 2023.3
NGO

Configurations:

  • NGO Cloud Service: After loading the project’s dedicated Linux server build, I created a fleet and started 1 server with a specific IP and Port (35.234.121.231:9000). The Unity dashboard confirms that the server is online.

  • UFW Rules and WebGL: I ensured I have the UFW rules to access port 9000. I then ran the server.js to mount the WebGL build. Once loaded, the build tries to connect to the server and after a few seconds, prints “Client disconnected 0, Count:0, port:9000”, which is the expected log in case of failure.

  • Client and Server Settings: Both the WebGL client and the Linux server builds are executed with Unity Transport, with “Use Websockets” ticked. I also tried running the server build without “Use Websockets” ticked, but the result was the same.

Network Checks: In my local bash, I could ping the NGO server, but nmap confirms that port 9000 is down. This is particularly confusing because the Unity dashboard confirms the server binds to port 9000, yet my local bash states the port is down.

Logs:

ping 35.234.121.231
PING 35.234.121.231 (35.234.121.231) 56(84) bytes of data.
64 bytes from 35.234.121.231: icmp_seq=1 ttl=56 time=16.8 ms
64 bytes from 35.234.121.231: icmp_seq=2 ttl=56 time=14.3 ms
64 bytes from 35.234.121.231: icmp_seq=3 ttl=56 time=14.5 ms
64 bytes from 35.234.121.231: icmp_seq=4 ttl=56 time=15.0 ms
64 bytes from 35.234.121.231: icmp_seq=5 ttl=56 time=15.2 ms
  
nmap -p 9000 35.234.121.231
Starting Nmap 7.80 ( https://nmap.org ) at 2024-08-06 18:10 CEST
Note: Host seems down. If it is really up, but blocking our ping probes, try -Pn
Nmap done: 1 IP address (0 hosts up) scanned in 3.15 seconds

Hierarchy Setup:

  • NetworkManager: Has Unity Transport with “Use Websockets” ticked and PlayerPrefab attached.

  • Client, Setup, Server: Empty objects with respective scripts attached. The Example_ServerQueryHandler.cs is also attached to the Server object.

Assets:

  • Prefab/PlayerPrefab: Has the GamePlayer.cs script attached.
  • Scripts: The Assets/Scripts folder contains the following scripts:

Client.cs:

public class Client : MonoBehaviour
{
    static bool initialized;
    const string serverIp = "35.234.121.231";
    const ushort serverPort = 9000;

    async void Start()
    {
        try
        {
            if (!initialized)
            {
                Debug.Log("Initializing Unity Services...");
                await UnityServices.InitializeAsync();
                AuthenticationService.Instance.SwitchProfile(UnityEngine.Random.Range(0, 1000000).ToString());
                await AuthenticationService.Instance.SignInAnonymouslyAsync();
                initialized = true;
                Debug.Log("Unity Services initialized.");
            }

            ConnectDirectlyToServer();
        }
        catch (Exception ex)
        {
            Debug.LogError($"Error initializing services: {ex}");
        }
    }

    void ConnectDirectlyToServer()
    {
        Debug.Log("Connecting directly to the server...");

        var transport = NetworkManager.Singleton.GetComponent<UnityTransport>();
        transport.SetConnectionData(serverIp, serverPort);
        bool result = NetworkManager.Singleton.StartClient();

        // Logging and showing on UI
        Debug.Log("StartClient " + result);
        FindFirstObjectByType<TMP_Text>()?.SetText("StartClient " + result);
        NetworkManager.Singleton.OnConnectionEvent += LogConnectionEvent;
    }

    void LogConnectionEvent(NetworkManager manager, ConnectionEventData data)
    {
        switch (data.EventType)
        {
            case ConnectionEvent.ClientConnected:
                FindFirstObjectByType<TMP_Text>().SetText("Client connected " + data.ClientId +
                                                          " Count:" +
                                                          NetworkManager.Singleton.ConnectedClientsIds.Count + " Port:" + 
                                                          (manager.NetworkConfig.NetworkTransport as UnityTransport)?.ConnectionData.Port);
                break;
            case ConnectionEvent.ClientDisconnected:
                FindFirstObjectByType<TMP_Text>()
                    .SetText("Client disconnected " + data.ClientId + " Count:" +
                             NetworkManager.Singleton.ConnectedClientsIds.Count + " Port:" + 
                             (manager.NetworkConfig.NetworkTransport as UnityTransport)?.ConnectionData.Port);
                break;
        }
    }
}

Server.cs:

public class Server : MonoBehaviour
{
    string _ticketId;

    void Start()
    {
        DontDestroyOnLoad(gameObject);
#if UNITY_SERVER || UNITY_EDITOR
        StartCoroutine(StartServer());
        StartCoroutine(ApproveBackfillTicketEverySecond());
#endif
    }

#if UNITY_SERVER || UNITY_EDITOR
    async Awaitable StartServer()
    {
        await UnityServices.InitializeAsync();
        var server = MultiplayService.Instance.ServerConfig;
        var transport = NetworkManager.Singleton.GetComponent<UnityTransport>();
        transport.SetConnectionData("0.0.0.0", server.Port);
        Debug.Log("Network Transport " + transport.ConnectionData.Address + ":" + transport.ConnectionData.Port);

        if (!NetworkManager.Singleton.StartServer())
        {
            Debug.LogError("Failed to start server");
            throw new Exception("Failed to start server");
        }

        NetworkManager.Singleton.OnClientConnectedCallback += (clientId) => { Debug.Log("Client connected"); };
        NetworkManager.Singleton.OnServerStopped += (reason) => { Debug.Log("Server stopped"); };
        NetworkManager.Singleton.SceneManager.LoadScene("Level1", LoadSceneMode.Single);
        Debug.Log($"Started Server {transport.ConnectionData.Address}:{transport.ConnectionData.Port}");

        var callbacks = new MultiplayEventCallbacks();
        callbacks.Allocate += OnAllocate;
        callbacks.Deallocate += OnDeallocate;
        callbacks.Error += OnError;
        callbacks.SubscriptionStateChanged += OnSubscriptionStateChanged;

        while (MultiplayService.Instance == null)
        {
            await Awaitable.NextFrameAsync();
        }

        var events = await MultiplayService.Instance.SubscribeToServerEventsAsync(callbacks);
        await CreateBackfillTicket();
    }

    void OnSubscriptionStateChanged(MultiplayServerSubscriptionState obj)
    {
        Debug.Log($"Subscription state changed: {obj}");
    }

    void OnError(MultiplayError obj)
    {
        Debug.Log($"Error received: {obj}");
    }

    async void OnDeallocate(MultiplayDeallocation obj)
    {
        Debug.Log($"Deallocation received: {obj}");
        await MultiplayService.Instance.UnreadyServerAsync();
    }

    async void OnAllocate(MultiplayAllocation allocation)
    {
        Debug.Log($"Allocation received: {allocation}");
        await MultiplayService.Instance.ReadyServerForPlayersAsync();
    }

    async Task CreateBackfillTicket()
    {
        MatchmakingResults results =
            await MultiplayService.Instance.GetPayloadAllocationFromJsonAs<MatchmakingResults>();

        Debug.Log(
            $"Environment: {results.EnvironmentId} MatchId: {results.MatchId} MatchProperties: {results.MatchProperties}");

        var backfillTicketProperties = new BackfillTicketProperties(results.MatchProperties);

        string queueName = "test";
        string connectionString = MultiplayService.Instance.ServerConfig.IpAddress + ":" +
                                MultiplayService.Instance.ServerConfig.Port;

        var options = new CreateBackfillTicketOptions(queueName,
            connectionString,
            new Dictionary<string, object>(),
            backfillTicketProperties);

        Debug.Log("Requesting backfill ticket");
        _ticketId = await MatchmakerService.Instance.CreateBackfillTicketAsync(options);
    }

    IEnumerator ApproveBackfillTicketEverySecond()
    {
        for (int i = 4; i >= 0; i--)
        {
            Debug.Log($"Waiting {i} seconds to start backfill");
            yield return new WaitForSeconds(1f);
        }

        while (true)
        {
            yield return new WaitForSeconds(1f);
            if (String.IsNullOrWhiteSpace(_ticketId))
            {
                Debug.Log("No backfill ticket to approve");
                continue;
            }

            Debug.Log("Doing backfill approval for _ticketId: " + _ticketId);
            yield return MatchmakerService.Instance.ApproveBackfillTicketAsync(_ticketId);
            Debug.Log("Approved backfill ticket: " + _ticketId);
        }
    }
#endif
}

Setup.cs:

public class Startup : MonoBehaviour
{
    public string Client;
    public string Server;

    void Start()
    {
        if (System.Environment.GetCommandLineArgs().Any(arg => arg == "-port"))
        {
            Debug.Log("Starting server");
            SceneManager.LoadScene(Server);
        }
        else
        {
            Debug.Log("Starting client");
            SceneManager.LoadScene(Client);
        }
    }
}

Example_ServerQueryHandler.cs:

using Unity.Netcode;
#if UNITY_SERVER || UNITY_EDITOR
using Unity.Services.Multiplay;
#endif
using UnityEngine;

public class Example_ServerQueryHandler : MonoBehaviour
{
    const ushort k_DefaultMaxPlayers = 10;
    const string k_DefaultServerName = "MyServerExample";
    const string k_DefaultGameType = "MyGameType";
    const string k_DefaultBuildId = "test2";
    const string k_DefaultMap = "MyMap";

#if UNITY_SERVER || UNITY_EDITOR
    IServerQueryHandler m_ServerQueryHandler;

    async void Start()
    {
        while (MultiplayService.Instance == null)
        {
            await Awaitable.NextFrameAsync();
        }

        m_ServerQueryHandler = await MultiplayService.Instance.StartServerQueryHandlerAsync(
            k_DefaultMaxPlayers, k_DefaultServerName, k_DefaultGameType, k_DefaultBuildId, k_DefaultMap);
    }

    void Update()
    {
        if (m_ServerQueryHandler != null)
        {
            if (NetworkManager.Singleton.ConnectedClients.Count != m_ServerQueryHandler.CurrentPlayers)
                m_ServerQueryHandler.CurrentPlayers = (ushort)NetworkManager.Singleton.ConnectedClients.Count;

            m_ServerQueryHandler.UpdateServerCheck();
        }
    }

    public void ChangeQueryResponseValues(ushort maxPlayers, string serverName, string gameType, string buildId)
    {
        m_ServerQueryHandler.MaxPlayers = maxPlayers;
        m_ServerQueryHandler.ServerName = serverName;
        m_ServerQueryHandler.GameType = gameType;
        m_ServerQueryHandler.BuildId = buildId;
    }

    public void PlayerCountChanged(ushort newPlayerCount)
    {
        m_ServerQueryHandler.CurrentPlayers = newPlayerCount;
    }
#endif
}

GamePlayer.cs:

public class GamePlayer : NetworkBehaviour
{
    [ContextMenu("Send Test")]
    public void SendTest()
    {
        Debug.Log("Sending Test");
        TestServerRpc();
    }

    [ServerRpc]
    void TestServerRpc()
    {
        TestClientRpc();
    }

    [ClientRpc]
    void TestClientRpc()
    {
        Debug.Log("Got Client Rpc");
    }

    public override void OnNetworkSpawn()
    {
        base.OnNetworkSpawn();
        if (IsLocalPlayer)
        {
            Debug.Log("I am the local player");
        }
    }

    void Start()
    {
        if (IsClient && IsLocalPlayer)
        {
            Debug.Log("Sending server rpc");
            TestServerRpc();
        }
    }
}

server.js:

const express = require('express');
const compression = require('compression');
const path = require('path');
const app = express();
const port = 8080;

app.use(compression());

app.use((req, res, next) => {
  res.header('Access-Control-Allow-Origin', '*');
  res.header('Access-Control-Allow-Methods', 'GET,POST');
  res.header('Access-Control-Allow-Headers', 'Content-Type');
  res.header('Content-Security-Policy', "default-src 'self'; img-src 'self' data:; style-src 'self' 'unsafe-inline'; script-src 'self' 'unsafe-inline' 'wasm-unsafe-eval'; connect-src *");
  next();
});

// Set Content-Encoding and Content-Type headers for gzipped files
app.get('*.js.gz', (req, res, next) => {
  res.set('Content-Encoding', 'gzip');
  res.set('Content-Type', 'application/javascript');
  console.log('Serving gzipped JS file:', req.url);
  next();
});

app.get('*.data.gz', (req, res, next) => {
  res.set('Content-Encoding', 'gzip');
  res.set('Content-Type', 'application/octet-stream');
  console.log('Serving gzipped data file:', req.url);
  next();
});

app.get('*.wasm.gz', (req, res, next) => {
  res.set('Content-Encoding', 'gzip');
  res.set('Content-Type', 'application/wasm');
  console.log('Serving gzipped WASM file:', req.url);
  next();
});

// Serve the WebGL build
app.use(express.static(path.join(__dirname, '.')));

// Handle favicon.ico requests
app.get('/favicon.ico', (req, res) => res.status(204));

// Serve index.html for all other routes
app.get('*', (req, res) => {
  res.sendFile(path.resolve(__dirname, 'index.html'));
});

app.listen(port, () => {
  console.log(`WebGL build is served at http://localhost:${port}`);
});

List of Logs:

NGO Cloud, Server Engine.log: MB - I removed the irrelevant logs

Mono path[0] = '/game/DedicatedNGOConTest/build_Data/Managed'
Mono config path = '/game/DedicatedNGOConTest/build_Data/MonoBleedingEdge/etc'
Preloaded 'lib_burst_generated.so'
Initialize engine version: 2023.3.0b7 (ebadad6d577d)
[Subsystems] Discovering subsystems at path /game/DedicatedNGOConTest/build_Data/UnitySubsystems
Forcing GfxDevice: Null
GfxDevice: creating device client; kGfxThreadingModeNonThreaded
NullGfxDevice:
    Version:  NULL 1.0 [1.0]
    Renderer: Null Device
    Vendor:   Unity Technologies
Begin MonoManager ReloadAssembly
- Loaded All Assemblies, in  0.106 seconds
- Finished resetting the current domain, in  0.002 seconds
[PhysX] Initialized MultithreadedTaskDispatcher with 1 workers.
Starting server
Unloading 5 Unused Serialized files (Serialized files now loaded: 0)
[PhysX] Initialized MultithreadedTaskDispatcher with 1 workers.
UnloadTime: 3.452849 ms
Unloading 3 unused Assets to reduce memory usage. Loaded Objects now: 1970.
Total: 1.365319 ms (FindLiveObjects: 0.144534 ms CreateObjectMapping: 0.093984 ms MarkObjects: 1.102612 ms  DeleteObjects: 0.023711 ms)

Network Transport 0.0.0.0:9000
Started Server 0.0.0.0:9000
Subscription state changed: Subscribing
Unloading 5 Unused Serialized files (Serialized files now loaded: 0)
[Wire]: Attempting connection on: ws://127.0.0.1:8086/v1/connection/websocket
Waiting 4 seconds to start backfill
SQP server: SQP server started on 0.0.0.0:9010
[PhysX] Initialized MultithreadedTaskDispatcher with 1 workers.
UnloadTime: 2.490008 ms
[Wire]: Websocket connected to : ws://127.

Server.js logs:

node server.js
WebGL build is served at http://localhost:8080
Serving gzipped JS file: /Build/websocket.framework.js.gz
Serving gzipped data file: /Build/websocket.data.gz
Serving gzipped WASM file: /Build/websocket.wasm.gz

Browser F12 logs:

WEBGL_debug_renderer_info is deprecated in Firefox and will be removed. Please use RENDERER. websocket.loader.js:1:8342
Applying workaround to Firefox bug https://bugzilla.mozilla.org/show_bug.cgi?id=1397977 websocket.loader.js:1:1331
    printErr http://localhost:8080/Build/websocket.loader.js:1
    warnOnce http://localhost:8080/Build/websocket.framework.js.gz:9
    enumerateMediaDeviceList http://localhost:8080/Build/websocket.framework.js.gz:9
    unityFramework http://localhost:8080/Build/websocket.framework.js.gz:9
[UnityCache] 'http://localhost:8080/Build/websocket.data.gz' successfully downloaded and stored in the browser cache websocket.loader.js:1:6232
[UnityMemory] Configuration Parameters - Can be set up in boot.config
websocket.framework.js.gz:9:31902
    "memorysetup-allocator-temp-initial-block-size-main=262144"
    "memorysetup-allocator-temp-initial-block-size-worker=262144"
    "memorysetup-temp-allocator-size-audio-worker=65536"
    "memorysetup-temp-allocator-size-background-worker=32768"
    "memorysetup-bucket-allocator-granularity=16"
    "memorysetup-bucket-allocator-bucket-count=8"
    "memorysetup-bucket-allocator-block-size=4194304"
    "memorysetup-bucket-allocator-block-count=1"
    "memorysetup-main-allocator-block-size=16777216"
    "memorysetup-thread-allocator-block-size=16777216"
    "memorysetup-gfx-main-allocator-block-size=16777216"
    "memorysetup-gfx-thread-allocator-block-size=16777216"
    "memorysetup-cache-allocator-block-size=4194304"
    "memorysetup-typetree-allocator-block-size=2097152"
    "memorysetup-profiler-bucket-allocator-granularity=16"
    "memorysetup-profiler-bucket-allocator-bucket-count=8"
    "memorysetup-profiler-bucket-allocator-block-size=4194304"
    "memorysetup-profiler-bucket-allocator-block-count=1"
    "memorysetup-profiler-allocator-block-size=16777216"
    "memorysetup-profiler-editor-allocator-block-size=1048576"
    "memorysetup-temp-allocator-size-main=4194304"
    "memorysetup-job-temp-allocator-block-size=2097152"
    "memorysetup-job-temp-allocator-block-size-background=1048576"
    "memorysetup-job-temp-allocator-reduction-small-platforms=262144"
Loading player data from data.unity3d
websocket.framework.js.gz:9:31902
Initialize engine version: 2023.3.0b7 (ebadad6d577d)
websocket.framework.js.gz:9:31902
Creating WebGL 2.0 context. websocket.loader.js:1:1294
Renderer: ANGLE (AMD, Radeon HD 3200 Graphics Direct3D11 vs_5_0 ps_5_0), or similar
websocket.framework.js.gz:9:31902
Vendor:   Mozilla
websocket.framework.js.gz:9:31902
Version:  OpenGL ES 3.0 (WebGL 2.0)
websocket.framework.js.gz:9:31902
OPENGL LOG: Creating OpenGL ES 3.0 graphics device ; Context level  <OpenGL ES 3.0> ; Context handle 1
websocket.framework.js.gz:9:31902
An AudioContext was prevented from starting automatically. It must be created or resumed after a user gesture on the page. websocket.framework.js.gz:9:119048
[PhysX] Initialized SinglethreadedTaskDispatcher.
websocket.framework.js.gz:9:31902
Input Manager initialize...
websocket.framework.js.gz:9:31902
[PhysX] Initialized SinglethreadedTaskDispatcher.
websocket.framework.js.gz:9:31902
UnloadTime: 1.000000 ms
websocket.framework.js.gz:9:31902
An AudioContext was prevented from starting automatically. It must be created or resumed after a user gesture on the page. 5 websocket.framework.js.gz:9:119171
Starting client
websocket.framework.js.gz:9:31902
[PhysX] Initialized SinglethreadedTaskDispatcher.
websocket.framework.js.gz:9:31902
UnloadTime: 0.000000 ms
websocket.framework.js.gz:9:31902
Unloading 5 Unused Serialized files (Serialized files now loaded: 0)
websocket.framework.js.gz:9:31902
Unloading 3 unused Assets to reduce memory usage. Loaded Objects now: 1828.
websocket.framework.js.gz:9:31902
Total: 4.000000 ms (FindLiveObjects: 0.000000 ms CreateObjectMapping: 0.000000 ms MarkObjects: 4.000000 ms  DeleteObjects: 0.000000 ms)

websocket.framework.js.gz:9:31902
Initializing Unity Services...
websocket.framework.js.gz:9:31902
An AudioContext was prevented from starting automatically. It must be created or resumed after a user gesture on the page. 2 websocket.framework.js.gz:9:119171
Unity Services initialized.
websocket.framework.js.gz:9:31902
Connecting directly to the server...
websocket.framework.js.gz:9:31902
StartClient True
websocket.framework.js.gz:9:31902
An AudioContext was prevented from starting automatically. It must be created or resumed after a user gesture on the page. 5 websocket.framework.js.gz:9:119171
Firefox can’t establish a connection to the server at ws://35.234.121.231:9000/. websocket.framework.js.gz:9:291896
Failed to connect to server.
websocket.framework.js.gz:9:31830
    _JS_Log_Dump http://localhost:8080/Build/websocket.framework.js.gz:9
    <anonymous> http://localhost:8080/Build/websocket.wasm.gz:25129521
    <anonymous> http://localhost:8080/Build/websocket.wasm.gz:35195471
    <anonymous> http://localhost:8080/Build/websocket.wasm.gz:35200610
    <anonymous> http://localhost:8080/Build/websocket.wasm.gz:35200332
    <anonymous> http://localhost:8080/Build/websocket.wasm.gz:35198093
    <anonymous> http://localhost:8080/Build/websocket.wasm.gz:34697246
    <anonymous> http://localhost:8080/Build/websocket.wasm.gz:35250059
    invoke_viiii http://localhost:8080/Build/websocket.framework.js.gz:9
    <anonymous> http://localhost:8080/Build/websocket.wasm.gz:18441344
    <anonymous> http://localhost:8080/Build/websocket.wasm.gz:18441791
    <anonymous> http://localhost:8080/Build/websocket.wasm.gz:21293133
    <anonymous> http://localhost:8080/Build/websocket.wasm.gz:18443803
    <anonymous> http://localhost:8080/Build/websocket.wasm.gz:8744011
    <anonymous> http://localhost:8080/Build/websocket.wasm.gz:8748110
    <anonymous> http://localhost:8080/Build/websocket.wasm.gz:24873032
    <anonymous> http://localhost:8080/Build/websocket.wasm.gz:25049123
    <anonymous> http://localhost:8080/Build/websocket.wasm.gz:35249882
    invoke_iiii http://localhost:8080/Build/websocket.framework.js.gz:9
    <anonymous> http://localhost:8080/Build/websocket.wasm.gz:25046723
    <anonymous> http://localhost:8080/Build/websocket.wasm.gz:1061280
    <anonymous> http://localhost:8080/Build/websocket.wasm.gz:34593589
    <anonymous> http://localhost:8080/Build/websocket.wasm.gz:33798168
    <anonymous> http://localhost:8080/Build/websocket.wasm.gz:33798189
    <anonymous> http://localhost:8080/Build/websocket.wasm.gz:33764510
    <anonymous> http://localhost:8080/Build/websocket.wasm.gz:33493249
    <anonymous> http://localhost:8080/Build/websocket.wasm.gz:33452088
    <anonymous> http://localhost:8080/Build/websocket.wasm.gz:33452205
    <anonymous> http://localhost:8080/Build/websocket.wasm.gz:35058412
    <anonymous> http://localhost:8080/Build/websocket.wasm.gz:35249975
    _JS_CallAsLongAsNoExceptionsSeen http://localhost:8080/Build/websocket.framework.js.gz:9
    _JS_CallAsLongAsNoExceptionsSeen http://localhost:8080/Build/websocket.framework.js.gz:9
    <anonymous> http://localhost:8080/Build/websocket.wasm.gz:35039055
    <anonymous> http://localhost:8080/Build/websocket.wasm.gz:35249975
    browserIterationFunc http://localhost:8080/Build/websocket.framework.js.gz:9
    callUserCallback http://localhost:8080/Build/websocket.framework.js.gz:9
    runIter http://localhost:8080/Build/websocket.framework.js.gz:9
    Browser_mainLoop_runner http://localhost:8080/Build/websocket.framework.js.gz:9
An AudioContext was prevented from starting automatically. It must be created or resumed after a user gesture on the page.

Issue Summary:
Despite the server being confirmed online by the Unity dashboard, nmap reports port 9000 as down. This discrepancy is the most confusing part, as it suggests the port is not accessible despite being bound by the server.

You mean Unity 6? If you’re still on 2023.3 it means you’re running a beta version.

Have you tried running a dedicated server locally and connecting to that with your WebGL client?

Be sure to register events BEFORE you call StartXxxx or else you may miss some events!
Same for the server side. Events first, StartXxxx last.

transport.SetConnectionData("0.0.0.0", server.Port);

You are not setting the server listen address (third parameter). This means the server will listen only on localhost (127.0.0.1).

Use “0.0.0.0” as the listen address parameter (or the actual server IP) and enter the public server IP in the first parameter (although I’m not sure maybe you can leave the address as 0.0.0.0).

The server logs tell you that the server bound the port to “0.0.0.0:9000”. :wink:

Thanks for your reply. I probably wasn’t clear about the discrepancy. While the server indeed tells me that the server is bound to port 9000, when I test it with nmap command from the client webserver bash, the output is that it isn’t connected. I.e.: ```
Note: Host seems down. If it is really up, but blocking our ping probes, try -Pn

I am not arguing with the fact that the server is bound to port 9000. I simply state that from the local client bash the server is down, i.e. it cannot access the port. Thus, I can not continue testing, until I cannot call from another station the NGO IP+Port.