Deployment

Deploying your Colyseus server

Deploying Colyseus is no different than deploying a regular Node.js application. See DigitalOcean’s guide for the general setup. Scaling to multiple processes or machines requires extra steps. See Scalability.

⚠️

Consider using Colyseus Cloud to deploy and scale your Colyseus servers. Every item on the checklist below is handled for you.

Production checklist

  • Compile your TypeScript: run tsc at deploy time and start the compiled entrypoint with plain node. The official template compiles to build/index.js. Do not run tsx/ts-node in production (why).
  • Set NODE_ENV=production: dependencies and error verbosity behave accordingly, and server.simulateLatency() must never run in production.
  • Run under a process manager: PM2 restarts crashed processes and plays well with Colyseus:
ecosystem.config.js
const os = require('os');
 
module.exports = {
    apps: [{
        name: "colyseus-app",
        script: 'build/index.js',
        time: true,
        watch: false,
        instances: os.cpus().length,
        exec_mode: 'fork',        // IMPORTANT: DO NOT use 'cluster' mode.
        wait_ready: true,
    }],
};
  • Serve over HTTPS: put a reverse proxy in front (Nginx or Apache below) with a certificate from Let’s Encrypt. The SDK connects via https:// and upgrades to secure WebSockets (wss://) automatically.
  • Let deploys drain gracefully: Colyseus registers a graceful shutdown routine on SIGTERM/SIGINT: rooms are notified, clients receive SERVER_SHUTDOWN (4001), and the process exits when empty.
  • Expose a health check: a plain HTTP route returning 200 lets your load balancer or uptime monitor probe each process.
  • More than one process or machine?: you need a shared presence and driver, and a public address per process. Follow Scalability.

Self-hosting on Vultr

A pre-configured Colyseus server is available on Vultr Marketplace. It’s a good option if you want to self-host your Colyseus server.

This server is configured with:

  • Node.js LTS
  • PM2
  • Nginx
  • FREE colyseus.dev subdomain with SSL (Let’s Encrypt)

Follow the instructions at Vultr Marketplace to start your server.


Nginx configuration

When self-hosting, it is recommended to use nginx and pm2 in your production environment.

Nginx configuration

/etc/nginx/sites-available/yourdomain.com
server {
    listen 80;
    server_name yourdomain.com;

    location / {
        proxy_pass http://localhost:2567;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        proxy_set_header Host $host;
        proxy_cache_bypass $http_upgrade;
        proxy_read_timeout 86400s;
        proxy_send_timeout 86400s;
        include proxy_params;
    }
}

Nginx configuration with SSL

It’s recommended to acquire your certificate from LetsEncrypt.

/etc/nginx/sites-available/yourdomain.com
server {
    listen 80;
    listen 443 ssl;
    server_name yourdomain.com;

    ssl_certificate /path/to/your/cert.crt;
    ssl_certificate_key /path/to/your/cert.key;

    location / {
        proxy_pass http://localhost:2567;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        proxy_set_header Host $host;
        proxy_cache_bypass $http_upgrade;
        proxy_read_timeout 86400s;
        proxy_send_timeout 86400s;
        include proxy_params;
    }
}

Sticky sessions are not required: the seat reservation already binds each client to the process that created its room. For proxying multiple processes, see Scalability → NGINX or the Traefik Load Balancer.


Apache configuration

Here’s how to use Apache as a proxy to your Node.js Colyseus app. (Thanks tomkleine!)

Install the required Apache modules:

Terminal
sudo a2enmod ssl
sudo a2enmod proxy
sudo a2enmod proxy_http
sudo a2enmod proxy_html
sudo a2enmod proxy_wstunnel

Virtual host configuration:

/etc/apache2/sites-available/yourdomain.com.conf
<VirtualHost *:80>
    ServerName servername.xyz
    # Redirect all requests received from port 80 to the HTTPS variant (force ssl)
    RewriteEngine On
    RewriteRule ^(.*)$ https://%{HTTP_HOST}$1 [R=301,L]
</VirtualHost>

<VirtualHost *:443>
    ServerName servername.xyz

    # enable SSL
    SSLEngine On
    SSLCertificateFile          /PATH/TO/CERT/FILE
    SSLCertificateKeyFile       /PATH/TO/PRIVATE/KEY/FILE

    #
    # setup the proxy to forward websocket requests properly to a normal websocket
    # and vice versa, so there's no need to change the colyseus library or the
    # server for that matter
    #
    # note: this proxy automatically converts the secure websocket (wss)

    RewriteEngine On
    RewriteCond %{HTTP:UPGRADE} ^WebSocket$           [NC,OR]
    RewriteCond %{HTTP:CONNECTION} ^Upgrade$          [NC]
    RewriteRule .* ws://127.0.0.1:APP-PORT-HERE%{REQUEST_URI}  [P,QSA,L]

    # setup the proxy to forward all https requests to http backend
    # (also automatic conversion from https to http and vice versa)

    ProxyPass "/" "http://localhost:APP-PORT-HERE/"
    ProxyPassReverse "/" "http://localhost:APP-PORT-HERE/"

</VirtualHost>

Docker

Requirements

  • Download and install Docker
  • package.json and package-lock.json are in the project.
  • Set up the npm start command so it starts the server

Create Dockerfile in the root of the Colyseus project

Dockerfile
FROM node:22
 
ENV PORT 2567
 
WORKDIR /usr/src/app
 
# A wildcard is used to ensure both package.json AND package-lock.json are copied
COPY package*.json ./
 
RUN npm ci
# run this for production
# npm ci --only=production
 
COPY . .
 
EXPOSE 2567
 
CMD [ "npm", "start" ]

Create .dockerignore file in the same directory

.dockerignore
node_modules
npm-debug.log

This will prevent your local modules and debug logs from being copied onto your Docker image and possibly overwriting modules installed within your image.

Build Docker Image

Go to the directory that has your Dockerfile and run the following command to build the Docker image. The -t flag lets you tag your image so it’s easier to find later using the docker images command:

Terminal
docker build -t <your username>/colyseus-server .

Confirm Image Build

Your image will now be listed by Docker with following command:

Terminal
docker images

Output:

# Example
REPOSITORY                         TAG        ID              CREATED
node                               22         1934b0b038d1    About a minute ago
<your username>/colyseus-server    latest     d64d3505b0d2    About a minute ago

Run the Docker Image

Run the Docker Image with following command:

Terminal
docker run -p 2567:2567 -d <your username>/colyseus-server

Running your image with -d runs the container in detached mode, leaving the container running in the background. The -p flag redirects a public port to a private port inside the container.

Done

Done, now you can connect to the server with localhost:2567

More information: