One VPS can comfortably host several CS 1.6 servers — the engine is light and a modern core has cycles to spare. The rules are simple: each instance needs its own UDP port, its own working directory for logs and configs, and its own process supervisor. This guide sets up three, but the pattern scales to as many as your CPU and bandwidth allow.
1. One base install, many instances
A full App 90 install is a few hundred megabytes, and copying it per server wastes disk and makes updates painful. Install it once, then create per-instance directories that share the read-only engine and mod files via hardlinks, keeping only configs and logs separate. Start from a working base at /home/steam/hlds (see the SteamCMD install), then:
cd /home/steam cp -al hlds server1 cp -al hlds server2 cp -al hlds server3
cp -al makes an archive copy with hardlinks: the binaries and maps occupy disk once, but each directory can hold its own cstrike/server.cfg, logs/, and banned.cfg. When you re-run app_update 90 on the base, hardlinked files update in place; regenerate the copies after a major engine change to be safe.
2. Give each instance its own port and identity
The engine's UDP port is set with -port. Use a clean numbering scheme so the firewall and your memory both stay sane:
| Instance | Directory | Port |
|---|---|---|
| server1 | /home/steam/server1 | 27015 |
| server2 | /home/steam/server2 | 27016 |
| server3 | /home/steam/server3 | 27017 |
Each instance's cstrike/server.cfg needs a distinct hostname and its own rcon_password. If the VPS has multiple public IPs you can instead bind each server to a different IP with -ip and reuse port 27015; most people just use different ports on one IP.
3. Start them by hand first
Prove each one boots before automating anything:
cd /home/steam/server1 ./hlds_run -game cstrike -strictportbind -ip 0.0.0.0 -port 27015 \ +map de_dust2 +maxplayers 20 +sv_lan 0 cd /home/steam/server2 ./hlds_run -game cstrike -strictportbind -ip 0.0.0.0 -port 27016 \ +map de_dust2 +maxplayers 20 +sv_lan 0
-strictportbind is important here: without it, a second server started on an already-used port silently grabs the next free one, and you end up with two servers on 27016 and none on 27015, wondering why a client cannot connect.
4. Manage them with a systemd template
Instead of one unit per server, write a single template unit parameterised by directory and port. Create /etc/systemd/system/[email protected]:
[Unit]
Description=CS 1.6 server (%i)
After=network.target
[Service]
Type=simple
User=steam
WorkingDirectory=/home/steam/%i
ExecStart=/home/steam/%i/hlds_run -game cstrike -strictportbind \
-ip 0.0.0.0 -port ${PORT} +map de_dust2 +maxplayers 20 +sv_lan 0
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.target
Because each instance needs a different port, drop an override per instance:
sudo systemctl edit hlds@server2
[Service] Environment=PORT=27016
Then enable and start each — the full template approach is covered in the systemd service guide:
sudo systemctl enable --now hlds@server1 sudo systemctl enable --now hlds@server2 sudo systemctl enable --now hlds@server3
5. Open the ports
sudo ufw allow 27015:27017/udp sudo ufw allow 27015:27017/tcp
The TCP range is for RCON. If you also run HLTV per instance, allocate a second block (27020+) and open it too — see which ports to open.
Common errors
- Two servers, one shows, one does not — a port collision the engine resolved silently. Add
-strictportbindand give each a unique-port. - Both servers write to the same log — they share a
cstrike/directory. Each instance needs its own directory (thecp -alcopies above). - RCON controls the wrong server — same
rcon_passwordand you connected to the wrong port. Use distinct passwords and connect by port. - High load with several full servers — you set an aggressive
sys_ticrate/-pingbooston every instance. FPS scales per process; do not run four servers each pinned at 1000 FPS on a two-core box.
Plan the resources honestly
Instances are cheap in disk but not free in CPU and bandwidth. A busy 32-slot server pushes real traffic, and running several full ones on a low-core VPS with an aggressive -pingboost or high sys_ticrate on each will starve them all. A useful rule of thumb: budget one physical core per busy public server if you want stable server FPS, and check your provider's bandwidth cap — several full servers can move a surprising amount of egress. Maps are shared through the hardlinked copies, so adding a custom map to the base and re-running cp -al propagates it without duplicating disk. Keep each instance's rcon_password distinct and stored only in that instance's cstrike/server.cfg, readable only by the steam user, so one leaked password does not hand over every server.
Verification
systemctl status 'hlds@*' ss -lunp | grep hlds
You should see one hlds_linux bound per port (27015, 27016, 27017). Connect a client to each port in turn and confirm the hostname differs. When all instances answer independently and survive a reboot, the multi-server setup is done.









