24 min read

Self-Host Colyseus Behind NAT with Localtonet

Install and verify a Colyseus multiplayer server, then expose its HTTP and WebSocket traffic securely through a Localtonet HTTP tunnel.

A Colyseus server behind NAT connects through a Localtonet tunnel to remote game clients.
Colyseus remains on the private host while HTTP and WebSocket traffic crosses an outbound tunnel.
Game Server Hosting · Colyseus · Localtonet · 2026

Run an authoritative multiplayer server locally, verify it, and make it reachable without opening router ports

Colyseus is an open-source Node.js framework for room-based multiplayer games, matchmaking, and real-time state synchronization. This guide starts with the server itself: preparing Node.js, generating a Colyseus project, starting it, identifying its actual local endpoint, and validating a room connection. After the local service works, we connect it to a Localtonet HTTP tunnel so remote game clients can use its HTTP and WebSocket traffic through a public HTTPS endpoint. The workflow does not require inbound router port forwarding, firewall changes, VPN setup, or a public IP address.

🔒 Keep game authority and access controls on your server 🌐 Carry HTTP and WebSocket traffic through one public endpoint ⚡ Install locally first, then add remote access

What this self-hosted architecture does

Colyseus is an authoritative multiplayer framework for Node.js. In an authoritative design, important game state and game rules run on the server rather than being accepted directly from a player. Clients send actions or inputs, while the server decides how those actions affect the shared state. Colyseus provides room-based gameplay, matchmaking, reconnection support, and synchronizable data structures for real-time and turn-based projects.

A typical Colyseus client first uses an HTTP-based matchmaking operation such as joining or creating a room. The connection can then use WebSockets for persistent, bidirectional communication with that room. This means remote access must account for more than an ordinary page load. The public endpoint must handle the initial HTTP requests and the WebSocket upgrade and connection used by the game session.

Self-hosting introduces a networking boundary. A server listening on a laptop, workstation, home server, or private cloud instance may be accessible only from that machine or its local network. Network address translation commonly prevents unsolicited inbound internet traffic from reaching it. Carrier-grade NAT, changing public addresses, and restrictive network environments can make conventional router forwarding unavailable or inconvenient.

With Localtonet, the client application on the machine that can reach Colyseus establishes an outbound connection to one of our relay servers. An HTTP tunnel points to the Colyseus local IP address and port and provides a public URL. The tunnel remains available only while the selected Localtonet client is connected and the tunnel is running.

⚔️ Authoritative game logic Colyseus runs room logic and state decisions on the server, helping clients share a consistent game state without making each client authoritative.
🔄 Real-time state synchronization The framework provides synchronizable data structures and sends state changes to connected clients using its multiplayer protocol.
🚪 Room-based matchmaking Applications can organize sessions as rooms and use Colyseus matchmaking APIs to join or create the appropriate room.
🌐 Public HTTP endpoint A Localtonet HTTP tunnel maps a public HTTPS address to the working Colyseus service on the host or another locally reachable machine.
🔌 Outbound tunnel connection The Localtonet client initiates the relay connection, so this workflow does not require inbound router port forwarding or a public IP address.
🧩 Separate application security The tunnel supplies connectivity. Your Colyseus application remains responsible for player authentication, authorization, input validation, and room access rules.
Build and test in layers

Do not create the tunnel as a substitute for local testing. First confirm that Colyseus starts and that a compatible client can complete the intended matchmaking and room workflow locally. Then expose the exact working local address through Localtonet. This separation makes configuration errors much easier to diagnose.

Prerequisites and decisions to make first

The official Colyseus quickstart requires Node.js and uses npm. Install a currently supported Node.js release from the official Node.js distribution appropriate for your operating system. The supplied Colyseus evidence does not establish a specific minimum Node.js version, so this guide does not invent one. If your project or the current Colyseus documentation specifies a version, follow that requirement and keep it consistent across development and deployment.

Confirm that both Node.js and npm are available in your terminal:

node --version
npm --version

Both commands should print version information. If either command is missing, repair the Node.js installation or terminal path before creating the project. A package manager error at this stage is unrelated to NAT or Localtonet and should be resolved locally first.

You also need a directory where the generated project can be created, permission to install its dependencies, and a terminal that can keep the server process running. For remote access, install and run the Localtonet client on the same machine as Colyseus or on a device that can reach the Colyseus listening address over the local network.

Before continuing, decide whether this is a temporary development endpoint or a persistent deployment. A development machine is suitable for controlled testing, but it may sleep, restart, change networks, or stop the terminal process. A long-running game service needs deliberate process supervision, updates, backups, resource monitoring, and an application-specific security plan. Those production controls are distinct from tunnel creation.

