Repository navigation
Installation Linux Compose
Run the full fb stack on a single Linux host with Docker Compose. This is the default Linux path for local development and small staging environments — closest to Windows — Runner.
Parent guide: Linux Installation
Manifests live in infra/compose/. See also infra/compose/README.md.
| Use Compose | Use Kubernetes instead |
|---|---|
| One machine, no cluster | Production cluster, multiple nodes |
Fast docker compose up
|
NodePort / LoadBalancer at scale |
| Single world (or few profiles) | Many worlds with isolated StatefulSets |
| Developer onboarding | CI deploy to shared cluster |
Application images use the same server/*/Dockerfile definitions as Kubernetes. crash-watch is built from infra/crash-watch/Dockerfile.
| Requirement | Notes |
|---|---|
| Linux x64 | Ubuntu 24.04 or similar |
| Docker + Compose v2 | See Install Compose below |
| Git + submodules | Clone per Linux Installation |
| Disk space | 10 GB+ free for image layers and volumes |
No Kubernetes, Pulumi, or host-native toolchain (GCC, CMake on host) required.
Ubuntu packages Docker and Compose separately. If docker compose version fails:
# Option A — plugin (recommended)
sudo apt-get update && sudo apt-get install -y docker-compose-plugin
docker compose version
# Option B — standalone binary (no apt plugin)
mkdir -p ~/bin
curl -SL "https://github.com/docker/compose/releases/download/v2.32.4/docker-compose-linux-x86_64" \
-o ~/bin/docker-compose && chmod +x ~/bin/docker-compose
export PATH="$HOME/bin:$PATH"Scripts under tools/compose-*.sh call docker compose. With the standalone binary, either install the plugin or alias:
alias docker='function _d(){ if [ "$1" = "compose" ]; then shift; ~/bin/docker-compose "$@"; else command docker "$@"; fi; }; _d'cp infra/compose/.env.example infra/compose/.env
# Set FB_HOST to your LAN IP if clients connect remotely
# Optional: set TABLE_PUBLISH_* for admin-tool runtime table patch (see below)
bash tools/compose-config.sh
bash tools/compose-build.sh
docker compose -f infra/compose/docker-compose.yml --profile infra --profile app up -dOr: bash tools/compose-up.sh
The admin-tool 패치 menu (테이블 / 스크립트) uploads files to HTTP storage and broadcasts a reload. Without these values the matching page shows that the feature is unavailable and does not send requests.
Add to infra/compose/.env (never commit real secrets):
TABLE_PUBLISH_UPLOAD_BASE_URL=http://cshyeon.com:8080/upload/fb/json
TABLE_PUBLISH_DOWNLOAD_BASE_URL=http://cshyeon.com:8080/fb/json
TABLE_PUBLISH_USERNAME=<same as GitHub NAS_ID>
TABLE_PUBLISH_PASSWORD=<same as GitHub NAS_PW>
SCRIPT_PUBLISH_UPLOAD_BASE_URL=http://cshyeon.com:8080/upload/fb/scripts
SCRIPT_PUBLISH_DOWNLOAD_BASE_URL=http://cshyeon.com:8080/fb/scripts
# Optional; defaults to TABLE_PUBLISH_* / same NAS credentials if omitted:
# SCRIPT_PUBLISH_USERNAME=
# SCRIPT_PUBLISH_PASSWORD=docker-compose.yml maps these to TablePublish__* / ScriptPublish__* environment variables for the admin-tool service.
tools/compose-build.sh compiles from source (first run can take hours). To smoke-test the stack with CI-built images:
for svc in data build gateway login game internal write-back log marketplace matchmaking admin-tool crash-watch; do
docker pull ghcr.io/boyism80/fb/${svc}:latest
docker tag ghcr.io/boyism80/fb/${svc}:latest fb/${svc}:local
done
bash tools/compose-config.sh
docker compose -f infra/compose/docker-compose.yml --profile infra --profile app up -dOptional profiles:
| Profile | Services |
|---|---|
infra |
mysql, redis, rabbitmq |
app |
internal, write-back, log, marketplace, matchmaking, admin-tool, gateway, login, game, game-cross, crash-watch |
Example:
docker compose --profile infra --profile app up -d| Service | Image | Purpose |
|---|---|---|
| mysql | mysql:8.0 |
Unified + world databases |
| redis | redis:7-alpine |
Cache / sessions |
| rabbitmq | rabbitmq:3-management |
AMQP (+ management UI on 15672) |
Volumes: mysql_data, redis_data — persist across restarts.
Published ports (dev defaults):
| Service | Host port |
|---|---|
| MySQL | 3306 |
| Redis | 6379 |
| RabbitMQ AMQP | 5672 |
| RabbitMQ management | 15672 |
| Internal (HTTP) | 3000 |
| Gateway (client TCP) | 3001 |
| Login (client TCP) | 3002 |
| Game (client TCP) | 3004 |
| Game cross (TCP) | 3100 |
| Marketplace (HTTP) | 3010 |
| Matchmaking (HTTP) | 3340 |
| Admin Tool (HTTP) | 3020 |
Migrations run via Internal on startup (Database:AutoMigration), not via MySQL init scripts.
Build from repo Dockerfiles:
| Service | Dockerfile | Depends on |
|---|---|---|
| internal |
server/http/Dockerfile (SERVICE=internal) |
mysql, redis, rabbitmq |
| write-back |
server/http/Dockerfile (SERVICE=write-back) |
mysql, redis, rabbitmq, internal |
| log |
server/http/Dockerfile (SERVICE=log) |
rabbitmq |
| marketplace |
server/http/Dockerfile (SERVICE=marketplace) |
mysql, internal |
| admin-tool |
server/http/Dockerfile (SERVICE=admin-tool) |
internal |
| matchmaking | server/matchmaking/Dockerfile |
rabbitmq |
| gateway | server/gateway/Dockerfile |
internal, rabbitmq |
| login | server/login/Dockerfile |
mysql, redis, internal |
| game | server/game/Dockerfile |
mysql, redis, rabbitmq, login, marketplace, matchmaking |
| game-cross |
server/game/Dockerfile (role: cross, port 3100) |
same as game |
| crash-watch | infra/crash-watch/Dockerfile |
gateway, login, game, game-cross; Docker socket |
Build order (matches CI):
-
fb/data:local—server/fb/data/Dockerfile -
fb/build:local—server/fb/Dockerfile -
fb/crash-watch:local—infra/crash-watch/Dockerfile - C++ then .NET service images (
tools/compose-build.sh)
Single Compose network (e.g. fb-dev). Services resolve each other by service name (mysql, internal, …).
FB_HOST — IP or hostname clients use to connect (same role as Pulumi host on Kubernetes):
- LAN: host machine IP
- Same machine:
127.0.0.1with published ports
Gateway / Login / Game / Game-cross configs must expose FB_HOST, not Docker internal DNS names.
DISCORD_BOT_TOKEN / DISCORD_CHANNEL_ID — optional Discord bot credentials for crash-watch. Empty disables Discord; the container still watches Docker deaths for gateway, login, game, and game-cross (needs /var/run/docker.sock).
Recommended approach: tools/compose-config.sh renders C++ configs from templates into infra/compose/config/ (gitignored): gateway, login, game, game-cross.
Example .env (see infra/compose/.env.example):
FB_HOST=192.168.1.100
MYSQL_ROOT_PASSWORD=admin
GATEWAY_PORT=3001
LOGIN_PORT=3002
GAME_PORT=3004
GAME_CROSS_PORT=3100
INTERNAL_PORT=3000
MATCHMAKING_PORT=3340
# Optional; empty disables Discord
DISCORD_BOT_TOKEN=
DISCORD_CHANNEL_ID=Replace <host> with FB_HOST from .env (LAN IP when clients connect remotely).
docker compose -f infra/compose/docker-compose.yml ps
# HTTP health
curl -sf http://<host>:3000/health # internal
curl -sf http://<host>:3010/health # marketplace
# Client TCP entrypoints
nc -zv <host> 3001 # gateway
nc -zv <host> 3002 # login
nc -zv <host> 3004 # game (home)
nc -zv <host> 3100 # game (cross)
curl -sf http://<host>:3340/health # matchmaking
# Infra
docker exec fb-mysql-1 mysqladmin ping -h127.0.0.1 -uroot -padmin
docker exec fb-redis-1 redis-cli pingOn first start, wait until Internal finishes migrations and Game logs show map/NPC loading at 100.00% (typically 30–60 seconds after up).
Connect game clients to Gateway at <host>:3001.
docker compose -f infra/compose/docker-compose.yml --profile infra --profile app down
docker compose -f infra/compose/docker-compose.yml down -v # also remove volumesGenerated configs (infra/compose/config/*/config.json) are gitignored; re-run tools/compose-config.sh before the next up.
| Symptom | Likely cause |
|---|---|
docker: unknown command: docker compose |
Compose v2 plugin not installed — see Install Compose v2 |
compose-build.sh very slow |
Expected on first run (C++ toolchain image); use pre-built images to skip |
| Client cannot connect |
FB_HOST still 127.0.0.1 while client is on another machine — set LAN IP in .env and re-run compose-config.sh
|
| Game CrashLoop | Infra not healthy; check docker compose ps and MySQL/Redis/RabbitMQ logs |
| No Discord crash alerts |
DISCORD_BOT_TOKEN / DISCORD_CHANNEL_ID empty in .env; crash-watch still logs to stdout |
| Admin 패치 pages unavailable |
TABLE_PUBLISH_* / SCRIPT_PUBLISH_* empty in .env — set upload/download URLs and NAS credentials, then recreate admin-tool |
| Port already in use | Host service bound to 3306, 3001, etc. — change ports in .env
|
infra/compose/
docker-compose.yml
config/ # appsettings + C++ templates
.env.example
README.md
tools/compose-config.sh
tools/compose-build.sh
tools/compose-up.sh
infra/crash-watch/Dockerfile