Skip to content

speedvoltage/motd

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

3 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

320_13

hl2dm-motd

hl2dm-motd is a Node.js/TypeScript daemon for Half-Life 2: Deathmatch server integration.

It sits between:

  • the SRCDS plugin over WebSocket,
  • MySQL persistence,
  • the in-game MOTD browser UI,
  • MOTD API endpoints used by the UI.

The service handles MOTD session verification, player settings sync, stats/ranks, admin actions, ban workflows, achievements, GeoIP lookups, demo metadata, and demo uploads.


Requirements

  • Node.js 18+
  • pnpm 10+
  • MySQL 8+ or compatible
  • An SRCDS plugin configured to connect to this daemon

Basic setup

Install dependencies:

pnpm install

Create a local environment file:

cp .env.example .env

Edit .env for your server. Do not commit .env.

Run the development server:

pnpm --filter @hl2dm/motd-server run dev

Build the server package:

pnpm --filter @hl2dm/motd-server run build

Start the built server:

pnpm --filter @hl2dm/motd-server run start

Required environment variables

These must be set for a real deployment:

  • DB_HOST — MySQL host. Use 127.0.0.1 instead of localhost if your MySQL server only listens on IPv4.
  • DB_PORT — MySQL port, usually 3306.
  • DB_USER — MySQL user.
  • DB_PASS — MySQL password.
  • DB_NAME — MySQL database name.
  • SRCDS_WS_SECRET — shared secret used by the SRCDS WebSocket client. This must match the SRCDS-side websocket_secret.
  • STEAM_API_KEY — Steam Web API key used for Steam profile lookups.

Optional environment variables

Common optional settings:

  • NODE_ENV — set to production for production deployments.
  • SERVER_PORT — HTTP listen port. Default: 4000.
  • PUBLIC_URL — public base URL for generated links.
  • TRUST_PROXY — set to 1 when the service is behind a trusted reverse proxy. Default: 1.
  • VERIFY_TOKEN_TIMEOUT_MS — timeout for MOTD token verification through SRCDS. Default: 8000.
  • MAP_TRANSITION_RECONNECT_GRACE_SECONDS — reconnect grace window for map changes. Default: 600.
  • WEAPON_POINTS_JSON — weapon scoring configuration.
  • AZURE_TRANSLATOR_KEY, AZURE_TRANSLATOR_REGION, AZURE_TRANSLATOR_ENDPOINT — Azure Translator configuration.
  • WS_DEBUG, WS_DEBUG_PAYLOADS, WS_DEBUG_LARGE_MESSAGE_BYTES — WebSocket diagnostics.
  • SRCDS_WS_MAX_PAYLOAD_BYTES — maximum accepted SRCDS WebSocket message size. Default: 65536.

Security-sensitive environment variables

Treat these as secrets or production safety switches:

  • SRCDS_WS_SECRET — must be long, private, and match the SRCDS plugin configuration.
  • DEMO_UPLOAD_TOKEN — required for demo upload and demo metadata endpoints. If this is missing, demo upload requests fail closed.
  • MOTD_BROWSER_DEBUG_TOKEN — required when MOTD_BROWSER_DEBUG=1; must be at least 32 characters.
  • MOTD_BROWSER_DEBUG — must stay 0 in production.
  • MOTD_BROWSER_DEBUG_ALLOW_REMOTE — must stay 0 unless you intentionally accept the risk of remote browser-debug access.
  • DB_PASS, STEAM_API_KEY, AZURE_TRANSLATOR_KEY — private credentials.

.env.example must contain examples only. Do not put real secrets or reusable default tokens in it.


GeoIP database setup

GeoIP support uses MaxMind GeoLite2 database files through the maxmind package.

Real .mmdb files are not included in this repository and must not be committed. Download GeoLite2 City and ASN databases through your own MaxMind account, place them in a private local path, and point the service at those files:

GEOIP_ENABLED=1
GEOIP_CITY_MMDB=/var/geoip/GeoLite2-City.mmdb
GEOIP_ASN_MMDB=/var/geoip/GeoLite2-ASN.mmdb

For development without GeoIP, leave:

GEOIP_ENABLED=0

The repository ignores *.mmdb and *.mmdb.gz files. Do not add MaxMind license keys, download URLs, or database files to the public repo.


Demo upload setup

Demo files are stored under:

DEMO_STORAGE_ROOT=/var/www/hl2dm-game.com

Demo upload and metadata endpoints require bearer-token authentication:

Authorization: Bearer <DEMO_UPLOAD_TOKEN>

Required behavior:

  • If DEMO_UPLOAD_TOKEN is unset, upload and metadata requests are rejected.
  • If the request has no bearer token, the request is rejected.
  • If the bearer token is wrong, the request is rejected.
  • If the bearer token is correct, the request can continue subject to file name, file type, and size checks.