Requirement Why it is needed How to confirm it
Node.js and npm Colyseus is a Node.js framework, and the official quickstart uses npm to generate and start the server project. Run node --version and npm --version.
Generated Colyseus project It contains the application scripts, dependencies, room definitions, and configuration used by your server. Generate the project, enter its directory, and review its files and package scripts.
Verified local endpoint Localtonet needs the actual IP address and port on which the running service is reachable. Read the startup output and current project configuration, then test the reported endpoint locally.
Compatible game client A page response alone does not prove that matchmaking, WebSocket upgrades, and room communication work. Use your project client or a generated example client to join a known room and exchange an expected message or state update.
Localtonet client and device token The client establishes the outbound connection and identifies the device that will run the tunnel. Install the client, authenticate the intended device, and keep its device-specific token private.
Do not copy unknown versions or endpoints from another installation

Colyseus templates and defaults can change. The evidence available for this guide does not establish a universal hostname, local port, readiness path, TLS setting, room name, or generated file layout. Obtain those details from your generated project, its startup output, and the current documentation for the version you installed.

Install and start a Colyseus server

The official quickstart provides a compact three-command workflow. Run it from the parent directory in which you want the new my-server directory to be created.

1

Generate the Colyseus project

Use the official project generator to create a new server in ./my-server. The @latest selector requests the current generator release available through npm.

2

Enter the generated directory

Change into the project directory before running package scripts or inspecting the generated configuration.

3

Start the generated server

Run the project start script and keep the terminal open. Record the listening address, port, warnings, and any local URL printed by the process.

npm create colyseus-app@latest ./my-server
cd my-server
npm start

The generator may ask questions or offer presets depending on its current release. Select options that match the type of game you are building, and retain a record of those choices. Colyseus 0.18 release information identifies minimal, realtime-action, and turn-based create-colyseus-app presets, but the exact interactive prompts and resulting project contents can change. Read each prompt rather than assuming a fixed sequence beyond the official quickstart commands.

When npm start succeeds, do not immediately close the terminal. Its output is the most reliable evidence for the endpoint produced by your generated version and configuration. Look for the address or interface, the port, startup completion, and any registered development tools or routes. If the process exits, resolve that failure before configuring remote access.

The generated package.json is the authoritative record of what npm start invokes in this project. Review it before adding a production service manager or changing scripts. Also review the generated source to locate room registration, transport configuration, environment handling, and optional development interfaces. File names are intentionally not prescribed here because the supplied evidence does not establish a stable generated layout.

Pin and review before production use

The generator command intentionally uses the latest release. That is convenient for a new project, but production deployments should keep their dependency manifest and lockfile under version control, review release and migration notes, and test upgrades before deployment. Colyseus 0.18 includes new features and breaking changes, so an older project should not be upgraded by replacing version numbers without migration testing.

Configure Colyseus for your game

A generated server is a starting point, not a complete production game backend. Your application must define at least one room that corresponds to the name your client will request. Room logic owns the server-side state and receives client lifecycle events and messages. The client and server must agree on the room name, expected messages, and synchronized schema.

Define the room contract

Write down the protocol between the game client and server before exposing it. That contract includes the matchmaking room name, accepted join options, client messages, server responses, state fields, error handling, and reconnection behavior. A mismatch can resemble a networking problem even when the HTTP and WebSocket connection itself is healthy.

Colyseus supports server-authoritative state synchronization. Keep decisive game rules on the server, validate every client-supplied value, and reject actions that are impossible or unauthorized. A WebSocket connection is not proof that a player may access every room or perform every action.

Determine the actual listening endpoint

Identify the local endpoint from the generated project and runtime output. You need two values for the later tunnel configuration: a local IP address reachable from the Localtonet client device and the listening port used by Colyseus.

If both processes run on the same machine, use the local address confirmed by the application and operating system. If Localtonet runs on a different device, a loopback-only listener cannot be reached from that other device. In that topology, configure Colyseus according to its current documentation so it listens on an appropriate local interface, then test access from the Localtonet device before creating the tunnel.

Do not assume that a browser-visible URL proves the WebSocket path is correct. A Colyseus deployment can involve matchmaking routes, room connections, and optional tools. Verify the exact workflow used by your intended client SDK.

Keep development interfaces private

Generated projects or selected presets may include playground, monitoring, or administrative functionality. Colyseus 0.18 introduced guards for monitor and playground usage and changed production behavior for playground data endpoints. Review your generated version carefully. Do not expose operational tools merely because they share the same server as the game endpoint.

