cs16-dm-server: CS 1.6 deathmatch server in Docker
One-command setup (SteamCMD + pinned, checksum-verified ReHLDS / ReGameDLL / Metamod-R / AMXX / ReAPI / ReUnion / CSDM-ReAPI / YaPB / GunGame), .env settings, ./cs menu (map, DM/GunGame mode, bots, kill counter, restart, update), own plugins (extras, rtv, mode switch), all-time kill counter, watchdog + nightly backup, docs for admins and players. Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
commit
7e9cbee14d
33 files changed
+1890
No files matched your search
@@ -0,0 +1,91 @@
|
||||
# Running the server
|
||||
|
||||
Start with `./cs`, the menu that covers day-to-day use. This page covers everything else. The paths below are relative to the repo folder.
|
||||
|
||||
## Admins (in-game admin menu)
|
||||
|
||||
1. While the person is on the server, run `./rcon status` and copy their ID from the `uniqueid` column (`STEAM_0:1:12345678`).
|
||||
2. Add a line at the end of `hlds/cstrike/addons/amxmodx/configs/users.ini`:
|
||||
```
|
||||
"STEAM_0:1:12345678" "" "abcdefghijklmnopqrstu" "ce"
|
||||
```
|
||||
The flags `abcdefghijklmnopqrstu` mean all rights. `ce` means "match by SteamID, no password".
|
||||
3. Run `./rcon amx_reloadadmins`, or wait for the next map.
|
||||
4. In game the admin opens the console and types `amxmodmenu`. From there they can kick, ban (by SteamID), change the map, and start votes.
|
||||
|
||||
Don't ban by IP (`addip`, or `amx_banip`) when players come through a tunnel like playit. Everyone shares one IP there, so an IP ban kicks everybody.
|
||||
|
||||
Setup keeps `users.ini` when you re-run it.
|
||||
|
||||
## RCON from inside the game
|
||||
|
||||
The password is in `secrets/rcon-password.txt`. In the game console:
|
||||
```
|
||||
rcon_password <the password>
|
||||
rcon changelevel de_nuke
|
||||
```
|
||||
`./rcon` on the server does the same without the password ever leaving the machine.
|
||||
|
||||
To change the password, put a new one in `secrets/rcon-password.txt`, then run `./cs restart`.
|
||||
|
||||
## Maps
|
||||
|
||||
The default mapcycle has 11 stock maps with deathmatch spawn points: de_dust2, de_inferno, de_nuke, de_train, cs_office, de_aztec, de_dust, cs_italy, de_cbble, de_prodigy and cs_assault. Every stock map works with `./cs map`.
|
||||
|
||||
To add a custom map:
|
||||
1. Copy `mapname.bsp` into `hlds/cstrike/maps/`. If the map comes with extra files (`.wad`, `.res`, `sound/`, `models/`, `gfx/`), copy those into `hlds/cstrike/` with the same folder layout.
|
||||
2. Add `mapname` as a line in `hlds/cstrike/mapcycle.txt`, which controls rotation and the rtv vote.
|
||||
3. **Spawn points:** without a spawn file, deathmatch uses the map's normal team spawns. That works, but people spawn in two clumps. To add proper spawn points, give yourself admin (see above) and type `csdm_edit_spawns` in the console on that map. Save, and the file lands in `addons/amxmodx/configs/csdm/spawns/mapname.spawns.cfg`. For GunGame to use the same points, also run `ln -s spawns/mapname.spawns.cfg hlds/cstrike/addons/amxmodx/configs/csdm/mapname.spawns.cfg` from the repo folder.
|
||||
4. **Bots** download navigation for well-known maps automatically. On unknown maps they learn as they go, and they're clumsy at first.
|
||||
|
||||
**Fast downloads:** the game's built-in download is slow (and slower through a tunnel). Put a copy of the custom maps and sounds on any web server, laid out like `cstrike/` (`maps/`, `sound/`, ...). Then add this to `hlds/cstrike/custom.cfg`:
|
||||
```
|
||||
sv_downloadurl "http://your.site/cstrike/"
|
||||
```
|
||||
|
||||
## Changing settings
|
||||
|
||||
- `.env`: name, password, slots, port, first map, bots. Then run `./cs apply`.
|
||||
- `hlds/cstrike/custom.cfg`: any server cvar. It applies on the next map (`./cs map <current map>` to apply now).
|
||||
- `hlds/cstrike/addons/amxmodx/configs/csdm/config.ini`: deathmatch settings (respawn time, spawn protection, gun menu contents, `free_for_all = 0` for team DM). Setup keeps your copy.
|
||||
- `hlds/cstrike/addons/amxmodx/configs/gungame.cfg`: GunGame (weapon order, kills per level, warmup). This file comes from the repo, so a setup re-run replaces it. To keep GunGame changes, put the `gg_...` lines in `custom.cfg` instead.
|
||||
- Extras cvars, all of which also go in `custom.cfg`: `esef_kill_hp` (10), `esef_kill_hp_hs` (20), `esef_damage` (1), `esef_sounds` (1), `esef_hudinfo` (1). Set any of them to `0` to turn it off.
|
||||
|
||||
## Backups
|
||||
|
||||
`./scripts/install-cron.sh` runs `scripts/backup.sh` every night at 04:30. It writes `backups/cs16-YYYY-MM-DD.tar.gz` and keeps 14 days. The backup holds `.env`, secrets, `mapcycle.txt`, `custom.cfg`, the AMXX configs, stats, the GunGame stats and the kill tally. The game itself isn't included (setup downloads it again). The backups sit on the same disk as the server, so copy them somewhere else if that matters to you.
|
||||
|
||||
To restore one file, run this from the repo folder: `tar xzf backups/cs16-<date>.tar.gz <path inside>`.
|
||||
|
||||
The backup also deletes server logs older than 30 days. Before it does, it adds their kills to the counter, so the all-time total keeps counting.
|
||||
|
||||
## Watchdog
|
||||
|
||||
The same cron install runs `scripts/watchdog.sh` every 5 minutes. If the server stops answering for about 15 minutes while its container is "running", the watchdog restarts it and writes a line to `watchdog.log`. Crashes are handled by Docker itself (`restart: unless-stopped`). After a crash, `docker inspect -f '{{.RestartCount}}' cs16` counts how many restarts there have been.
|
||||
|
||||
## More than one server
|
||||
|
||||
Clone the repo again **into a folder with a different name**, for example `git clone <repo url> cs16-gg`. Docker Compose names a project after its folder, so two folders that are both called `cs16-dm-server` would control each other's container. Then give the new server its own settings before setup:
|
||||
|
||||
```sh
|
||||
cd cs16-gg
|
||||
cp .env.example .env # then edit: CS_PORT=27016, CS_NAME=cs16-gg (both must differ from the first server)
|
||||
./setup.sh
|
||||
./scripts/install-cron.sh
|
||||
```
|
||||
|
||||
Every folder is independent: its own game files, configs, stats and cron lines.
|
||||
|
||||
## Logs and privacy
|
||||
|
||||
- `docker logs cs16` or `./cs logs` shows the live console. `./cs logs` hides password lines.
|
||||
- `hlds/cstrike/logs/` has one file per map: kills, chat, connects. HLDS also writes every cvar into these files at each map change, **including the join password**. Don't paste them publicly.
|
||||
|
||||
## Uninstall
|
||||
|
||||
```sh
|
||||
./scripts/install-cron.sh --remove
|
||||
docker compose down
|
||||
cd .. && rm -rf cs16-dm-server # everything lives in this folder
|
||||
docker image rm cs16-dm-server:local
|
||||
```
|
||||
@@ -0,0 +1,85 @@
|
||||
# How it works
|
||||
|
||||
## The stack
|
||||
|
||||
| Part | Version | Why |
|
||||
|---|---|---|
|
||||
| HLDS app 90, beta `steam_legacy` | (frozen branch) | Valve's dedicated server. ReHLDS needs engine build ≤ 8684, so the legacy branch is used |
|
||||
| [ReHLDS](https://github.com/rehlds/ReHLDS) | 3.15.0.896 | drop-in engine with fixes and better performance; replaces `engine_i486.so`, `hlds_linux` etc. |
|
||||
| [ReGameDLL_CS](https://github.com/rehlds/ReGameDLL_CS) | 5.30.0.814 | drop-in game logic (`cstrike/dlls/cs.so`) with `mp_freeforall`, `mp_forcerespawn` and more |
|
||||
| [Metamod-R](https://github.com/rehlds/Metamod-R) | 1.3.0.149 | plugin loader; `liblist.gam` points the game at it |
|
||||
| [AMX Mod X](https://www.amxmodx.org) | 1.10.0.5486 | scripting platform for the plugins |
|
||||
| [ReAPI](https://github.com/rehlds/ReAPI) | 5.29.0.358 | AMXX module that gives plugins access to ReHLDS/ReGameDLL hooks |
|
||||
| [ReUnion](https://github.com/rehlds/ReUnion) | 0.2.0.25 | lets non-Steam clients (protocol 47/48) join |
|
||||
| [CSDM-ReAPI](https://github.com/wopox1337/CSDM-ReAPI) | 1.0.8 | deathmatch: respawn, gun menu, spawn points, spawn protection |
|
||||
| [YaPB](https://github.com/yapb/yapb) | 4.4.957 | bots (Metamod plugin) |
|
||||
| [GunGame](https://github.com/fysiks1/amxx-gungame_cstrike) | 2.13c | GunGame mode, compiled from source by setup |
|
||||
|
||||
`tools/versions.txt` pins every download by URL and sha256. If anything upstream changes a file, setup stops instead of installing it.
|
||||
|
||||
## Install flow (`setup.sh`)
|
||||
|
||||
1. Creates `.env` and asks the questions. Generates `secrets/rcon-password.txt` and `secrets/reunion-salt.txt`, which are kept forever. The salt derives non-Steam players' IDs, so a new salt would reset their stats and admin entries.
|
||||
2. Builds the image: Debian bookworm, 32-bit libs, SteamCMD, unzip/xz.
|
||||
3. Downloads the game with SteamCMD, anonymously, with up to 4 tries, because app 90 often fails the first time. It runs `validate` only on the very first download. Later, validate would put back Valve's version of files you edited, and it also silently removes ReHLDS and Metamod.
|
||||
4. `tools/install-addons.sh` runs inside the image (repo mounted read-only, only `dl/` writable):
|
||||
- downloads and checks the pinned files
|
||||
- unpacks ReHLDS, then sets its exec bits, which the zip loses
|
||||
- unpacks ReGameDLL and comments out the `sv_alltalk 0` that its `game.cfg` would force on every map
|
||||
- unpacks Metamod and points `liblist.gam` at it (a copy of the original is kept as `liblist.gam.orig`)
|
||||
- unpacks AMXX, ReAPI and ReUnion. ReUnion gets the salt and `IDClientsLimit 0`, so several non-Steam players with the same placeholder ID can all join.
|
||||
- unpacks CSDM-ReAPI and the spawn files. de_prodigy and de_train are in CSDM 2.1's old 6-field format and get converted to the 10 fields CSDM-ReAPI reads, because it silently skips lines with any other count. Symlinks one folder up let GunGame find the files too.
|
||||
- unpacks YaPB, with `chmod 775` on its folders (the tarball's folders have no x bit, so the bots couldn't save their path caches), `yb_csdm_mode 2` (FFA-aware) and `yb_quota_mode fill`
|
||||
- copies the GunGame source, lang file and sounds, plus the 14 announcer sounds
|
||||
- copies `cstrike/` from the repo over the game
|
||||
- compiles `rtv`, `esef_extras`, `esef_mode` and `gungame` with AMXX's `amxxpc`
|
||||
- leaves exactly one of `plugins-CSDM_ReAPI.ini` / `plugins-gungame.ini` active. It keeps the mode that was running before, or uses `CS_MODE` on the first install.
|
||||
- symlinks `steamclient.so` into `~/.steam/sdk32`. Without it you get "Unable to initialize Steam" in Docker.
|
||||
- saves and restores what people edit: `users.ini`, `amxx.cfg`, `csdm/config.ini`. `mapcycle.txt` and `custom.cfg` are only written on the first install.
|
||||
5. Stops the old container if it's running (the engine files are in use), starts the server, and waits until it answers an A2S query.
|
||||
|
||||
## At every container start (`tools/start.sh`)
|
||||
|
||||
- writes `cstrike/env.cfg` (hostname) and `cstrike/secrets.cfg` (RCON + join password, mode 600) from `.env` and `secrets/`
|
||||
- sets `yb_quota` / `yb_difficulty` in `addons/yapb/conf/yapb.cfg` from `CS_BOTS` / `CS_BOT_DIFFICULTY`
|
||||
- runs `hlds_run -game cstrike -port $CS_PORT +maxplayers $CS_MAXPLAYERS +map $CS_MAP -pingboost 2 -norestart +log on`
|
||||
|
||||
`server.cfg` runs `env.cfg`, then `secrets.cfg`, then `custom.cfg`, on every map.
|
||||
|
||||
## Game modes
|
||||
|
||||
`esef_mode` (own plugin) is a server command: `esef_mode`, `esef_mode dm` or `esef_mode gg`. AMXX reads every `configs/plugins-*.ini` at each map change, so a mode is simply which plugin list is named `.ini` and which is named `.ini.off`. The plugin renames them, then reloads the map. The rename stays on disk, so the mode survives restarts.
|
||||
|
||||
GunGame settings (`configs/gungame.cfg`):
|
||||
- free for all: `gg_tk_penalty -1`, plus `mp_freeforall 1` in `gg_map_setup`
|
||||
- bomb and hostages blocked
|
||||
- 30 s knife warmup, 1 s respawn, 30 min maps
|
||||
- 2 kills per level
|
||||
|
||||
`gg_map_setup` also switches off the respawn cvars CSDM leaves behind (`mp_forcerespawn 0`, `mp_respawn_immunitytime 0`). CSDM sets them again in dm mode.
|
||||
|
||||
**Important:** GunGame needs the AMXX modules `cstrike`, `fakemeta` and `hamsandwich`. They're listed in `configs/modules.ini` so they load at server start. If they load later, on the first GunGame map, they miss the game's message registration and the server crashes when a player joins (`PF_MessageBegin_I: bogus message type ( 0 )`). Because of this, Metamod logs `Not loading plugin 'CStrike'; already loaded` on every map. Those errors are harmless. Never add `reapi` to `modules.ini`: AMXX autoloads it, and listing it loads it twice.
|
||||
|
||||
## Own plugins (`plugins/`)
|
||||
|
||||
- **esef_extras:** damage numbers (DHUD; blue = dealt, red = taken, real HP lost), killstreak announcements at 3/5/7/9/11/13/15 (to everyone), multikills within 2 s (to the killer), headshot / knife / first blood sounds, +HP per kill (capped at 100), and a "K D | streak (best)" HUD line that hides itself in GunGame.
|
||||
- **rtv:** a minimal rock-the-vote. 60% of players (`amx_rtv_ratio`) starts a 15 s vote between 5 random mapcycle maps. It's blocked in the first 2 minutes (`amx_rtv_delay`) and in the last 3 minutes, when mapchooser's end-of-map vote runs.
|
||||
- **esef_mode:** the mode switch described above.
|
||||
|
||||
## Server settings worth knowing (`cstrike/server.cfg`)
|
||||
|
||||
- `sv_lan 0`: has to stay 0 even for VPN or tunnel players, because they aren't "LAN" to the engine.
|
||||
- `sv_rehlds_maxclients_from_single_ip 16`: a tunnel like playit delivers every player from one IP.
|
||||
- `sv_rcon_banpenalty 1`: a wrong RCON password bans the source IP for 1 minute instead of forever, which matters when everyone shares the tunnel's IP.
|
||||
- `sv_rcon_condebug 0`: RCON commands contain the password, so they aren't echoed to the console or `docker logs`.
|
||||
- `sys_ticrate 300`: plenty for DM, and it keeps CPU use low.
|
||||
|
||||
## Crash handling
|
||||
|
||||
- **Crash:** the container runs with `init: true`, so tini is PID 1, and hlds runs with `-norestart`. When hlds dies the container exits and Docker's `restart: unless-stopped` starts it again. Without `-norestart`, hlds_run's own restart loop can hang after a crash, with the container still showing "running". Core dumps are off (`ulimits: core: 0`), because a single crash writes ~170 MB.
|
||||
- **Hang:** `scripts/watchdog.sh` runs from cron and A2S-queries the server. After 3 failed checks in a row it runs `docker restart`.
|
||||
- **Logs:** Docker's json log is capped at 3 × 10 MB. `scripts/backup.sh` deletes game logs older than 30 days, after counting their kills.
|
||||
|
||||
## Kill counter
|
||||
|
||||
`./kills` counts the `"X<..>" killed "Y<..>" with "weapon"` lines in `hlds/cstrike/logs/*.log`, keeping the counts per log file in `kills-tally.json`. Because the counts live in that file, the totals survive the 30-day log cleanup.
|
||||
@@ -0,0 +1,48 @@
|
||||
# Joining the server
|
||||
|
||||
Send this page to your players along with the server address (for example `1.2.3.4:27015` or a playit address like `something.ply.gg:12345`).
|
||||
|
||||
## Steam version
|
||||
|
||||
1. Install **Counter-Strike** (1.6) from Steam.
|
||||
2. Turn on the console: **Options → Keyboard → Advanced → Enable developer console**.
|
||||
3. In the main menu press **~** (the key under Esc) and type:
|
||||
```
|
||||
connect 1.2.3.4:27015
|
||||
```
|
||||
4. To find it again later: **Find Servers → Favorites → Add a server**, then enter the same address.
|
||||
|
||||
The first time you join, the game downloads ~2 MB of sounds. After that, joining is instant.
|
||||
|
||||
## Non-Steam clients
|
||||
|
||||
Non-Steam builds that speak protocol 47 or 48 can join (the server runs ReUnion). Use the same `connect` command in the console.
|
||||
|
||||
## In-game
|
||||
|
||||
| Type in chat | What it does |
|
||||
|---|---|
|
||||
| `guns` | reopen the deathmatch gun menu |
|
||||
| `rtv` | vote to change the map (needs 60% of players; not in the first 2 or the last 3 minutes) |
|
||||
| `/rank`, `/top15`, `/stats` | your rank, top 15, your stats |
|
||||
| `!rules`, `!level`, `!score`, `!top`, `!weapons` | GunGame info (GunGame mode only) |
|
||||
|
||||
How the game works here:
|
||||
- **Deathmatch:** free for all, so shoot anyone. You respawn in under a second with 2 seconds of spawn protection, and pick your guns from the menu.
|
||||
- **Every kill gives you HP:** +10, or +20 for a headshot, up to 100.
|
||||
- **Numbers on screen:** blue numbers are damage you dealt, red numbers are damage you took.
|
||||
- **Announcer:** killstreaks at 3, 5, 7… kills are announced to everyone. Fast double, multi, ultra and monster kills are announced to you.
|
||||
- **GunGame mode:** every 2 kills you move to the next weapon, from glock up to the knife. The first player to finish the knife level wins the map.
|
||||
- **Bots:** they leave the server as people join.
|
||||
|
||||
## Tips for smoother play
|
||||
|
||||
Put these in the console. They're the usual settings for 1.6 online:
|
||||
|
||||
```
|
||||
rate 100000
|
||||
cl_updaterate 102
|
||||
cl_cmdrate 105
|
||||
ex_interp 0.01
|
||||
fps_max 100
|
||||
```
|
||||
Reference in new issue
Block a user