Skip to content

Installation Linux Compose

boyism80 edited this page Sep 18, 2026 · 5 revisions

Linux — Docker 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.


When to use Compose

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.


Prerequisites

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.

Install Compose v2

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'

Quick start

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 -d

Or: bash tools/compose-up.sh

Admin-tool table publish secrets (optional)

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.


Faster start with pre-built images

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 -d

Optional 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 layout

Infrastructure (profile: infra)

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.

Application services (profile: app)

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):

  1. fb/data:local — server/fb/data/Dockerfile
  2. fb/build:local — server/fb/Dockerfile
  3. fb/crash-watch:local — infra/crash-watch/Dockerfile
  4. C++ then .NET service images (tools/compose-build.sh)

Networking

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.1 with 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).

Configuration

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=

Verify deployment

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 ping

On 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.


Tear down

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 volumes

Generated configs (infra/compose/config/*/config.json) are gitignored; re-run tools/compose-config.sh before the next up.


Troubleshooting

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

Repository layout

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

Related pages

Clone this wiki locally