@babylonjs-toolkit/server 0.0.0-stage → 9.35.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CUSTOM.md +1690 -0
- package/DEPLOY.md +2012 -0
- package/README.md +1081 -2
- package/lib/AbuseLimits.d.ts +64 -0
- package/lib/AbuseLimits.js +121 -0
- package/lib/Authentication.d.ts +86 -0
- package/lib/Authentication.js +272 -0
- package/lib/BootSessionOwner.d.ts +86 -0
- package/lib/BootSessionOwner.js +116 -0
- package/lib/ColyseusLoggerAdapter.d.ts +32 -0
- package/lib/ColyseusLoggerAdapter.js +73 -0
- package/lib/DedicatedSceneRegistry.d.ts +52 -0
- package/lib/DedicatedSceneRegistry.js +74 -0
- package/lib/DedicatedSession.d.ts +152 -0
- package/lib/DedicatedSession.js +173 -0
- package/lib/DualTransport.d.ts +112 -0
- package/lib/DualTransport.js +197 -0
- package/lib/GameServer.d.ts +64 -0
- package/lib/GameServer.js +647 -0
- package/lib/GameServerConfig.d.ts +387 -0
- package/lib/GameServerConfig.js +1059 -0
- package/lib/GameServerLobbyRoom.d.ts +33 -0
- package/lib/GameServerLobbyRoom.js +56 -0
- package/lib/GameServerLogger.d.ts +111 -0
- package/lib/GameServerLogger.js +190 -0
- package/lib/GameServerMetrics.d.ts +158 -0
- package/lib/GameServerMetrics.js +276 -0
- package/lib/GameServerState.d.ts +164 -0
- package/lib/GameServerState.js +26 -0
- package/lib/HeadlessRuntime.d.ts +316 -0
- package/lib/HeadlessRuntime.js +380 -0
- package/lib/JoinGate.d.ts +34 -0
- package/lib/JoinGate.js +221 -0
- package/lib/NetworkAddresses.d.ts +33 -0
- package/lib/NetworkAddresses.js +90 -0
- package/lib/PlayerTokens.d.ts +17 -0
- package/lib/PlayerTokens.js +24 -0
- package/lib/RoomServerTransport.d.ts +73 -0
- package/lib/RoomServerTransport.js +90 -0
- package/lib/ServerEndpoints.d.ts +133 -0
- package/lib/ServerEndpoints.js +247 -0
- package/lib/ServerInit.d.ts +28 -0
- package/lib/ServerInit.js +113 -0
- package/lib/SessionRoom.d.ts +391 -0
- package/lib/SessionRoom.js +930 -0
- package/lib/TlsCertificates.d.ts +35 -0
- package/lib/TlsCertificates.js +130 -0
- package/lib/admin/AccountRoutes.d.ts +8 -0
- package/lib/admin/AccountRoutes.js +502 -0
- package/lib/admin/AdminAccounts.d.ts +329 -0
- package/lib/admin/AdminAccounts.js +607 -0
- package/lib/admin/AdminApiRouter.d.ts +202 -0
- package/lib/admin/AdminApiRouter.js +465 -0
- package/lib/admin/AdminApiTypes.d.ts +1782 -0
- package/lib/admin/AdminApiTypes.js +4 -0
- package/lib/admin/AdminAudit.d.ts +113 -0
- package/lib/admin/AdminAudit.js +266 -0
- package/lib/admin/AdminCli.d.ts +7 -0
- package/lib/admin/AdminCli.js +351 -0
- package/lib/admin/AdminClock.d.ts +51 -0
- package/lib/admin/AdminClock.js +10 -0
- package/lib/admin/AdminConsole.d.ts +39 -0
- package/lib/admin/AdminConsole.js +325 -0
- package/lib/admin/AdminConstants.d.ts +147 -0
- package/lib/admin/AdminConstants.js +167 -0
- package/lib/admin/AdminCrypto.d.ts +19 -0
- package/lib/admin/AdminCrypto.js +29 -0
- package/lib/admin/AdminExtensionsHost.d.ts +176 -0
- package/lib/admin/AdminExtensionsHost.js +307 -0
- package/lib/admin/AdminPasswords.d.ts +33 -0
- package/lib/admin/AdminPasswords.js +92 -0
- package/lib/admin/AdminPermissions.d.ts +28 -0
- package/lib/admin/AdminPermissions.js +74 -0
- package/lib/admin/AdminRecords.d.ts +196 -0
- package/lib/admin/AdminRecords.js +3 -0
- package/lib/admin/AdminRequestBodies.d.ts +47 -0
- package/lib/admin/AdminRequestBodies.js +84 -0
- package/lib/admin/AdminRequestGate.d.ts +38 -0
- package/lib/admin/AdminRequestGate.js +59 -0
- package/lib/admin/AdminResponses.d.ts +103 -0
- package/lib/admin/AdminResponses.js +164 -0
- package/lib/admin/AdminServices.d.ts +99 -0
- package/lib/admin/AdminServices.js +4 -0
- package/lib/admin/AdminStaticFiles.d.ts +29 -0
- package/lib/admin/AdminStaticFiles.js +97 -0
- package/lib/admin/AdminStore.d.ts +152 -0
- package/lib/admin/AdminStore.js +46 -0
- package/lib/admin/AlertChannels.d.ts +43 -0
- package/lib/admin/AlertChannels.js +120 -0
- package/lib/admin/AlertEngine.d.ts +231 -0
- package/lib/admin/AlertEngine.js +681 -0
- package/lib/admin/AlertRoutes.d.ts +8 -0
- package/lib/admin/AlertRoutes.js +180 -0
- package/lib/admin/ApiKeyRoutes.d.ts +8 -0
- package/lib/admin/ApiKeyRoutes.js +53 -0
- package/lib/admin/ApiKeys.d.ts +63 -0
- package/lib/admin/ApiKeys.js +167 -0
- package/lib/admin/AuditRoutes.d.ts +8 -0
- package/lib/admin/AuditRoutes.js +106 -0
- package/lib/admin/AuthToolRoutes.d.ts +13 -0
- package/lib/admin/AuthToolRoutes.js +164 -0
- package/lib/admin/BanList.d.ts +87 -0
- package/lib/admin/BanList.js +152 -0
- package/lib/admin/CborDecoder.d.ts +18 -0
- package/lib/admin/CborDecoder.js +201 -0
- package/lib/admin/ColyseusCloudClient.d.ts +313 -0
- package/lib/admin/ColyseusCloudClient.js +272 -0
- package/lib/admin/ColyseusCloudRoutes.d.ts +8 -0
- package/lib/admin/ColyseusCloudRoutes.js +91 -0
- package/lib/admin/ColyseusCloudService.d.ts +180 -0
- package/lib/admin/ColyseusCloudService.js +476 -0
- package/lib/admin/ColyseusCloudSettings.d.ts +16 -0
- package/lib/admin/ColyseusCloudSettings.js +29 -0
- package/lib/admin/ColyseusCloudViews.d.ts +105 -0
- package/lib/admin/ColyseusCloudViews.js +371 -0
- package/lib/admin/CommonPasswords.d.ts +6 -0
- package/lib/admin/CommonPasswords.js +19 -0
- package/lib/admin/ConfigOverrides.d.ts +174 -0
- package/lib/admin/ConfigOverrides.js +406 -0
- package/lib/admin/ConfigRoutes.d.ts +8 -0
- package/lib/admin/ConfigRoutes.js +91 -0
- package/lib/admin/ConsoleSessions.d.ts +112 -0
- package/lib/admin/ConsoleSessions.js +201 -0
- package/lib/admin/DedicatedRoutes.d.ts +21 -0
- package/lib/admin/DedicatedRoutes.js +254 -0
- package/lib/admin/ExtensionRoutes.d.ts +8 -0
- package/lib/admin/ExtensionRoutes.js +145 -0
- package/lib/admin/FileAdminStore.d.ts +157 -0
- package/lib/admin/FileAdminStore.js +349 -0
- package/lib/admin/FleetDirectory.d.ts +323 -0
- package/lib/admin/FleetDirectory.js +489 -0
- package/lib/admin/FleetLeader.d.ts +43 -0
- package/lib/admin/FleetLeader.js +89 -0
- package/lib/admin/FleetRoutes.d.ts +55 -0
- package/lib/admin/FleetRoutes.js +465 -0
- package/lib/admin/HealthWarnings.d.ts +10 -0
- package/lib/admin/HealthWarnings.js +95 -0
- package/lib/admin/LeaderboardRoutes.d.ts +8 -0
- package/lib/admin/LeaderboardRoutes.js +569 -0
- package/lib/admin/LogBuffer.d.ts +60 -0
- package/lib/admin/LogBuffer.js +92 -0
- package/lib/admin/LogRedaction.d.ts +15 -0
- package/lib/admin/LogRedaction.js +72 -0
- package/lib/admin/LogRoutes.d.ts +45 -0
- package/lib/admin/LogRoutes.js +307 -0
- package/lib/admin/MaintenanceMode.d.ts +41 -0
- package/lib/admin/MaintenanceMode.js +74 -0
- package/lib/admin/MaintenanceWindows.d.ts +91 -0
- package/lib/admin/MaintenanceWindows.js +207 -0
- package/lib/admin/MetricsRoutes.d.ts +8 -0
- package/lib/admin/MetricsRoutes.js +209 -0
- package/lib/admin/MetricsSampler.d.ts +124 -0
- package/lib/admin/MetricsSampler.js +211 -0
- package/lib/admin/OneTimeCodes.d.ts +60 -0
- package/lib/admin/OneTimeCodes.js +162 -0
- package/lib/admin/OpenIdConnect.d.ts +146 -0
- package/lib/admin/OpenIdConnect.js +335 -0
- package/lib/admin/Passkeys.d.ts +130 -0
- package/lib/admin/Passkeys.js +432 -0
- package/lib/admin/PlayerRoutes.d.ts +20 -0
- package/lib/admin/PlayerRoutes.js +676 -0
- package/lib/admin/RedisAdminStore.d.ts +114 -0
- package/lib/admin/RedisAdminStore.js +258 -0
- package/lib/admin/RolloutCoordinator.d.ts +99 -0
- package/lib/admin/RolloutCoordinator.js +321 -0
- package/lib/admin/ServerEvents.d.ts +57 -0
- package/lib/admin/ServerEvents.js +89 -0
- package/lib/admin/SessionRoutes.d.ts +113 -0
- package/lib/admin/SessionRoutes.js +386 -0
- package/lib/admin/UserRoutes.d.ts +8 -0
- package/lib/admin/UserRoutes.js +214 -0
- package/lib/cli.d.ts +2 -0
- package/lib/cli.js +221 -0
- package/lib/console/assets/index-CI5N7c-T.js +21 -0
- package/lib/console/assets/index-DPitvzLp.css +1 -0
- package/lib/console/favicon.svg +1 -0
- package/lib/console/index.html +16 -0
- package/lib/discord/DiscordOAuth.d.ts +57 -0
- package/lib/discord/DiscordOAuth.js +127 -0
- package/lib/discord/DiscordSessions.d.ts +79 -0
- package/lib/discord/DiscordSessions.js +135 -0
- package/lib/discord/DiscordSignInConstants.d.ts +54 -0
- package/lib/discord/DiscordSignInConstants.js +55 -0
- package/lib/discord/DiscordSignInRoutes.d.ts +51 -0
- package/lib/discord/DiscordSignInRoutes.js +359 -0
- package/lib/index.d.ts +24 -0
- package/lib/index.js +18 -0
- package/lib/leaderboards/FileLeaderboardRankStore.d.ts +293 -0
- package/lib/leaderboards/FileLeaderboardRankStore.js +808 -0
- package/lib/leaderboards/LeaderboardConstants.d.ts +63 -0
- package/lib/leaderboards/LeaderboardConstants.js +70 -0
- package/lib/leaderboards/LeaderboardError.d.ts +15 -0
- package/lib/leaderboards/LeaderboardError.js +20 -0
- package/lib/leaderboards/LeaderboardIdentity.d.ts +44 -0
- package/lib/leaderboards/LeaderboardIdentity.js +72 -0
- package/lib/leaderboards/LeaderboardPublicApi.d.ts +17 -0
- package/lib/leaderboards/LeaderboardPublicApi.js +389 -0
- package/lib/leaderboards/LeaderboardRankStore.d.ts +296 -0
- package/lib/leaderboards/LeaderboardRankStore.js +18 -0
- package/lib/leaderboards/LeaderboardRules.d.ts +122 -0
- package/lib/leaderboards/LeaderboardRules.js +472 -0
- package/lib/leaderboards/LeaderboardScheduler.d.ts +43 -0
- package/lib/leaderboards/LeaderboardScheduler.js +103 -0
- package/lib/leaderboards/LeaderboardService.d.ts +669 -0
- package/lib/leaderboards/LeaderboardService.js +1667 -0
- package/lib/leaderboards/LeaderboardTransfer.d.ts +35 -0
- package/lib/leaderboards/LeaderboardTransfer.js +580 -0
- package/lib/leaderboards/RedisLeaderboardRankStore.d.ts +282 -0
- package/lib/leaderboards/RedisLeaderboardRankStore.js +691 -0
- package/package.json +64 -4
- package/templates/init/Caddyfile +6 -0
- package/templates/init/DEPLOY.md +233 -0
- package/templates/init/Dockerfile +12 -0
- package/templates/init/app.json +21 -0
- package/templates/init/aws/README.md +118 -0
- package/templates/init/aws/ecs-fargate-alb.yml +207 -0
- package/templates/init/aws/ecs-fargate-nlb-quic.yml +210 -0
- package/templates/init/babylon-game-server.config.mjs +158 -0
- package/templates/init/colyseus-cloud/README.md +133 -0
- package/templates/init/colyseus-cloud/babylon-game-server.config.mjs +36 -0
- package/templates/init/colyseus-cloud/ecosystem.config.cjs +35 -0
- package/templates/init/colyseus-cloud/gitignore +6 -0
- package/templates/init/colyseus-cloud/package.json +15 -0
- package/templates/init/digitalocean-app.yaml +30 -0
- package/templates/init/docker-compose.full.yml +45 -0
- package/templates/init/docker-compose.websocket.yml +41 -0
- package/templates/init/fly.toml +56 -0
- package/templates/init/heroku.yml +11 -0
- package/templates/init/kubernetes/deployment.yaml +71 -0
- package/templates/init/kubernetes/redis.yaml +73 -0
- package/templates/init/kubernetes/service.yaml +24 -0
- package/templates/init/monitoring/grafana-dashboard.json +539 -0
- package/templates/init/monitoring/prometheus-alerts.yml +51 -0
- package/templates/init/monitoring/prometheus-scrape.yml +17 -0
- package/templates/init/railway.json +13 -0
- package/templates/init/render.yaml +19 -0
package/package.json
CHANGED
|
@@ -1,6 +1,66 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@babylonjs-toolkit/server",
|
|
3
|
-
"version": "
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
3
|
+
"version": "9.35.0",
|
|
4
|
+
"description": "Babylon Game Server — the multiplayer session server for Babylon Toolkit games",
|
|
5
|
+
"author": "MackeyK24 <mackeyk24@gmail.com>",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"main": "lib/index.js",
|
|
8
|
+
"types": "lib/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": "./lib/index.js"
|
|
11
|
+
},
|
|
12
|
+
"bin": {
|
|
13
|
+
"babylon-game-server": "lib/cli.js"
|
|
14
|
+
},
|
|
15
|
+
"files": [
|
|
16
|
+
"lib",
|
|
17
|
+
"templates",
|
|
18
|
+
"README.md",
|
|
19
|
+
"DEPLOY.md",
|
|
20
|
+
"CUSTOM.md"
|
|
21
|
+
],
|
|
22
|
+
"engines": {
|
|
23
|
+
"node": ">=22"
|
|
24
|
+
},
|
|
25
|
+
"scripts": {
|
|
26
|
+
"build": "npm run build:server && npm run build:console",
|
|
27
|
+
"build:server": "tsc -p tsconfig.json",
|
|
28
|
+
"build:console": "vite build --config console/vite.config.ts",
|
|
29
|
+
"check:console": "tsc -p console/tsconfig.json",
|
|
30
|
+
"start": "node lib/cli.js",
|
|
31
|
+
"test": "npm run build && node scripts/run-server-tests.mjs",
|
|
32
|
+
"prepack": "npm run build && node scripts/release-manifest.mjs apply",
|
|
33
|
+
"postpack": "node scripts/release-manifest.mjs restore",
|
|
34
|
+
"release:publish": "npm publish --access public",
|
|
35
|
+
"release:image": "cd .. && docker buildx build --platform linux/amd64,linux/arm64 -f SVR/Dockerfile -t ghcr.io/mackeyk24/babylon-game-server:$npm_package_version -t mackeyk24/babylon-game-server:$npm_package_version --push ."
|
|
36
|
+
},
|
|
37
|
+
"dependencies": {
|
|
38
|
+
"@babylonjs/havok": "1.3.14",
|
|
39
|
+
"@colyseus/ws-transport": "0.18.4",
|
|
40
|
+
"babylonjs": "9.35.0",
|
|
41
|
+
"babylonjs-gui": "9.35.0",
|
|
42
|
+
"babylonjs-loaders": "9.35.0",
|
|
43
|
+
"babylonjs-toolkit": "9.35.0",
|
|
44
|
+
"colyseus": "0.18.9",
|
|
45
|
+
"express": "5.3.0",
|
|
46
|
+
"ioredis": "5.11.1",
|
|
47
|
+
"jose": "6.2.12",
|
|
48
|
+
"prom-client": "15.1.3"
|
|
49
|
+
},
|
|
50
|
+
"devDependencies": {
|
|
51
|
+
"@colyseus/sdk": "0.18.5",
|
|
52
|
+
"@fails-components/webtransport": "1.6.2",
|
|
53
|
+
"@types/node": "22.15.3",
|
|
54
|
+
"@types/react": "19.3.0",
|
|
55
|
+
"@types/react-dom": "19.3.0",
|
|
56
|
+
"@vitejs/plugin-react": "6.1.2",
|
|
57
|
+
"qrcode-generator": "1.4.4",
|
|
58
|
+
"react": "19.3.0",
|
|
59
|
+
"react-dom": "19.3.0",
|
|
60
|
+
"typescript": "6.0.3",
|
|
61
|
+
"vite": "8.3.1"
|
|
62
|
+
},
|
|
63
|
+
"optionalDependencies": {
|
|
64
|
+
"@colyseus/h3-transport": "0.18.4"
|
|
65
|
+
}
|
|
66
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
# Caddy in front of the Babylon Game Server {{version}} (docker-compose.websocket.yml).
|
|
2
|
+
# CADDY_SITE is your domain (Caddy gets and renews its certificate automatically) and defaults to :443.
|
|
3
|
+
# CADDY_SITE=:8080 serves plain HTTP on 8080 for a local check.
|
|
4
|
+
{$CADDY_SITE::443} {
|
|
5
|
+
reverse_proxy game-server:2567
|
|
6
|
+
}
|
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
# Deploying the Babylon Game Server {{version}}
|
|
2
|
+
|
|
3
|
+
This folder was written by `babylon-game-server init`. It holds your server configuration and a ready recipe for each
|
|
4
|
+
way of hosting it. Every recipe uses the published image `ghcr.io/mackeyk24/babylon-game-server:{{version}}` (also
|
|
5
|
+
on Docker Hub as `mackeyk24/babylon-game-server:{{version}}`), either directly or through the `Dockerfile` here,
|
|
6
|
+
which adds your `babylon-game-server.config.mjs`.
|
|
7
|
+
|
|
8
|
+
TLS, UDP (HTTP/3 WebTransport) and player authentication are **off** in every file until you turn them on. Each
|
|
9
|
+
recipe's header states where TLS ends (`edge`: the proxy or platform, `server`: the game server itself), whether its
|
|
10
|
+
host can carry UDP, and how to enable auth.
|
|
11
|
+
|
|
12
|
+
| File | What it is |
|
|
13
|
+
|---|---|
|
|
14
|
+
| `babylon-game-server.config.mjs` | Every setting at its default, with notes on enabling TLS, UDP and auth |
|
|
15
|
+
| `.env.example` | Every setting as a `GAME_SERVER_*` environment variable |
|
|
16
|
+
| `Dockerfile` | Your image: the published image plus your config |
|
|
17
|
+
| `docker-compose.websocket.yml`, `Caddyfile` | The server behind Caddy (HTTPS at Caddy, WebSocket only) |
|
|
18
|
+
| `docker-compose.full.yml` | TLS on the server, WebSocket + HTTP/3 on 443 TCP + UDP, and Redis |
|
|
19
|
+
| `aws/`, `fly.toml`, `railway.json`, `render.yaml`, `digitalocean-app.yaml`, `heroku.yml`, `app.json`, `colyseus-cloud/`, `kubernetes/` | Cloud and platform recipes (see [Platforms](#platforms)) |
|
|
20
|
+
|
|
21
|
+
**Recommended host: Colyseus Cloud (`colyseus-cloud/`).** The server is built on Colyseus 0.18, and Colyseus Cloud is
|
|
22
|
+
Colyseus's own hosting, at a fixed monthly price: `wss://` provided, one process per CPU sharing Redis, and rolling
|
|
23
|
+
deploys that let running sessions finish. Its folder installs the published package instead of using the image; its
|
|
24
|
+
`README.md` has every step. The other recipes run the same server anywhere else.
|
|
25
|
+
|
|
26
|
+
## Production checklist
|
|
27
|
+
|
|
28
|
+
1. **Point the game at the server.** Set the game's `serverUrl` (the Unity `NetworkSettings` component, or
|
|
29
|
+
`StartGameArgs`) to `wss://<your domain>`. Browsers block `ws://` from an `https://` page.
|
|
30
|
+
2. **Decide on authentication.** With auth off, anyone who can reach the server can join (the server logs a warning
|
|
31
|
+
in production). To require players to sign in, set `GAME_SERVER_AUTH_ENABLED=true` and a mode
|
|
32
|
+
(`GAME_SERVER_AUTH_MODE`: `shared-secret`, `jwt` or `webhook`) with its fields, and have the game pass
|
|
33
|
+
`StartGameArgs.authToken`.
|
|
34
|
+
- **Discord sign-in (optional, works beside any mode):** register `https://<your domain>/game-server/discord/callback`
|
|
35
|
+
under OAuth2 → Redirects in your Discord application, set it as `GAME_SERVER_DISCORD_REDIRECT_URI`, and put the client
|
|
36
|
+
secret in `GAME_SERVER_DISCORD_CLIENT_SECRET` in your platform's secret store (with
|
|
37
|
+
`GAME_SERVER_DISCORD_SIGN_IN_ENABLED=true`, `GAME_SERVER_DISCORD_CLIENT_ID` and `GAME_SERVER_DISCORD_RETURN_ORIGINS`).
|
|
38
|
+
3. **Restrict origins.** Set `GAME_SERVER_ALLOWED_ORIGINS` to your game's origins, e.g. `https://game.example.com`.
|
|
39
|
+
4. **Protect the admin API.** The four original admin endpoints stay off until `GAME_SERVER_ADMIN_TOKEN` is set; use a
|
|
40
|
+
long random value from your platform's secret store. For scripts, prefer the console's API keys, which carry only
|
|
41
|
+
the permissions they need (`babylon-game-server admin create-api-key`).
|
|
42
|
+
5. **Size instances for dedicated sessions.** Each Server-mode session runs the scene's simulation on the server
|
|
43
|
+
(`limits.maxDedicatedSessions` per process, default 4). Shared and Host sessions only relay, and are light.
|
|
44
|
+
6. **When scaling out**, run Redis, set `GAME_SERVER_REDIS_URL` on every instance, and set
|
|
45
|
+
`GAME_SERVER_PUBLIC_ADDRESS` per instance to an address players can reach that instance on directly (seat
|
|
46
|
+
reservations send each player to the instance that holds the session).
|
|
47
|
+
7. **Health checks:** liveness `GET /game-server/health`, readiness `GET /game-server/ready` (503 while draining or
|
|
48
|
+
when Redis is unreachable). On `SIGTERM` the server drains for `GAME_SERVER_DRAIN_SECONDS` (default 30): give the
|
|
49
|
+
platform at least that long before it kills the container.
|
|
50
|
+
8. **Set up the admin console** (`/game-server/admin/`; README, "Admin console"):
|
|
51
|
+
- **HTTPS.** The console refuses plain HTTP except from a loopback address. Serve it on your TLS address (an edge
|
|
52
|
+
with `GAME_SERVER_TRUST_PROXY=true` that sends `x-forwarded-proto: https`, or TLS on the server).
|
|
53
|
+
- **Keep its data.** Accounts, bans, the audit log and the leaderboards live in Redis when `GAME_SERVER_REDIS_URL` is set, otherwise in
|
|
54
|
+
`GAME_SERVER_ADMIN_DATA_DIR` (`/data` in the image). Mount a volume at `/data` (the compose files and `fly.toml`
|
|
55
|
+
do), or use Redis with persistence (`docker-compose.full.yml`, `kubernetes/redis.yaml`). Platforms without
|
|
56
|
+
volumes (Railway, Render, DigitalOcean App Platform, Heroku, ECS Fargate) need Redis, or the console forgets its
|
|
57
|
+
accounts on every deploy.
|
|
58
|
+
- **Restrict who can reach it.** Set `GAME_SERVER_ADMIN_ALLOWED_NETWORKS` to your office or VPN ranges (CIDR), or
|
|
59
|
+
block `/game-server/admin/` at the edge. Requests from other addresses answer 404.
|
|
60
|
+
- **Create the first Owner.** The first start logs `admin setup link` (valid 30 minutes, used once): open it on your
|
|
61
|
+
HTTPS address, or run `babylon-game-server admin create-owner --username <name>` in the container. Every account
|
|
62
|
+
signs in with a password and an authenticator code or passkey.
|
|
63
|
+
- **Back up the data.** Copy the data folder (or snapshot the volume), or turn on Redis persistence and backups; it
|
|
64
|
+
holds the bans, the audit log and the leaderboards. The console's Leaderboards page warns when they are not
|
|
65
|
+
durable.
|
|
66
|
+
|
|
67
|
+
## Docker Compose
|
|
68
|
+
|
|
69
|
+
Both compose files read `GAME_SERVER_IMAGE` when it is set, so you can try a locally built image first
|
|
70
|
+
(`GAME_SERVER_IMAGE=my-game-server docker compose …`).
|
|
71
|
+
|
|
72
|
+
### WebSocket behind Caddy (`docker-compose.websocket.yml`)
|
|
73
|
+
|
|
74
|
+
Caddy terminates HTTPS (it obtains and renews a certificate for your domain automatically) and proxies to the server,
|
|
75
|
+
which publishes no ports of its own. Point your domain's DNS at the host and open TCP 443.
|
|
76
|
+
|
|
77
|
+
```sh
|
|
78
|
+
CADDY_SITE=game.example.com docker compose -f docker-compose.websocket.yml up -d
|
|
79
|
+
# players use wss://game.example.com
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
Local check without a domain (plain HTTP on 8080):
|
|
83
|
+
|
|
84
|
+
```sh
|
|
85
|
+
CADDY_SITE=:8080 docker compose -f docker-compose.websocket.yml up -d
|
|
86
|
+
curl -s http://localhost:8080/game-server/health # {"status":"ok"}
|
|
87
|
+
docker compose -f docker-compose.websocket.yml down
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
### TLS, HTTP/3 and Redis (`docker-compose.full.yml`)
|
|
91
|
+
|
|
92
|
+
The server terminates TLS itself, so it can also offer HTTP/3 WebTransport over UDP on the same port 443.
|
|
93
|
+
|
|
94
|
+
1. Get a certificate into `./certs` (`fullchain.pem`, `privkey.pem`), for example with certbot:
|
|
95
|
+
`certbot certonly --standalone -d game.example.com`, then copy the files from `/etc/letsencrypt/live/<domain>/`
|
|
96
|
+
(a certbot `--deploy-hook` can copy them on every renewal; the server reloads them without a restart, and HTTP/3
|
|
97
|
+
picks them up at the next restart).
|
|
98
|
+
2. Open TCP **and** UDP 443 on the host and its firewall.
|
|
99
|
+
3. Start it:
|
|
100
|
+
|
|
101
|
+
```sh
|
|
102
|
+
docker compose -f docker-compose.full.yml up -d
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
Players use `wss://game.example.com`; browsers that support WebTransport switch to HTTP/3 datagrams automatically and
|
|
106
|
+
fall back to the WebSocket when UDP is blocked.
|
|
107
|
+
|
|
108
|
+
## Platforms
|
|
109
|
+
|
|
110
|
+
Which transports each host can carry. WebSocket works everywhere; HTTP/3 WebTransport (UDP datagrams) needs a host
|
|
111
|
+
that forwards inbound UDP to the server **and** TLS on the server itself. Players whose network or browser cannot use
|
|
112
|
+
HTTP/3 fall back to the WebSocket automatically, so a WebSocket-only host is fully playable.
|
|
113
|
+
|
|
114
|
+
| Host | WebSocket | UDP (HTTP/3) | TLS |
|
|
115
|
+
|---|---|---|---|
|
|
116
|
+
| Docker Compose + Caddy (`docker-compose.websocket.yml`) | yes | no (Caddy proxies TCP only) | edge (Caddy) |
|
|
117
|
+
| Docker Compose full (`docker-compose.full.yml`) | yes | yes (443/udp published) | server |
|
|
118
|
+
| AWS ECS Fargate + ALB (`aws/ecs-fargate-alb.yml`) | yes | no: [ALB listeners are HTTP/HTTPS only](https://docs.aws.amazon.com/elasticloadbalancing/latest/application/load-balancer-listeners.html) | edge (ALB) |
|
|
119
|
+
| AWS ECS Fargate + NLB QUIC (`aws/ecs-fargate-nlb-quic.yml`) | yes | yes (`TCP_QUIC` listener) | server |
|
|
120
|
+
| AWS single EC2 + Elastic IP (`aws/README.md`) | yes | yes (open UDP 443) | server |
|
|
121
|
+
| AWS Elastic Beanstalk (`aws/README.md`) | yes | no: [ALB listeners are HTTP/HTTPS only](https://docs.aws.amazon.com/elasticloadbalancing/latest/application/load-balancer-listeners.html) | edge (ALB) |
|
|
122
|
+
| Fly.io (`fly.toml`) | yes | no: [UDP must bind `fly-global-services`](https://docs.fly.io/networking/udp-and-tcp) | edge (Fly proxy) |
|
|
123
|
+
| Railway (`railway.json`) | yes | no: [no inbound UDP](https://docs.railway.com/networking/tcp-proxy) | edge (Railway) |
|
|
124
|
+
| Render (`render.yaml`) | yes | no: [HTTP and WebSocket only](https://render.com/docs/websocket) | edge (Render) |
|
|
125
|
+
| DigitalOcean App Platform (`digitalocean-app.yaml`) | yes | no: [HTTP only](https://docs.digitalocean.com/products/app-platform/details/limits/) | edge (App Platform) |
|
|
126
|
+
| Heroku (`heroku.yml`, `app.json`) | yes | no: [HTTP routing only](https://devcenter.heroku.com/articles/http-routing) | edge (Heroku router) |
|
|
127
|
+
| Colyseus Cloud (`colyseus-cloud/`) | yes | no: its NGINX carries HTTP and WebSocket only | edge (Colyseus Cloud) |
|
|
128
|
+
| Kubernetes (`kubernetes/`) | yes | only with server TLS and a UDP-capable LoadBalancer Service | edge (Ingress) or server |
|
|
129
|
+
|
|
130
|
+
Every recipe below except Colyseus Cloud builds from the `Dockerfile` in this folder (the published image plus your
|
|
131
|
+
config) or runs the published image directly, keeps server TLS, UDP and auth off unless the table says otherwise, and honours the
|
|
132
|
+
platform's `PORT` when `GAME_SERVER_PORT` is not set.
|
|
133
|
+
|
|
134
|
+
### AWS
|
|
135
|
+
|
|
136
|
+
`aws/README.md` walks through three setups: ECS Fargate behind an Application Load Balancer (`aws/ecs-fargate-alb.yml`,
|
|
137
|
+
WebSocket, TLS at the ALB, health `/game-server/ready`, idle timeout 3600 s), ECS Fargate behind a Network Load
|
|
138
|
+
Balancer with a `TCP_QUIC` listener (`aws/ecs-fargate-nlb-quic.yml`, WebSocket + HTTP/3, TLS on the server from a
|
|
139
|
+
Secrets Manager PEM secret), and one EC2 instance with an Elastic IP, plus Elastic Beanstalk notes.
|
|
140
|
+
|
|
141
|
+
```sh
|
|
142
|
+
aws cloudformation deploy --template-file aws/ecs-fargate-alb.yml --stack-name babylon-game-server \
|
|
143
|
+
--capabilities CAPABILITY_IAM \
|
|
144
|
+
--parameter-overrides VpcId=vpc-... SubnetIds=subnet-a,subnet-b CertificateArn=arn:aws:acm:...
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
### Fly.io (`fly.toml`)
|
|
148
|
+
|
|
149
|
+
WebSocket only, TLS at Fly's edge on 443, readiness check on `/game-server/ready`. Fly hands UDP only to sockets bound
|
|
150
|
+
to `fly-global-services`, while the server's HTTP/3 transport binds one address for TCP and UDP, so HTTP/3 is not
|
|
151
|
+
offered ([Fly: UDP and TCP](https://docs.fly.io/networking/udp-and-tcp)).
|
|
152
|
+
|
|
153
|
+
```sh
|
|
154
|
+
fly launch --copy-config --no-deploy
|
|
155
|
+
fly deploy
|
|
156
|
+
# players use wss://<app>.fly.dev
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
### Railway (`railway.json`)
|
|
160
|
+
|
|
161
|
+
TLS: edge. UDP: not supported on this host. Auth: set `GAME_SERVER_AUTH_*` in the service's variables to enable.
|
|
162
|
+
(JSON has no comments, so this recipe's header lives here.) Railway builds the `Dockerfile`, checks
|
|
163
|
+
`/game-server/ready`, and sets `PORT`. Its public networking is HTTP, plus a TCP proxy; there is no inbound UDP
|
|
164
|
+
([Railway: TCP proxy](https://docs.railway.com/networking/tcp-proxy)).
|
|
165
|
+
|
|
166
|
+
```sh
|
|
167
|
+
railway init
|
|
168
|
+
railway up
|
|
169
|
+
railway domain # players use wss://<generated domain>
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
### Render (`render.yaml`)
|
|
173
|
+
|
|
174
|
+
A Docker web service with `healthCheckPath: /game-server/ready`; Render terminates TLS and supports WebSockets, but
|
|
175
|
+
not inbound UDP ([Render: WebSockets](https://render.com/docs/websocket)). Commit this folder to a repository and
|
|
176
|
+
create a Blueprint from it in the Render dashboard.
|
|
177
|
+
|
|
178
|
+
### DigitalOcean App Platform (`digitalocean-app.yaml`)
|
|
179
|
+
|
|
180
|
+
A service built from the `Dockerfile` with `http_port: 2567` and a health check on `/game-server/ready`. App Platform
|
|
181
|
+
routes HTTP (including WebSockets) only ([App Platform limits](https://docs.digitalocean.com/products/app-platform/details/limits/)).
|
|
182
|
+
Set `github.repo`, then:
|
|
183
|
+
|
|
184
|
+
```sh
|
|
185
|
+
doctl apps create --spec digitalocean-app.yaml
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
### Heroku (`heroku.yml`, `app.json`)
|
|
189
|
+
|
|
190
|
+
The container stack builds the `Dockerfile`; `app.json` sets the stack, trusts the router's forwarding header, and
|
|
191
|
+
shortens the drain to 25 s because Heroku stops a dyno 30 s after `SIGTERM`. The router carries HTTP and WebSockets
|
|
192
|
+
only ([Heroku: HTTP routing](https://devcenter.heroku.com/articles/http-routing)).
|
|
193
|
+
|
|
194
|
+
```sh
|
|
195
|
+
heroku create --stack container
|
|
196
|
+
git push heroku main
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
### Colyseus Cloud (`colyseus-cloud/`)
|
|
200
|
+
|
|
201
|
+
The recommended host. WebSocket only, TLS at Colyseus Cloud's NGINX, one process per CPU sharing Redis. This folder is
|
|
202
|
+
a deploy repository that installs the published package, so it uses neither the `Dockerfile` nor the image. Push it as a
|
|
203
|
+
repository of its own, or as a subfolder of another repository with the panel's Root directory set to it. Its
|
|
204
|
+
`README.md` has every step.
|
|
205
|
+
|
|
206
|
+
```sh
|
|
207
|
+
cd colyseus-cloud
|
|
208
|
+
npm install # keep the package-lock.json this writes
|
|
209
|
+
git init && git add . && git commit -m "Babylon Game Server on Colyseus Cloud"
|
|
210
|
+
npx @colyseus/cloud deploy # or connect the repository on the panel
|
|
211
|
+
# the banner in the application logs shows wss://<your-application-address>
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
Set `NODE_ENV=production`, `GAME_SERVER_ALLOWED_ORIGINS` and `GAME_SERVER_ADMIN_TOKEN` on the panel. Leave
|
|
215
|
+
`GAME_SERVER_TLS_ENABLED`, `GAME_SERVER_UDP_ENABLED` and `GAME_SERVER_PUBLIC_ADDRESS` unset: the server refuses to start
|
|
216
|
+
with them. The drain time here is 600 s, and a process holding a `boot` dedicated session uses all of it on every
|
|
217
|
+
deploy; `GAME_SERVER_DRAIN_SECONDS` changes it. After changing a boot scene, watch the logs for `the boot dedicated
|
|
218
|
+
sessions could not start; trying again`: a bad scene does not fail a rolling deploy.
|
|
219
|
+
|
|
220
|
+
### Kubernetes (`kubernetes/`)
|
|
221
|
+
|
|
222
|
+
`deployment.yaml` runs the image with liveness `/game-server/health`, readiness `/game-server/ready`,
|
|
223
|
+
`GAME_SERVER_REDIS_URL`, and a per-pod `GAME_SERVER_PUBLIC_ADDRESS` from the pod IP (downward API). `service.yaml` is
|
|
224
|
+
a ClusterIP Service for an Ingress; `redis.yaml` is a single Redis Deployment and Service.
|
|
225
|
+
|
|
226
|
+
```sh
|
|
227
|
+
kubectl apply -f kubernetes/redis.yaml -f kubernetes/deployment.yaml -f kubernetes/service.yaml
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
Put a TLS Ingress in front of the Service for `wss://`. When scaling past one replica, each pod must be reachable on
|
|
231
|
+
its own address, because seat reservations send each player to the pod that holds the session (see the comment in
|
|
232
|
+
`service.yaml`). For HTTP/3, enable server TLS (mount the certificate from a Secret) and UDP, and expose the pods with a
|
|
233
|
+
LoadBalancer Service that forwards both TCP and UDP on the same port.
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# Babylon Game Server {{version}}: your game's server image, built on the published base image.
|
|
2
|
+
# docker build -t my-game-server .
|
|
3
|
+
# docker run -p 2567:2567 my-game-server
|
|
4
|
+
# The base image runs as user "node", exposes 2567/tcp and 2567/udp, and checks its own /game-server/health.
|
|
5
|
+
# TLS: edge (a proxy or the platform terminates it) unless you enable it in the config.
|
|
6
|
+
# UDP: off unless you enable it in the config (it also needs TLS and a host that forwards UDP).
|
|
7
|
+
# Auth: set GAME_SERVER_AUTH_* to enable.
|
|
8
|
+
FROM ghcr.io/mackeyk24/babylon-game-server:{{version}}
|
|
9
|
+
COPY babylon-game-server.config.mjs /app/config/
|
|
10
|
+
ENV GAME_SERVER_CONFIG=/app/config/babylon-game-server.config.mjs
|
|
11
|
+
# Local dedicated scenes (exported glTF folders) referenced by dedicated.scenes[].sceneRoot:
|
|
12
|
+
# COPY scenes/ /app/scenes/
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "Babylon Game Server",
|
|
3
|
+
"description": "Babylon Game Server {{version}} for Babylon Toolkit multiplayer games. TLS: edge (the Heroku router). UDP: not supported on this host (WebSocket only). Auth: set GAME_SERVER_AUTH_* to enable.",
|
|
4
|
+
"stack": "container",
|
|
5
|
+
"env": {
|
|
6
|
+
"GAME_SERVER_TRUST_PROXY": {
|
|
7
|
+
"description": "The Heroku router sends the player's address in x-forwarded-for.",
|
|
8
|
+
"value": "true"
|
|
9
|
+
},
|
|
10
|
+
"GAME_SERVER_DRAIN_SECONDS": {
|
|
11
|
+
"description": "Seconds running sessions may continue after SIGTERM; Heroku stops a dyno 30 s after SIGTERM.",
|
|
12
|
+
"value": "25"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"formation": {
|
|
16
|
+
"web": {
|
|
17
|
+
"quantity": 1,
|
|
18
|
+
"size": "basic"
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
TLS: edge (ecs-fargate-alb.yml, Elastic Beanstalk) or server (ecs-fargate-nlb-quic.yml, single EC2)
|
|
3
|
+
UDP: supported with ecs-fargate-nlb-quic.yml and single EC2; not supported on this host with an ALB or Elastic Beanstalk
|
|
4
|
+
Auth: set GAME_SERVER_AUTH_* to enable
|
|
5
|
+
-->
|
|
6
|
+
|
|
7
|
+
# Babylon Game Server {{version}} on AWS
|
|
8
|
+
|
|
9
|
+
Three ways to run the server on AWS, from simplest to most capable. All of them use the published image
|
|
10
|
+
`ghcr.io/mackeyk24/babylon-game-server:{{version}}`, or your own image built from `../Dockerfile` and pushed to ECR
|
|
11
|
+
(pass it as the `Image` parameter). Nothing here is deployed for you: run the commands with your own AWS account.
|
|
12
|
+
|
|
13
|
+
## ECS Fargate behind an Application Load Balancer (`ecs-fargate-alb.yml`)
|
|
14
|
+
|
|
15
|
+
WebSocket only. The ALB terminates HTTPS with an ACM certificate for your domain, forwards to the tasks on port 2567,
|
|
16
|
+
checks `/game-server/ready`, and keeps idle WebSockets for 3600 s.
|
|
17
|
+
|
|
18
|
+
1. Request (or import) a certificate for your domain in ACM, in the stack's region.
|
|
19
|
+
2. Deploy:
|
|
20
|
+
|
|
21
|
+
```sh
|
|
22
|
+
aws cloudformation deploy \
|
|
23
|
+
--template-file aws/ecs-fargate-alb.yml \
|
|
24
|
+
--stack-name babylon-game-server \
|
|
25
|
+
--capabilities CAPABILITY_IAM \
|
|
26
|
+
--parameter-overrides \
|
|
27
|
+
VpcId=vpc-0123456789abcdef0 \
|
|
28
|
+
SubnetIds=subnet-aaaa,subnet-bbbb \
|
|
29
|
+
CertificateArn=arn:aws:acm:us-east-1:123456789012:certificate/... \
|
|
30
|
+
DesiredCount=1
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
3. Point your domain at the `LoadBalancerDnsName` output (CNAME, or a Route 53 alias record), then set the game's
|
|
34
|
+
`serverUrl` to `wss://<your domain>`.
|
|
35
|
+
|
|
36
|
+
## ECS Fargate behind a Network Load Balancer with QUIC (`ecs-fargate-nlb-quic.yml`)
|
|
37
|
+
|
|
38
|
+
WebSocket **and** HTTP/3 WebTransport. A `TCP_QUIC` listener on 443 passes TCP and QUIC through to the tasks on 2567,
|
|
39
|
+
and the server terminates TLS itself with a PEM certificate from Secrets Manager (`GAME_SERVER_TLS_CERT_PEM` /
|
|
40
|
+
`GAME_SERVER_TLS_KEY_PEM`), with `GAME_SERVER_TLS_ENABLED=true` and `GAME_SERVER_UDP_ENABLED=true`.
|
|
41
|
+
|
|
42
|
+
1. Store the certificate (for example from certbot) as one JSON secret with the keys `certPem` and `keyPem`:
|
|
43
|
+
|
|
44
|
+
```sh
|
|
45
|
+
aws secretsmanager create-secret --name babylon-game-server-tls \
|
|
46
|
+
--secret-string "$(jq -n --rawfile certPem fullchain.pem --rawfile keyPem privkey.pem '{certPem: $certPem, keyPem: $keyPem}')"
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
2. Deploy:
|
|
50
|
+
|
|
51
|
+
```sh
|
|
52
|
+
aws cloudformation deploy \
|
|
53
|
+
--template-file aws/ecs-fargate-nlb-quic.yml \
|
|
54
|
+
--stack-name babylon-game-server-quic \
|
|
55
|
+
--capabilities CAPABILITY_IAM \
|
|
56
|
+
--parameter-overrides \
|
|
57
|
+
VpcId=vpc-0123456789abcdef0 \
|
|
58
|
+
SubnetIds=subnet-aaaa,subnet-bbbb \
|
|
59
|
+
TlsSecretArn=arn:aws:secretsmanager:us-east-1:123456789012:secret:babylon-game-server-tls-AbCdEf
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
3. Point your domain at the `LoadBalancerDnsName` output.
|
|
63
|
+
|
|
64
|
+
QUIC listeners cannot have security groups, so the task security group admits 2567 TCP and UDP from anywhere. QUIC
|
|
65
|
+
on Network Load Balancers is newer than the rest of this setup: check the current Elastic Load Balancing documentation
|
|
66
|
+
for QUIC listener and target requirements in your region before you depend on it. A renewed certificate reaches
|
|
67
|
+
`wss://` without a restart when it comes from files; from Secrets Manager it is read at task start, so roll the
|
|
68
|
+
service (`aws ecs update-service --force-new-deployment`) after rotating the secret.
|
|
69
|
+
|
|
70
|
+
## Alternative: one EC2 instance with an Elastic IP (HTTP/3 without a load balancer)
|
|
71
|
+
|
|
72
|
+
The most direct way to offer HTTP/3: the instance's address receives TCP and UDP 443 itself.
|
|
73
|
+
|
|
74
|
+
1. Launch an instance (for example Amazon Linux 2023, t4g.small) with Docker installed, and associate an Elastic IP.
|
|
75
|
+
Point your domain at the Elastic IP.
|
|
76
|
+
2. In its security group, open **TCP 443 and UDP 443** to `0.0.0.0/0` (and TCP 80 if certbot uses the HTTP challenge).
|
|
77
|
+
3. Get a certificate (`certbot certonly --standalone -d game.example.com`) and copy `fullchain.pem` / `privkey.pem`
|
|
78
|
+
into `./certs`, readable by the container user.
|
|
79
|
+
4. Run the image with TLS and UDP enabled, either with `../docker-compose.full.yml` or directly:
|
|
80
|
+
|
|
81
|
+
```sh
|
|
82
|
+
docker run -d --restart unless-stopped -p 443:443/tcp -p 443:443/udp \
|
|
83
|
+
-v "$PWD/certs:/certs:ro" \
|
|
84
|
+
-e GAME_SERVER_PORT=443 \
|
|
85
|
+
-e GAME_SERVER_TLS_ENABLED=true \
|
|
86
|
+
-e GAME_SERVER_TLS_CERT_FILE=/certs/fullchain.pem \
|
|
87
|
+
-e GAME_SERVER_TLS_KEY_FILE=/certs/privkey.pem \
|
|
88
|
+
-e GAME_SERVER_UDP_ENABLED=true \
|
|
89
|
+
ghcr.io/mackeyk24/babylon-game-server:{{version}}
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
## Elastic Beanstalk notes
|
|
93
|
+
|
|
94
|
+
- Use the **Docker** platform and deploy the folder with `../Dockerfile` (`eb init -p docker`, `eb create`).
|
|
95
|
+
- Beanstalk puts an Application Load Balancer in front: attach your ACM certificate to a 443 HTTPS listener, forward to
|
|
96
|
+
instance port 2567, set the health check path to `/game-server/ready`, and raise the ALB idle timeout to 3600 s so
|
|
97
|
+
WebSockets are not cut.
|
|
98
|
+
- WebSocket only: the ALB does not carry UDP, so HTTP/3 is not available on Beanstalk.
|
|
99
|
+
|
|
100
|
+
## Scaling
|
|
101
|
+
|
|
102
|
+
One task holds each session (a session never spans processes). To run more than one task, set `GAME_SERVER_REDIS_URL`
|
|
103
|
+
on every task (for example ElastiCache) and give each task a `GAME_SERVER_PUBLIC_ADDRESS` that players can reach it on
|
|
104
|
+
directly, because seat reservations send each player to the task that holds the session. A single load balancer
|
|
105
|
+
address cannot do that on its own, so keep `DesiredCount=1` per stack until per-task addresses are in place.
|
|
106
|
+
|
|
107
|
+
## Admin console data
|
|
108
|
+
|
|
109
|
+
The admin console (`/game-server/admin/`) keeps its accounts, bans and audit log in Redis when `GAME_SERVER_REDIS_URL`
|
|
110
|
+
is set, and otherwise in files under `GAME_SERVER_ADMIN_DATA_DIR` (`/data` in the templates). Fargate task storage is
|
|
111
|
+
lost whenever a task stops or is replaced, so on ECS use Redis as the console's store: create an ElastiCache for Redis
|
|
112
|
+
(or Valkey) cluster in the tasks' VPC, allow TCP 6379 from the task security group, and add `GAME_SERVER_REDIS_URL`
|
|
113
|
+
(through Secrets Manager when it carries a password) to the container's `Environment` or `Secrets`. Turn on ElastiCache
|
|
114
|
+
backups, because the audit log and the bans live there. Mounting an EFS volume at `/data` also works but is not part of
|
|
115
|
+
these templates. The console needs HTTPS: the ALB template's HTTPS listener and the NLB template's server TLS both
|
|
116
|
+
qualify. The first start logs `admin setup link` in CloudWatch: open its path
|
|
117
|
+
(`/game-server/admin/#/setup?token=…`) on your HTTPS address within 30 minutes to create the first Owner, or run
|
|
118
|
+
`babylon-game-server admin create-owner` against the same Redis.
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
# TLS: edge (the Application Load Balancer terminates HTTPS with your ACM certificate)
|
|
2
|
+
# UDP: not supported on this host (an ALB forwards HTTP and WebSocket only; see aws/ecs-fargate-nlb-quic.yml for HTTP/3)
|
|
3
|
+
# Auth: set GAME_SERVER_AUTH_* to enable (add them to the container Environment below, secrets through Secrets Manager)
|
|
4
|
+
#
|
|
5
|
+
# Babylon Game Server {{version}} on ECS Fargate behind an Application Load Balancer: players connect with
|
|
6
|
+
# wss://<your domain>, which you point (CNAME / alias) at the LoadBalancerDnsName output.
|
|
7
|
+
# Long-form intrinsics only (Ref: / Fn::GetAtt:), so any YAML parser can check the template.
|
|
8
|
+
# aws cloudformation deploy --template-file aws/ecs-fargate-alb.yml --stack-name babylon-game-server \
|
|
9
|
+
# --capabilities CAPABILITY_IAM --parameter-overrides VpcId=vpc-... SubnetIds=subnet-a,subnet-b CertificateArn=arn:aws:acm:...
|
|
10
|
+
# Keep DesiredCount at 1 unless sessions are routed to the task that holds them (see aws/README.md, Scaling).
|
|
11
|
+
AWSTemplateFormatVersion: "2010-09-09"
|
|
12
|
+
Description: Babylon Game Server {{version}} on ECS Fargate behind an Application Load Balancer (WebSocket, TLS at the ALB)
|
|
13
|
+
|
|
14
|
+
Parameters:
|
|
15
|
+
VpcId:
|
|
16
|
+
Type: AWS::EC2::VPC::Id
|
|
17
|
+
Description: The VPC the load balancer and the tasks run in.
|
|
18
|
+
SubnetIds:
|
|
19
|
+
Type: List<AWS::EC2::Subnet::Id>
|
|
20
|
+
Description: Two or more public subnets in different availability zones.
|
|
21
|
+
CertificateArn:
|
|
22
|
+
Type: String
|
|
23
|
+
Description: ARN of the ACM certificate for your game server domain.
|
|
24
|
+
Image:
|
|
25
|
+
Type: String
|
|
26
|
+
Default: ghcr.io/mackeyk24/babylon-game-server:{{version}}
|
|
27
|
+
Description: The server image (or your own image built from the init Dockerfile).
|
|
28
|
+
DesiredCount:
|
|
29
|
+
Type: Number
|
|
30
|
+
Default: 1
|
|
31
|
+
Description: Number of server tasks.
|
|
32
|
+
|
|
33
|
+
Resources:
|
|
34
|
+
Cluster:
|
|
35
|
+
Type: AWS::ECS::Cluster
|
|
36
|
+
|
|
37
|
+
LogGroup:
|
|
38
|
+
Type: AWS::Logs::LogGroup
|
|
39
|
+
Properties:
|
|
40
|
+
RetentionInDays: 14
|
|
41
|
+
|
|
42
|
+
TaskExecutionRole:
|
|
43
|
+
Type: AWS::IAM::Role
|
|
44
|
+
Properties:
|
|
45
|
+
AssumeRolePolicyDocument:
|
|
46
|
+
Version: "2012-10-17"
|
|
47
|
+
Statement:
|
|
48
|
+
- Effect: Allow
|
|
49
|
+
Principal:
|
|
50
|
+
Service: ecs-tasks.amazonaws.com
|
|
51
|
+
Action: sts:AssumeRole
|
|
52
|
+
ManagedPolicyArns:
|
|
53
|
+
- arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy
|
|
54
|
+
|
|
55
|
+
TaskDefinition:
|
|
56
|
+
Type: AWS::ECS::TaskDefinition
|
|
57
|
+
Properties:
|
|
58
|
+
Family: babylon-game-server
|
|
59
|
+
RequiresCompatibilities:
|
|
60
|
+
- FARGATE
|
|
61
|
+
NetworkMode: awsvpc
|
|
62
|
+
Cpu: "512"
|
|
63
|
+
Memory: "1024"
|
|
64
|
+
ExecutionRoleArn:
|
|
65
|
+
Fn::GetAtt: [TaskExecutionRole, Arn]
|
|
66
|
+
ContainerDefinitions:
|
|
67
|
+
- Name: game-server
|
|
68
|
+
Image:
|
|
69
|
+
Ref: Image
|
|
70
|
+
Essential: true
|
|
71
|
+
# Longer than the 30 s drain, so running sessions finish before the task is stopped.
|
|
72
|
+
StopTimeout: 45
|
|
73
|
+
PortMappings:
|
|
74
|
+
- ContainerPort: 2567
|
|
75
|
+
Protocol: tcp
|
|
76
|
+
Environment:
|
|
77
|
+
- Name: GAME_SERVER_LOG_FORMAT
|
|
78
|
+
Value: json
|
|
79
|
+
# Admin console data (accounts, bans, audit log). Fargate task storage is lost when the task stops: add
|
|
80
|
+
# GAME_SERVER_REDIS_URL (ElastiCache, see aws/README.md) so the console keeps its data in Redis.
|
|
81
|
+
- Name: GAME_SERVER_ADMIN_DATA_DIR
|
|
82
|
+
Value: /data
|
|
83
|
+
# The ALB sends the player's address in x-forwarded-for.
|
|
84
|
+
- Name: GAME_SERVER_TRUST_PROXY
|
|
85
|
+
Value: "true"
|
|
86
|
+
LogConfiguration:
|
|
87
|
+
LogDriver: awslogs
|
|
88
|
+
Options:
|
|
89
|
+
awslogs-group:
|
|
90
|
+
Ref: LogGroup
|
|
91
|
+
awslogs-region:
|
|
92
|
+
Ref: AWS::Region
|
|
93
|
+
awslogs-stream-prefix: game-server
|
|
94
|
+
|
|
95
|
+
LoadBalancerSecurityGroup:
|
|
96
|
+
Type: AWS::EC2::SecurityGroup
|
|
97
|
+
Properties:
|
|
98
|
+
GroupDescription: Babylon Game Server load balancer (HTTPS from anywhere)
|
|
99
|
+
VpcId:
|
|
100
|
+
Ref: VpcId
|
|
101
|
+
SecurityGroupIngress:
|
|
102
|
+
- IpProtocol: tcp
|
|
103
|
+
FromPort: 443
|
|
104
|
+
ToPort: 443
|
|
105
|
+
CidrIp: 0.0.0.0/0
|
|
106
|
+
|
|
107
|
+
ServiceSecurityGroup:
|
|
108
|
+
Type: AWS::EC2::SecurityGroup
|
|
109
|
+
Properties:
|
|
110
|
+
GroupDescription: Babylon Game Server tasks (port 2567 from the load balancer only)
|
|
111
|
+
VpcId:
|
|
112
|
+
Ref: VpcId
|
|
113
|
+
SecurityGroupIngress:
|
|
114
|
+
- IpProtocol: tcp
|
|
115
|
+
FromPort: 2567
|
|
116
|
+
ToPort: 2567
|
|
117
|
+
SourceSecurityGroupId:
|
|
118
|
+
Ref: LoadBalancerSecurityGroup
|
|
119
|
+
|
|
120
|
+
LoadBalancer:
|
|
121
|
+
Type: AWS::ElasticLoadBalancingV2::LoadBalancer
|
|
122
|
+
Properties:
|
|
123
|
+
Type: application
|
|
124
|
+
Scheme: internet-facing
|
|
125
|
+
Subnets:
|
|
126
|
+
Ref: SubnetIds
|
|
127
|
+
SecurityGroups:
|
|
128
|
+
- Ref: LoadBalancerSecurityGroup
|
|
129
|
+
LoadBalancerAttributes:
|
|
130
|
+
# WebSocket sessions stay open; the default 60 s idle timeout would cut quiet players.
|
|
131
|
+
- Key: idle_timeout.timeout_seconds
|
|
132
|
+
Value: "3600"
|
|
133
|
+
|
|
134
|
+
TargetGroup:
|
|
135
|
+
Type: AWS::ElasticLoadBalancingV2::TargetGroup
|
|
136
|
+
Properties:
|
|
137
|
+
VpcId:
|
|
138
|
+
Ref: VpcId
|
|
139
|
+
Protocol: HTTP
|
|
140
|
+
Port: 2567
|
|
141
|
+
TargetType: ip
|
|
142
|
+
HealthCheckProtocol: HTTP
|
|
143
|
+
HealthCheckPath: /game-server/ready
|
|
144
|
+
HealthCheckIntervalSeconds: 15
|
|
145
|
+
HealthyThresholdCount: 2
|
|
146
|
+
UnhealthyThresholdCount: 3
|
|
147
|
+
Matcher:
|
|
148
|
+
HttpCode: "200"
|
|
149
|
+
TargetGroupAttributes:
|
|
150
|
+
- Key: deregistration_delay.timeout_seconds
|
|
151
|
+
Value: "45"
|
|
152
|
+
|
|
153
|
+
HttpsListener:
|
|
154
|
+
Type: AWS::ElasticLoadBalancingV2::Listener
|
|
155
|
+
Properties:
|
|
156
|
+
LoadBalancerArn:
|
|
157
|
+
Ref: LoadBalancer
|
|
158
|
+
Port: 443
|
|
159
|
+
Protocol: HTTPS
|
|
160
|
+
SslPolicy: ELBSecurityPolicy-TLS13-1-2-2021-06
|
|
161
|
+
Certificates:
|
|
162
|
+
- CertificateArn:
|
|
163
|
+
Ref: CertificateArn
|
|
164
|
+
DefaultActions:
|
|
165
|
+
- Type: forward
|
|
166
|
+
TargetGroupArn:
|
|
167
|
+
Ref: TargetGroup
|
|
168
|
+
|
|
169
|
+
Service:
|
|
170
|
+
Type: AWS::ECS::Service
|
|
171
|
+
DependsOn: HttpsListener
|
|
172
|
+
Properties:
|
|
173
|
+
Cluster:
|
|
174
|
+
Ref: Cluster
|
|
175
|
+
LaunchType: FARGATE
|
|
176
|
+
DesiredCount:
|
|
177
|
+
Ref: DesiredCount
|
|
178
|
+
TaskDefinition:
|
|
179
|
+
Ref: TaskDefinition
|
|
180
|
+
HealthCheckGracePeriodSeconds: 30
|
|
181
|
+
NetworkConfiguration:
|
|
182
|
+
AwsvpcConfiguration:
|
|
183
|
+
# A public IP lets the task pull the image from ghcr.io without a NAT gateway.
|
|
184
|
+
AssignPublicIp: ENABLED
|
|
185
|
+
Subnets:
|
|
186
|
+
Ref: SubnetIds
|
|
187
|
+
SecurityGroups:
|
|
188
|
+
- Ref: ServiceSecurityGroup
|
|
189
|
+
LoadBalancers:
|
|
190
|
+
- ContainerName: game-server
|
|
191
|
+
ContainerPort: 2567
|
|
192
|
+
TargetGroupArn:
|
|
193
|
+
Ref: TargetGroup
|
|
194
|
+
|
|
195
|
+
Outputs:
|
|
196
|
+
LoadBalancerDnsName:
|
|
197
|
+
Description: Point your game server domain (CNAME or Route 53 alias) here.
|
|
198
|
+
Value:
|
|
199
|
+
Fn::GetAtt: [LoadBalancer, DNSName]
|
|
200
|
+
HealthUrl:
|
|
201
|
+
Description: The readiness check through the load balancer (use your domain, which the certificate covers).
|
|
202
|
+
Value:
|
|
203
|
+
Fn::Join:
|
|
204
|
+
- ""
|
|
205
|
+
- - "https://"
|
|
206
|
+
- Fn::GetAtt: [LoadBalancer, DNSName]
|
|
207
|
+
- /game-server/ready
|