A public tunnel increases reachability, not authorization

Apply player authentication, room authorization, rate controls, input validation, and least-privilege administration inside the application. Protect or disable development, monitoring, playground, debugging, and administrative routes before making the endpoint public. Never embed Localtonet device tokens, server credentials, or administrative secrets in a game client.

Verify the server locally before tunneling it

Browser developer tools show successful local HTTP and WebSocket connections to Colyseus.
Local HTTP and WebSocket checks confirm the server works before tunneling.

Local verification should proceed from the simplest check to the complete multiplayer workflow. The purpose is to prove that Colyseus works independently of public DNS, relay selection, and remote networks.

1

Confirm that the process stays running

Start the server with npm start. Verify that it does not exit and that the terminal shows no unresolved dependency, compilation, configuration, or address-binding error.

2

Record the reported local endpoint

Use the host and port shown by the running project or established by its current configuration. Do not substitute a port copied from an unrelated tutorial.

3

Test the local HTTP behavior

Open the reported URL or request a route known to exist in your generated project. A valid result may be a page, structured response, or application-specific status. The exact readiness route is not established by the available evidence.

4

Join a known room with a compatible client

Point your game client or generated example client at the local endpoint, request the room name registered by your server, and confirm that joining succeeds.

5

Exercise real-time communication

Send an expected game message or input and confirm that the server processes it and that the client receives the corresponding response or synchronized state change.

The last two checks are essential. A successful HTTP response can coexist with a failed WebSocket upgrade, a mismatched room name, an incompatible SDK, or an exception in room logic. Conversely, an HTTP 404 on an undocumented root path does not necessarily prove the game protocol is unavailable. Test a route and room workflow that the project actually defines.

For a two-player game, run at least two controlled clients when practical. Confirm that both join the intended room and that one client’s permitted action results in the expected state update for the other. Also test disconnect and reconnection behavior if your game depends on it.

Expose the working Colyseus endpoint with Localtonet

HTTP and WebSocket traffic travels from a public endpoint through Localtonet to local Colyseus.
The public endpoint forwards HTTP and WebSocket traffic to the private Colyseus service.

Once local verification succeeds, create an HTTP tunnel that points to the confirmed Colyseus address. An HTTP tunnel is the appropriate family for this workflow because the game endpoint uses HTTP interactions and WebSocket connections rather than an unrelated raw game protocol.

Localtonet runs independently of the Colyseus process. Keep Colyseus running, then install and run our client on the device that can reach it. The Localtonet client establishes an outbound relay connection, so you do not need to configure inbound router forwarding, make firewall changes, build a VPN, or obtain a public IP address.

1

Install and run the Localtonet client

Install the Localtonet application for the operating system on the device that can reach the verified Colyseus endpoint, then keep the client connected while the public game service is needed.

2

Authenticate or select the intended device

Use the device-specific authentication token associated with the client that will run the tunnel. Treat the token as a secret and never place it in source control, logs, screenshots, or distributed game builds.

3

Select an available relay server

Choose from the server or region values currently available in your Localtonet dashboard. Availability can vary, so this guide does not hardcode a server code or region name.

4

Create an HTTP tunnel to Colyseus

Set the local target to the IP address and port verified in the previous section. Choose an available HTTP process type appropriate to your account and deployment, such as a random subdomain, supported custom subdomain, or custom domain.

5

Start the tunnel

Creating a configuration does not make it active. Use the Start button and wait until the selected client and tunnel are running.

6

Use and verify the assigned public URL

Record the public HTTPS URL assigned to the running tunnel and repeat the HTTP, matchmaking, room-join, and real-time communication tests from a device outside the host network.

HTTP process types provide the same content through a public HTTPS address, but their naming and DNS workflows differ. Exact custom-domain DNS instructions are not included because they must be checked against the current Localtonet documentation before configuration. For the initial test, use the public address assigned by the dashboard.

You can review the current product workflow in our Localtonet HTTP tunnel documentation. Use the dashboard’s current field labels and available relay choices rather than relying on old screenshots or hardcoded values.

Tunnel lifecycle matters

The public endpoint works only while the selected Localtonet client is connected and the tunnel is running. Colyseus must also remain active and reachable at the configured local target. Creating the tunnel alone does not start it, and stopping either process interrupts active sessions.

Point Colyseus clients at the public endpoint

Colyseus clients use localhost for local tests and the secure public endpoint for remote connections.
Remote clients use the assigned public host and a secure WebSocket connection.

After remote verification, replace the local development base endpoint in your test client with the public HTTPS URL assigned to the Localtonet HTTP tunnel. The official Colyseus examples initialize supported clients with a server endpoint and then call a matchmaking operation such as joinOrCreate using a registered room name.

A JavaScript or TypeScript client follows this general pattern:

import { Client } from "@colyseus/sdk";

const client = new Client("https://your-assigned-public-host");
const room = await client.joinOrCreate("your_registered_room");

Replace both placeholders with values from your deployment. The host must be the public URL assigned to your running tunnel, and the room name must exactly match a room registered by your server. Do not publish a private dashboard URL, Localtonet device token, or administrative credential in client code.

Colyseus provides SDKs for multiple engines and platforms. Endpoint syntax can differ. For example, some SDK examples accept an HTTPS server URL, while another may show a secure WebSocket URL. Follow the current SDK documentation for the exact client you ship. Do not mechanically convert schemes or append guessed paths.

Test from a network genuinely outside the server’s LAN, such as a separate internet connection. Verify all of the following:

  • The client reaches the public endpoint without using the private LAN address.
  • The intended matchmaking request completes.
  • The player joins the expected room.
  • The WebSocket connection remains open during normal gameplay.
  • Messages or player inputs reach the server.
  • Authorized state updates return to every expected client.
  • Disconnect and reconnect behavior matches the game’s design.

Browser clients may also be subject to browser security rules associated with origins, cookies, authentication, and mixed content. If the web page itself is loaded over HTTPS, use the secure public endpoint appropriate to the SDK rather than attempting an insecure connection from that page. Configure application-level origin and credential behavior deliberately if your architecture requires it.

Operate the server safely

A reachable prototype and a dependable multiplayer service have different operational requirements. Localtonet supplies public connectivity to the local target, but it does not replace application security, deployment discipline, or capacity planning.

Protect identities and secrets

Keep the Localtonet device token on the tunnel host. Keep database credentials, signing keys, administrative credentials, and private service URLs on the server side. Public game clients must contain only information they are expected to reveal, including the public game endpoint.

Authenticate players when the game requires identity. Authorize room joins using server-side information rather than trusting a client-supplied role or player identifier. Validate message types, value ranges, movement rates, ownership, and state transitions. The authoritative model is useful only when the authoritative server rejects invalid input.

Separate development and production access

Do not expose source maps, debug routes, playgrounds, monitors, profilers, or administrative consoles to ordinary players. If operational access is necessary, protect it with the controls supported by your selected Colyseus version and application architecture. Colyseus 0.18 includes guard options for monitor and playground usage and a basic authentication middleware for HTTP routes, but those capabilities still require deliberate configuration.

Plan process continuity

Both Colyseus and the Localtonet client must remain running. A closed terminal, operating system restart, sleeping laptop, lost network connection, or stopped tunnel can disconnect players. For a persistent deployment, use operating system facilities or a process manager that is suitable for your environment. The supplied evidence does not establish one required process manager or a universal service file, so those commands are intentionally not guessed here.

Define how deployments handle active rooms. Abruptly stopping the process interrupts WebSocket sessions and may lose in-memory game state. If your application needs persistence, implement and test it according to the game’s requirements. Colyseus 0.18 includes an official database package built on Drizzle ORM for SQLite or PostgreSQL use cases, but adopting it is an application architecture decision rather than a prerequisite for this basic tunnel workflow.

Monitor the complete path

Observe application exceptions, room creation failures, rejected joins, connection counts, memory, CPU, and event-loop behavior. Also monitor whether the Localtonet device and tunnel remain connected. These are different failure domains. A connected tunnel cannot make an exited Colyseus process healthy, while a healthy local server is not publicly reachable when the tunnel is stopped.

When updating Colyseus, read the migration notes for the target release. Version 0.18 includes breaking changes such as a maximum of 63 fields in a Schema, replacement behavior for metadata setters, removal of client.id in favor of client.sessionId, and authentication migration considerations. Test client SDK compatibility, serialized state, room behavior, and reconnection before updating a live deployment.

Troubleshooting Colyseus and Localtonet

Symptom Likely area What to check
npm create or npm start fails Local Node.js environment Confirm Node.js and npm availability, terminal permissions, dependency installation output, generated scripts, and the first reported error.
The server starts but the expected page is absent Application route assumption Use a route actually defined by the generated project. Do not assume that the root path is a readiness endpoint.
Local HTTP works but room joining fails Colyseus application configuration Check the registered room name, client SDK compatibility, join options, server exceptions, and room authorization logic.
Local access works only on the Colyseus host Listening interface or local network reachability If Localtonet runs elsewhere, confirm that Colyseus listens on an appropriate interface and that the Localtonet device can reach the target directly.
The public URL does not respond Tunnel lifecycle or target mapping Confirm that Colyseus is running, the Localtonet client is connected, the HTTP tunnel is started, and its local IP and port exactly match the verified endpoint.
HTTP responds but WebSocket gameplay fails Client endpoint or protocol workflow Check the browser or SDK error, endpoint scheme, room name, WebSocket upgrade result, application logs, and whether the client appended a guessed path.
Players disconnect after the host is idle Host or process continuity Check system sleep, terminal closure, process exits, Localtonet client status, tunnel status, and local network interruptions.
A new release breaks room behavior Version migration Restore the tested lockfile if appropriate, review migration notes, compare server and SDK versions, and test documented breaking changes before redeployment.

Use a layered diagnosis

Start on the Colyseus host. Confirm that the process is alive and repeat the known local client test. If that fails, the tunnel is not the cause. Fix the application, dependencies, room registration, or local endpoint first.

Next, test the same endpoint from the device running Localtonet if it is a separate machine. If that fails, correct local reachability or the Colyseus listening interface. Only after both local tests pass should you inspect the Localtonet client connection, tunnel status, relay selection, and target mapping.

Finally, test from an external client and compare timestamps across the client, Colyseus logs, and Localtonet status. If no request reaches Colyseus, focus on the endpoint and tunnel path. If Colyseus receives the request and rejects it, focus on room names, authentication, authorization, SDK compatibility, and application exceptions.

Do not solve reachability by disabling security controls broadly

Avoid turning off host protections, exposing every listening interface, removing room authorization, or publishing administrative routes merely to make a test pass. Isolate the failing layer and apply the narrowest configuration change required for the intended game endpoint.

Frequently asked questions

Which port does Colyseus use by default?

The evidence supplied for this guide does not establish a universal Colyseus port for the current project generator. Read the output from npm start and inspect the generated project configuration. Use that verified port as the Localtonet HTTP tunnel target instead of copying a number from another installation.

Why use a Localtonet HTTP tunnel rather than a raw TCP tunnel?

This Colyseus workflow uses HTTP-based interactions and WebSocket connections. An HTTP tunnel provides a public HTTPS address for that web-oriented service. A raw TCP tunnel is intended for services that need direct public host-and-port forwarding rather than the HTTP and WebSocket endpoint described here.

Do I need router port forwarding or a public IP address?

No. The Localtonet client establishes an outbound connection to our relay server. This allows the public tunnel to reach the configured local Colyseus target without inbound router port forwarding, firewall changes, VPN setup, or a public IP address.

Does starting Colyseus automatically start the Localtonet tunnel?

No. They are separate processes. Colyseus must be running at the configured local target, the Localtonet client must be connected, and the tunnel must be started. Creating a tunnel configuration does not automatically make it active.

Is opening the public URL enough to prove the game server works?

No. It proves only that some HTTP behavior is reachable. Use a compatible Colyseus client to perform matchmaking, join a registered room, maintain the WebSocket connection, send an expected message or input, and receive a response or synchronized state update.

Can the Localtonet client run on another machine?

Yes, provided that machine can reach the Colyseus IP address and port over the local network. Test that path directly before creating the tunnel. A Colyseus service bound only to loopback on another host will not be reachable from the Localtonet device.

Does Localtonet secure player accounts and room permissions?

Localtonet provides the public connection to the local service. Your Colyseus application remains responsible for player authentication, authorization, room access, message validation, abuse controls, and administrative security. Do not treat tunnel reachability as permission to use the game service.

Will the public game endpoint remain available if the host sleeps?

No. The endpoint depends on the Colyseus process, host network, Localtonet client, and running tunnel. Sleep, shutdown, process termination, or loss of connectivity can interrupt active sessions. Use an appropriate always-on host and process supervision strategy for persistent deployments.

Make your verified Colyseus server reachable with Localtonet

Start the Localtonet client on the device that can reach Colyseus, create an HTTP tunnel to the verified local IP address and port, and test the assigned public endpoint with your real game client.

Get Started Free →

Localtonet is a secure multi-protocol tunneling and proxy platform designed to expose localhost, devices, private services, and AI agents to the public internet supporting HTTP/HTTPS tunnels, TCP/UDP forwarding, mobile proxy infrastructure, file server publishing, latency-optimized game connectivity, and developer-ready AI agent endpoint exposure from a single unified control plane.

support