Counter-Strike 1.6 Server (Linux) ___ _ ___ _ _ _ / __| ___ _ _ _ _ | |_ ___ _ _ ___ / __| | |_ _ _ (_) | |__ ___ | (__ / _ \ | || | | ' \ | _| / -_) | '_| |___| \__ \ | _| | '_| | | | / / / -_) \___| \___/ \_,_| |_||_| \__| \___| |_| |___/ \__| |_| |_| |_\_\ \___| _ __ / | / / | | _ / _ \ |_| (_) \___/ ___ / __| ___ _ _ __ __ ___ _ _ \__ \ / -_) | '_| \ V / / -_) | '_| |___/ \___| |_| \_/ \___| |_| __ _ _ __ / / | | (_) _ _ _ _ __ __ \ \ | | | |__ | | | ' \ | || | \ \ / | | | | |____| |_| |_||_| \_,_| /_\_\ | | \_\ /_/ ╔─*──*──*──*──*──*──*──*──*──*──*──*──*──*──*──*──*──*──*──*──*──╗ ║1 ........................................................ 1║ ║2* ........................................................ *2║ ║3 ........................................................ 3║ ║1 ...................Posted: 2025-02-25................... 1║ ║2* Tags: linux cs16 debian gaming server nginx letsencrypt *2║ ║3 ........................................................ 3║ ║1 ........................................................ 1║ ╚────────────────────────────────────────────────────────────────╝ How to run a Counter-Strike 1.6[1] server in Linux (namely Debian). I even go into some bonus materials, like making bonus assets (maps, sounds, etc.) download quickly, making statistics accessible as JSON via HTTPS. I run my own Counter-Strike 1.6 server![2] Please check it out. On that page I also talk about my inspiration for starting a server and more. # Initial setup Helpful: * https://www.amoradi.org/20210912011151.html * I'm using gnu screen for now, because I'm too lazy to daemonize things properly, I guess, at the moment Get the basics set up: ``` sudo dpkg --add-architecture i386 sudo apt update sudo apt install libc6:i386 libncurses5:i386 libstdc++6:i386 -y mkdir ~/steamcmd && cd ~/steamcmd wget https://steamcdn-a.akamaihd.net/client/installer/steamcmd_linux.tar.gz tar -xvzf steamcmd_linux.tar.gz ./steamcmd.sh ``` Now you should be in `steamcmd`: ``` force_install_dir ./cs16/ login anonymous app_update 90 -beta beta validate quit ``` Now you should be back outside of `steamcmd`: ``` mkdir -p ~/.steam/sdk32/ ln -s /home/baudrillard/steamcmd/linux32/steamclient.so ~/.steam/sdk32/steamclient.so ``` You now might be able to: ``` cd ~/steamcmd/cs16 ./hlds_run -game cstrike +map de_dust2 +maxplayers 20 +port 27015 ``` Make a ufw rule for this service: ``` sudo ufw allow 27015/tcp sudo ufw allow 27015/udp ``` # Additional tweaks Edit `~/steamcmd/cs16/cstrike/server.cfg` (might not exist): some things to set: * `hostname "Your Server Name"` * `rcon_password "your_rcon_password"` * `mapcyclefile "mapcycle.txt"` * You may to get bot support from like ZBot or POD-Bot? ``` bot_add bot_quota 10 # Number of bots bot_difficulty 1 # 0 - Easy, 1 - Normal, 2 - Hard, 3 - Expert bot_prefix "" ``` To add maps check out: * https://gamebanana.com/mods/cats/5474?_sSort=Generic_MostLiked * Place the maps in something like `/home/someuser/steamcmd/cs16/cstrike/maps`* you can use this command to get the list of the maps to put in the file... * try using `cp -r` to merge directories * `for file in maps/*.bsp; do basename "$file" .bsp; done > mapcycle.txt` * Add the map name to `mapcycle.txt` * i should make a script ## Resource server I'm not sure if this is working. ``` sv_allowupload 1 sv_allowdownload 1 sv_downloadurl "http://cs16.someodd.zip/cstrike/" ``` you could just serve the same cstrike dir you're already serving! and then hide the server.cfg to hide the rcon. just modify the nginx config i have here. it'll make it super fast. add to the server block: ``` location /cstrike/ { root /home/someuser/steamcmd/cs16/; # Specific root for the cstrike directory index index.html index.htm; location = /cstrike/server.cfg { deny all; # Deny access to the server.cfg file, returning 403 Forbidden } try_files $uri $uri/ =404; # Correctly handle the file paths within cstrike } ``` this is working super fast! ## Bots Back up the entire directory first. ### installing metamod `cd ~/steamcmd` Before installing Podbot, you need to install Metamod, which is a plugin interface for Half-Life modifications that allows you to use plugins like Podbot. **Download Metamod**: Visit the Metamod website and download the latest version appropriate for your server (P or V depending on your server's OS). http://metamod.org/ (i downloaded the regular linux, not x64 version). **IMPORTANT NOTE STARTING WITH DEBIAN TRIXIE (13)** just use Metamod-p like from https://sourceforge.net/projects/metamod-p/files/Metamod-P%20Binaries/. **Extract the Files**: Unzip the downloaded file into the `cstrike/addons/` directory of your server. Something like this: ``` mkdir -p cs16/cstrike/addons/metamod/dlls tar -xf metamod-1.20-linux.tar.gz -C cs16/cstrike/addons/metamod/dlls ``` edit `c16/cstrike/liblist.gam` and edit the value of `gameddl_linux`: ``` gamedll_linux "addons/metamod/dlls/metamod.so" ``` ### installing podbot Download podbot, I got `podbot_full_V3B22.zip`. extract the files: ``` unzip podbot_full_V3B22.zip -d cs16/cstrike/addons/ ``` edit metamod's plugin config `cs16/addons/metamod/plugins.ini` (maybe create it?) and add the following line: ``` linux addons/podbot/podbot_mm_i386.so ``` now try starting the server! to debug (after launching server): ``` meta list ``` ### a bit of configuring podbot `cs16/cstrike/addons/podbot/podbot.cfg` you may want to make bots easier, i found them very elite by default: `pb_minbotskill 15` and `pb_maxbotskill 60` ### creating waypoints Sadly, I'm not sure you can automatically create waypoints. So you'll maybe have ot do some work, especially if you're using custom maps. No waypoint, no bots. Download waypoints here for podbot: * https://gamebanana.com/mods/cats/3524 * https://github.com/ggoulart/cs1.6-server-more-maps/tree/master/podbot/wptdefault If you can find a `.pwf` file online, then place it in the `cstrike/addons/podbot/wptdefault/` directory. It should be named like the map, just different extension. Personally I did something like this: ``` git clone https://github.com/ggoulart/cs1.6-server-more-maps/ mv cs1.6-server-more-maps/podbot/wptdefault cs16/cstrike/addons/podbot/wptdefault ``` To test the above I switched to as_oilrig and then tried adding bots with `pb add` in steamcmd on server (rcon troubles) If you can't find the waypoints online, you can create them manually using the Podbot menu in the game. 1. **Start the Server with the Map**:- Launch CS 1.6 and start a server with the map. 1. **Open the Podbot Menu**:- In the console, type `pb menu` to open the Podbot command menu. - Navigate to the Waypoint options. 1. **Create Waypoints**:- Use the menu to add waypoints manually. Walk around the map and place waypoints at strategic locations—pathways, sniping spots, common areas, etc. - Save the waypoints frequently to prevent data loss. 1. **Test the Waypoints**:- Add bots to see if they navigate using the newly created waypoints. Adjust if necessary how do i add bots by default? ### sort of unethical: fake clients #### installing amxmodx amxmodx is maybe worth reading about. make it seem like more people are on the server than there are to encourage people to join https://www.amxmodx.org/downloads.php ``` mkdir amx tar -xf amxmodx-1.8.2-base-linux.tar.gz -C amx/ tar -xf amxmodx-1.8.2-cstrike-linux.tar.gz -C amx/ cp -r amx/addons/amxmodx cs16/cstrike/addons/ ``` once again edit `cs16/cstrike/addons/metamod/plugins.ini`: ``` linux addons/amxmodx/dlls/amxmodx_mm_i386.so ``` **Configure Basic Settings**: - Navigate to `cstrike/addons/amxmodx/configs/` and adjust settings in the configuration files like `amxx.cfg`, `users.ini` (for admin privileges), and `plugins.ini` (for controlling which plugins are active). **Verify Installation**: - Restart your server. - Connect to your server and type `meta list` in the server console. You should see both Metamod and AMX Mod X listed as loaded. #### fakefull Downloads: https://forums.alliedmods.net/showthread.php?p=254620 ``` mv fakefull_original.amxx cs16/cstrike/addons/amxmodx/plugins unzip fakefull_original.zip -d fakefull cp -r fakefull/addons/amx/* cs16/cstrike/addons/amxmodx unzip botnames.zip -d cs16/cstrike/addons/amxmodx/configs/ chmod 644 cstrike/addons/amxmodx/plugins/fakefull_original.amxx ``` try adding this to your `cs16/cstrike/addons/amxmodx/configs/amxx.cfg`: ``` // ****************** FakeFull Settings ****************** //Turns Automatic mode on. //ff_players must be set higher then 0. //<1 = ON || 0 = OFF> ff_automode 1 //Minimal number of fake and real clients on the server. //Fake clients will be kicked so that the total players on the //Server equals this number. If there are more players than this //All the fake players will be gone. Do NOT set this at or aboive //your max player count or no one will be able to join //REQUIRED to be above 0 for Automatic mode. ff_players 3 //Delay between each fake client joins/leaves. //REQUIRED to be above 0 for Automatic mode and regular bot add. ff_delay 1 ``` edit `cstrike/addons/amxmodx/configs/plugins.ini` and add: ``` fakefull_original.amxx ``` i'm not sure why it's not picking up on my settings in `amxx.cfg` but try this in steamcmd: ``` amx_addfake 3 ``` at this point i see bot spectating but player count doesn't artificially increase #### making our own I'll make a repo for this and other mods... Set up the fake queries depedency. Download this https://forums.alliedmods.net/showthread.php?t=244450 and install: 1. Download `fakequeries_binary.zip` from the attachments. 1. Extract to game directory ``` unzip fakequeries_binary.zip -d cs16/cstrike/ ``` 1. Add "fake_queries" in your modules.ini (in `cs16/cstrike/addons/amxmodx/configs/modules.ini`). Now save below as `addons/amxmodx/scripting/botcount.sma`: ``` #include #include public plugin_init() { register_plugin("Count Bots as Players", "1.0", "someodd"); // Update player counts periodically without changing other server info set_task(1.0, "update_player_counts", _, _, _, "b"); } public update_player_counts() { // Calculate total players including bots new total_players = count_total_players(); new max_players = get_maxplayers(); // Use the server's configured max players // Set the fake server query responses for player and bot counts fq_set_players(total_players); // Total players including bots fq_set_botsnum(0); // Report 0 bots // Log the operation results log_status(fq_set_players(total_players), "players"); log_status(fq_set_maxplayers(max_players), "max players"); log_status(fq_set_botsnum(0), "bots"); } count_total_players() { new count = 0, maxPlayers = get_maxplayers(); for (new i = 1; i <= maxPlayers; ++i) { if (is_user_connected(i)) // Check if the slot is occupied count++; } return count; } log_status(result, const description[]) { if (result != 0) // Change to check for non-zero return, assuming non-zero means failure server_print("^4[Count Bots as Players]^1 Failed to set %s.", description); } ``` prepare: 1. `cd addons/amxmodx/scripting/` 1. compile with `./amxxpc botcount.sma` 1. put the result in the `addons/amxmodx/plugins` with `mv botcount.amxx ../plugins` 1. enable by adding `botcount.amxx` to `addons/amxmodx/configs/plugins.ini` #### making podbots less obviously bots finally make it less obvious that there's podbots. `cd cs16/cstrike/addons/podbot` edit `podbot.cfg` specifically these: * `pb_detailnames 0` * `pb_chat 0` * `pb_radio 0` * Finally read this section carefully. I thought just having four would be enticing to people, while being maybe kind of plausible if they all dropped off or something when there's not a waypoint file for next map or whatever: ``` # These lines below are adding automatically the bots to the server when^M # the new game is created on the listenserver or the dedicated server^M # is starting.^M # As many such lines like "pb add" is here as many bots will be added ^M # to the server (unless You will not exceed pb_maxbots setting).^M pb add 100^M pb add 100^M pb add 100^M pb add 100^M ``` Now edit the bot names in `botnames.txt`. #### restrict over-powered weapons with amxmodd enable restmenu in `cstrike/addons/amxmodx/configs/plugins.ini`: ``` restmenu.amxx ; restrict weapons menu ``` you'll also want to set up admin by editing `configs/users.ini` and adding your steam ID you may find from something like https://www.steamidfinder.com/lookup/someodd/ here i added: ``` "STEAM_0:0:854249781" "" "abcdefghijklmnopqrstu" "ce" ``` then in the console in game `~`: ``` amx_restmenu ``` or something like that? ## Set up statistics Basically assumes you have an nginx setup running, see my #nginx tag[3]. https://developer.valvesoftware.com/wiki/Server_queries#Goldsource_Server ``` sudo apt-get update sudo apt-get install qstat ``` Try this command: ``` % quakestat -a2s localhost:27015 ADDRESS PLAYERS MAP RESPONSE TIME NAME localhost:27015 0/20 0/0 de_dust 0 / 0 cstrike Counter-Strike 1.6 Server ``` then make this in `/usr/local/bin/cs_stats.sh`: ``` #!/bin/bash # Run quakestat and capture the output, skipping the header line output=$(quakestat -a2s localhost:27015 | tail -n +2) # Find the PID of the process named 'hlds_linux' PID=$(pgrep -f hlds_linux) # Check if the PID was found if [ -z "$PID" ]; then echo "Process not found." exit 1 fi # Calculate the uptime in days and store it in a variable uptime_days=$(ps -p $PID -o etime= | awk -F'[:-]' '{if (NF == 4) {print $1 " days"} else {print "0 days"}}') # Parse the output using awk json=$(echo "$output" | awk -v uptime="$uptime_days" ' BEGIN { # Initialize JSON string printf "{" } { # Split the players field into current and max players split($2, players, "/"); # Replace all double quotes with escaped double quotes in the server name gsub(/"/, "\\\"", $6); # Construct JSON printf "\"address\": \"%s\", ", $1; printf "\"currentPlayers\": \"%s\", ", players[1]; printf "\"maxPlayers\": \"%s\", ", players[2]; printf "\"map\": \"%s\", ", $4; printf "\"uptimeDays\": \"%s\"", uptime; # Add uptimeDays to the JSON } END { # Close JSON string printf "}" }') echo $json ``` then `sudo chmod +x /usr/local/bin/cs_stats.sh` ``` sudo mkdir /var/www/cs16.someodd.zip % sudo chown -R someuser:someuser /var/www/cs16.someodd.zip ``` edit `sudo vi /etc/nginx/sites-available/cs16.someodd.zip.conf`: ``` server { listen 8765; listen 8888 ssl; server_name cs16.someodd.zip; root /var/www/cs16.someodd.zip; ssl_certificate /etc/letsencrypt/live/cs16.someodd.zip/cert.pem; ssl_certificate_key /etc/letsencrypt/live/cs16.someodd.zip/privkey.pem; location /stats.json { # Add CORS headers add_header 'Access-Control-Allow-Origin' '*'; add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS'; add_header 'Access-Control-Allow-Headers' 'Origin, X-Requested-With, Content-Type, Accept'; add_header 'Access-Control-Allow-Credentials' 'true'; } location / { try_files $uri $uri/ =404; } } ``` ``` sudo ln -s /etc/nginx/sites-available/cs16.someodd.zip.conf /etc/nginx/sites-enabled/ ``` `crontab -e`: ``` */30 * * * * /usr/local/bin/cs_stats.sh > /var/www/cs16.someodd.zip/stats.json 2>&1 ``` Create the certificate or whatever I selected *webroot* when prompted): ``` sudo certbot certonly --webroot-path="/var/www/cs16.someodd.zip" -d 'cs16.someodd.zip' ``` maybe setup the hook for renewal edit `/etc/letsencrypt/renewal/cs16.someodd.zip.conf` under `[renewalparams]`: ``` renew_hook = service nginx restart ``` and maybe the other one in that config too... Validate that the above command works correctly: ``` sudo certbot renew --dry-run ``` ## Daemonize/autostart Let's basically daemonize my Counter Strike 1.6 server, using Systemd. It's a little tricky because I wanted to use `screen` (to look at the interactive server thingy) and we need to tell `systemd` to expect the process to fork (detach itself into the background), to treat the child process (not the parent) as the main process. This is the behavior of many legacy or standalone server programs, like `hlds_run`, which often daemonizes itself. We use a PID file to keep track of the PID of the child process. This way `systemd` will know which process to monitor. Otherwise, `systemd` will just see that the startup script we made exits and assume the service isn't running anymore. Here's my normal start command: ``` ./hlds_run -game cstrike +map de_dust2 +maxplayers 20 +port 27015 ``` I actually like being able to use the terminal in there... So I like using `screen`. Write a startup script, which I actually just put as my `~/steamcmd/cs16/start_cs16.sh`: ``` #!/bin/bash # Change to the server directory cd /home/baudrillard/steamcmd/cs16 || exit # Start the server inside a named screen session screen -dmS cs_server ./hlds_run -game cstrike +map de_dust2 +maxplayers 16 -port 27015 # Get the PID of the screen session and write it to the PID file screen_pid=$(screen -ls | grep cs_server | awk '{print $1}' | cut -d. -f1) echo $screen_pid > /home/baudrillard/steamcmd/cs16/hlds.pid ``` Mark it as executable: ``` chmod +x ~/steamcmd/cs16/start_cs16.sh ``` Now let's make it a Systemd service by creating this service file `/etc/systemd/system/cs16.service` (be sure to change the paths, user, etc.): ``` [Unit] Description=Counter-Strike 1.6 Server After=network.target [Service] type=forking PIDFile=/home/baudrillard/steamcmd/cs16/hlds.pid User=baudrillard Group=baudrillard WorkingDirectory=/home/baudrillard/steamcmd/cs16 ExecStart=/bin/bash /home/baudrillard/steamcmd/cs16/start_cs16.sh ExecStop=/usr/bin/screen -S cs_server -X quit Restart=always [Install] WantedBy=multi-user.target ``` Now try to enable and start the service: ``` sudo systemctl enable cs16.service sudo systemctl start cs16.service ``` Now let's check screen: ``` screen -ls ``` Tap into it: ``` screen -r cs_server ``` You can detach by doing `ctrl+a` followed by `d`. Debugging service help: ``` sudo journalctl -u cs16.service -e ``` # Linux client setup You can try using Steam: ``` sudo dpkg --add-architecture i386 sudo apt-get update sudo apt-get install steam-installer ``` I had trouble using Steam from the Debian Sid repo, so I instead used the Steam flatpak[4]: ``` flatpak install ./com.valvesoftware.Steam.flatpakref flatpak run com.valvesoftware.Steam ``` # todo i want to add quake sounds # See also * Counter-Strike 1.6 on GameBanana[5], a good place to get mods (like maps) for CS1.6 * My CS1.6 server[6] ## Footnotes [1]: Counter-Strike 1.6: https://en.wikipedia.org/wiki/Counter-Strike_(video_game) [2]: I run my own Counter-Strike 1.6 server!: /0/services/counter-strike.md [3]: #nginx tag: /tags/#nginx [4]: used the Steam flatpak: https://flathub.org/apps/com.valvesoftware.Steam [5]: Counter-Strike 1.6 on GameBanana: https://gamebanana.com/games/4254 [6]: My CS1.6 server: /services