Demo upload filenames are restricted to the existing intended demo formats:

  • .dem
  • .dem.bz2

Demo upload size is limited by:

DEMO_UPLOAD_MAX_BYTES=536870912

The default is 536870912 bytes, which is 512 MiB. Oversized binary uploads are rejected and the upload stream is stopped. Usually will not be a problem for demos.


Browser debug mode

Browser debug mode exists for local MOTD UI development only.

Keep this disabled in production:

MOTD_BROWSER_DEBUG=0

If you enable it locally, you must set a long random token:

MOTD_BROWSER_DEBUG=1
MOTD_BROWSER_DEBUG_TOKEN=<32-or-more-random-characters>
MOTD_BROWSER_DEBUG_ALLOW_REMOTE=0

Debug requests must provide the token as either:

x-motd-debug-token: <token>

or:

/motd/debug?debug_token=<token>

Safety rules enforced by the server:

  • MOTD_BROWSER_DEBUG=0 disables browser debug routes.
  • MOTD_BROWSER_DEBUG=1 with a missing or short token fails closed.
  • Browser debug requests are localhost-only by default.
  • Remote browser debug requests require MOTD_BROWSER_DEBUG_ALLOW_REMOTE=1 and the configured token.
  • Browser debug sessions cannot resolve admin capabilities.

Never enable browser debug mode on a public deployment.


SRCDS integration notes

From the SRCDS plugin side, ensure these values align with the daemon:

  • motd_server_idDEFAULT_SERVER_ID or the server_id passed in the MOTD URL.
  • websocket_secretSRCDS_WS_SECRET.
  • websocket_address points to ws://<daemon-host>:<port>/ws/srcds.

The daemon tracks active SRCDS connections by server_id and verifies MOTD sessions through the connected SRCDS instance.


Verification checklist

After configuring .env, run the available checks:

pnpm --filter @hl2dm/motd-server run build

If you add tests later, run them before publishing. This snapshot does not include a dedicated test script for the demo upload route.

Manual demo upload checks:

  • DEMO_UPLOAD_TOKEN unset + upload request => rejected.
  • DEMO_UPLOAD_TOKEN set + missing bearer token => rejected.
  • DEMO_UPLOAD_TOKEN set + wrong bearer token => rejected.
  • DEMO_UPLOAD_TOKEN set + correct bearer token => accepted, subject to .dem / .dem.bz2 and size checks.
  • Upload larger than DEMO_UPLOAD_MAX_BYTES => rejected.

Manual browser-debug checks:

  • MOTD_BROWSER_DEBUG=0 => /motd/debug returns disabled.
  • MOTD_BROWSER_DEBUG=1 with no token => rejected.
  • MOTD_BROWSER_DEBUG=1 with a short token => rejected.
  • MOTD_BROWSER_DEBUG=1 with a 32+ character token from localhost => accepted only when the request supplies the token.
  • Browser-debug sessions cannot use admin capabilities.

Public release checklist

If you clone this project without forking, then before open-sourcing:

  • Remove committed MaxMind .mmdb files from Git history, or publish from a fresh clean repository.
  • Confirm no .mmdb or .mmdb.gz files exist in the public repository.
  • Confirm .env is not committed.
  • Confirm .env.example contains no real secrets or reusable default tokens.
  • Confirm DEMO_UPLOAD_TOKEN is set if demo upload endpoints are exposed.
  • Confirm DEMO_UPLOAD_MAX_BYTES is configured for your deployment.
  • Confirm MOTD_BROWSER_DEBUG=0 in production.
  • Confirm MOTD_BROWSER_DEBUG_TOKEN is blank in production, or unused because debug mode is disabled.
  • Run a dependency audit locally.
  • Build/typecheck the project.

Important: removing .mmdb files from the working tree is not enough if the public repository keeps this Git history. Clean the history with a tool such as git filter-repo or publish from a fresh repository that never contained the database files.


Troubleshooting

SRCDS not connecting

  • Confirm websocket_address is reachable from the game server host.
  • Confirm SRCDS_WS_SECRET matches the SRCDS websocket_secret.
  • Check daemon logs for WebSocket auth rejection.

MOTD says not in game or session mismatch

  • Ensure the MOTD URL includes the current remoteId from the latest WebSocket hello.
  • Ensure server_id matches an active SRCDS connection.

DB init fails with ::1:3306

This means the MySQL client attempted IPv6 loopback while MySQL likely listens only on IPv4.

Use:

DB_HOST=127.0.0.1

or configure MySQL to listen on IPv6 too.


License

Nothing special.

About

A modular, interactive MOTD menu system for HL2DM servers with SRCDS interoperability. Acts as a central system for HL2DM, allowing multiple servers to connect to a unified configuration. Handles persistent client data (settings, ranks, statistics), structured database communication, and integrates external services such as MaxMind GeoIP.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors