AOS REVIVALMenuJoin Discord
Server guide 04

Run several servers and update safely

One BattleSpades install can supervise many isolated servers — the ten official Match Lobby modes ship ready to launch together. This guide covers the fleet launcher, running as a service, and upgrading without losing data.

Checked BattleSpades 0.1.0-beta.19 minute read

The fleet launcher

--fleet <manifest> starts one child server per enabled [[instances]] entry, each with its own config, port and log. Config paths are resolved beside the manifest. Before anything starts, every config is validated and duplicate names or game ports are rejected. Ctrl+C sends a clean shutdown to every child and only force-stops a child that exceeds shutdown_timeout_seconds (1–60, default 10).

fleet.tomlTXT
[fleet]
shutdown_timeout_seconds = 10

[[instances]]
name = "Official TDM"
config = "configs/official-tdm.toml"
enabled = true

[[instances]]
name = "Official CTF"
config = "configs/official-ctf.toml"
enabled = true
# port = 27117   # optional: override this instance's [server] port
LaunchTXT
# Portable Windows release
.\BattleSpades.exe --fleet fleet.toml

# Source checkout
py -3.12 run_server.py --fleet fleet.toml

The ten official profiles

The shipped fleet.toml launches these profiles from configs/. Each uses the recovered retail map rotation and clock, backfills at most six bots with the crash-isolated process worker, and has its own game port, Steam ports and log file. AoSPlay and Steam publishing are disabled in all of them.

ProfileModeStart mapGame UDPSteam query / updater UDPClockBots
Official TDMconfigs/official-tdm.tomltdmMayanJungle2701527016 / 876615 min6 max (process)
Official CTFconfigs/official-ctf.tomlctfTokyoNeon2701727018 / 876730 min6 max (process)
Official Classic CTFconfigs/official-cctf.tomlcctfClassic2701927020 / 876890 min6 max (process)
Official Zombieconfigs/official-zombie.tomlzomSpookyMansion2702127022 / 876910 min6 max (process)
Official VIPconfigs/official-vip.tomlvipCityOfChicago2702327024 / 877015 min6 max (process)
Official Multi-Hillconfigs/official-multi-hill.tomlmhMayanJungle2702527026 / 877125 min6 max (process)
Official Territory Controlconfigs/official-territory-control.tomltcCityOfChicago2702727028 / 877225 min6 max (process)
Official Diamond Mineconfigs/official-diamond-mine.tomldiaArcticBase2702927030 / 877315 min6 max (process)
Official Demolitionconfigs/official-demolition.tomldemAtlantis2703127032 / 877415 min6 max (process)
Official Occupationconfigs/official-occupation.tomlocAncientEgypt2703327034 / 877515 min6 max (process)

To publish a fleet, give each profile its own public identity: enable [revival] per profile, register every game port, and run each with its own token (the fleet passes the parent's environment to every child, so separate launches or containers are simpler when each needs a different AOS_MASTER_WRITE_TOKEN). With Steam listing, forward each game and query port plus the Steam UDP ports 8766–8775 the profiles use.

Write your own profile

A profile is an ordinary config file; anything missing uses the built-in default (not the values in the big sample config.toml), so set the keys you care about explicitly.

configs/my-zombie.tomlTXT
[server]
name = "My Zombie Server"
port = 27041
max_players = 24

[game]
default_mode = "zom"
default_map = "SpookyMansion"

[lobby]
match_length_minutes = 10
map_rotation = ["SpookyMansion", "MayanJungle", "CastleWars"]

[bots]
enabled = true
population_mode = "backfill"
fill_target = 8
max_bots = 8
worker = "process"

[admin]
password = "another-long-unique-secret"
bans_path = "bans-zombie.json"

[revival]
enabled = false

[logging]
file = "my-zombie.log"
console = false

You can also run instances as completely separate processes: BattleSpades --config configs/my-zombie.toml (and --port to override the port once).

Keep it running as a service

The server stops cleanly on Ctrl+C, SIGINT and SIGTERM, so any service manager works. On Linux, systemd restarts it after a crash and starts it at boot.

/etc/systemd/system/battlespades.serviceTXT
[Unit]
Description=BattleSpades Ace of Spades server
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
User=battlespades
WorkingDirectory=/opt/battlespades
ExecStart=/opt/battlespades/BattleSpades --config /opt/battlespades/config.toml
Environment=AOS_MASTER_WRITE_TOKEN=aos_srv_...
Restart=on-failure
RestartSec=5

[Install]
WantedBy=multi-user.target
Enable and watch itTXT
sudo systemctl daemon-reload
sudo systemctl enable --now battlespades
journalctl -u battlespades -f

On Windows, the simplest option is a Task Scheduler task that runs BattleSpades.exe “At startup” with “Run whether user is logged on or not”, the server folder as “Start in”, and “If the task fails, restart every 1 minute”. For a source checkout run python run_server.py from its folder instead. --control-stdin lets a launcher stop the server by writing shutdown to its standard input.

Updating without losing data

Keep these across every upgrade — they are your data, not part of the program:

  • config.toml (and any configs/*.toml / fleet.toml you changed)
  • bans.json (or your bans_path)
  • state/round-results.sqlite3 — AoSPlay round results that were not yet uploaded
  • custom maps in maps/ (with their .txt/.json sidecars), prefabs, and your plugins
  • logs/ if you need history
  1. Test first

    Extract or build the new version in a separate folder and run it with --check, ideally on a spare port (--port 27099) for a quick join test.

  2. Announce

    Warn players with /say; a restart disconnects everyone.

  3. Stop

    Stop the old server (Ctrl+C or your service manager).

  4. Carry data over

    Copy the files above into the new folder. Compare your config.toml with the new sample for new keys; missing keys simply use defaults.

  5. Start

    Start the new version and watch the log for warnings.

Source checkout updateTXT
# stop the server first (compiled modules are locked while it runs)
git pull
python -m pip install -r requirements.txt
python setup.py build_ext --inplace
python run_server.py --check

The release packager refuses to overwrite an existing release folder on purpose, so a new portable version always lands next to the old one. Containers update by switching the image tag; see Docker.

Common questions

How many servers can one machine run?

It depends on CPU cores and memory. Each server simulates at 60 Hz and needs roughly 80–200 MB after loading a map, plus bots. Start small, watch tick stats in the logs, and add instances while they stay healthy.

Can two instances use the same port?

No. The fleet launcher refuses duplicate game ports, and the operating system would refuse the second socket anyway.

Will an update reset my bans?

Only if you forget to copy bans.json. Bans are stored in that file, keyed by IP address.