One install, many servers — bound together, kept up to date.
Linux CLI for Pelican Wings hosts. One main game server holds the real install; child servers share those files via bind mounts. A cron tick checks for Steam updates, restarts servers only when empty, and keeps children in sync — without every server running its own SteamCMD copy.
Large games (e.g. CS2) can take tens of gigabytes per server. With N independent installs you pay that cost N times. This tool keeps one full install on the main volume and bind-mounts the shared tree onto each child. Per-server files (configs, addons, maps you want independent) stay excluded by the game profile — so you keep distinct servers without duplicating the bulk game data.
- Linux Wings host with bind-mount support (run as root)
- Pelican Client API key (
ptlc_…) with access to all configured servers - Query host/port per server (to check the server for players)
- For Steam profiles: children must not run their own SteamCMD update (disable within Pelican Webinterface)
- Download the latest release for your architecture from GitHub Releases.
- Install the binary and config into one directory (e.g.
/opt/pelican-bindup/):
install -m 755 pelican-bindup_linux_amd64 /opt/pelican-bindup/pelican-bindup
cp config.yaml.example /opt/pelican-bindup/config.yaml- Edit
config.yaml— panel URL, API key, server UUIDs, query addresses. - Verify connectivity:
/opt/pelican-bindup/pelican-bindup test- Add the cron entries below.
Config and sidecar files (config.state.yaml, config.lock, optional log) live next to the binary by default. Override with -config /path/to/config.yaml.
Important: You need one fully installed game server acting as the main server. For every child:
Fully install the game server once, or create the server in Pelican and skip installation. Sync data from the main server with this tool. Manually copy any files still missing (see Profiles below) before the first start. Skipping step 3 often causes crashes on first launch because required data is still missing.
See config.yaml.example for the full reference. A group is one main plus its children:
groups:
- name: cs2-example
profile: cs2
main:
uuid: ...
query_host: server.example.com
query_port: 27015
children:
- uuid: ...
query_host: server.example.com
query_port: 27016
- uuid: ...
query_host: server.example.com
query_port: 27017
# Optional: use another profile's sync exclusions / query_protocol.
# Files still come from main; Steam/FSM still follow the group profile.
# profile: warforkbfbc2- syncs everything; except instance/ and *.inibfbc2- syncs everything; except instance/, dist/ and *.ini
cs2- syncs everything; except game/csgo/addons and game/csgo/cfg
warfork- syncs everything; except basewf/data.pk3* and basewf/modules.pk3*
| Command | Description |
|---|---|
run |
Cron tick — update orchestration and reboot |
sync |
Re-apply bind mounts (needed after reboot) |
test |
Verify panel, Steam (if used), query, Discord |
status |
Show group phases and server states |
Useful flags: -config, -mode prod|dry-run|check-only, -group <name>.
pelican-bindup run -mode dry-run # preview a tick
pelican-bindup sync -group cs2-exampleRun as root on the Wings host. Config must sit next to the binary (or pass -config).
# Every 5 minutes — update orchestration / reboot
*/5 * * * * /opt/pelican-bindup/pelican-bindup run > /dev/null 2>&1
# After reboot — re-apply bind mounts (mounts do not survive reboot)
@reboot /opt/pelican-bindup/pelican-bindup sync > /dev/null 2>&1To keep a log file instead of discarding output, redirect to a path (e.g. >>/var/log/pelican-bindup.log 2>&1). A ready-to-edit copy is in docs/crontab.example.
Requires Docker (no Go on the host):
make build # linux/amd64 → dist/
make build-all # linux amd64 + arm64