[ L4D2 Server — Install Guide ]

Step-by-step guide for installing a Left 4 Dead 2 dedicated server with SourceMod and MetaMod:Source on a fresh Debian or Ubuntu VPS. Covers everything from base OS prep through to a working SourceMod console you can load plugins onto. Once this is done, the L4D2 Stats Install Guide covers adding persistent player stats with a web UI on top.

[ Overview ]

Assumptions

  - Fresh Debian 12+ or Ubuntu 22.04+ VPS
  - ~10 GB free disk, 2 GB+ RAM
  - Non-root user with sudo (commands below assume your user, not root)
  - Open ports: 27015/udp (game), 27020/udp (SourceTV)

Time estimate

30–60 minutes including the ~10 GB game file download. Most of that is wall time waiting on SteamCMD.


[ 1. Prep the system ]

L4D2 dedicated server is a 32-bit (i386) binary. Multi-arch is required.

sudo dpkg --add-architecture i386
sudo apt update
sudo apt upgrade -y
sudo apt install -y curl wget file tar bzip2 gzip unzip bsdmainutils \
    python3 util-linux ca-certificates binutils bc jq tmux netcat-openbsd \
    lib32gcc-s1 lib32stdc++6 libcurl4-openssl-dev:i386 libsdl2-2.0-0:i386

(libsdl2-2.0-0:i386 is what L4D2 needs at runtime; missing it = silent crash on first launch.)


[ 2. Create a dedicated user ]

Never run game servers as root.

sudo adduser --disabled-password --gecos "" l4d2server
sudo passwd l4d2server   # set a password if you want SSH access
sudo su - l4d2server

The rest of the guide runs as l4d2server.


[ 3. Install LinuxGSM ]

LinuxGSM is the standard wrapper for Source-engine dedicated servers — handles updates, start/stop, monitoring, console capture.

wget -O linuxgsm.sh https://linuxgsm.sh
chmod +x linuxgsm.sh
bash linuxgsm.sh l4d2server

This downloads the LinuxGSM script tailored for L4D2 and saves it as l4d2server in your home directory.


[ 4. Install the game files ]

./l4d2server install

The installer will:

  - Check dependencies
  - Prompt for hostname, rcon password, admin SteamID (you can leave
    blanks and edit later)
  - Run SteamCMD to download ~10 GB of L4D2 server files (takes 5-20 min
    depending on connection)

When it finishes you should see Install complete and the prompt comes back.


[ 5. Get a Steam Game Server Login Token (GSLT) ]

Required to show up as a public server (without one, your server is invisible to the in-game browser).

  1. Open https://steamcommunity.com/dev/managegameservers in your browser
  2. Sign in with a Steam account
  3. Create a GSLT for App ID 222860 (L4D2)
  4. Give it a memo like "my-l4d2-vps"
  5. Copy the token string

On the VPS:

nano ~/lgsm/config-lgsm/l4d2server/l4d2server.cfg

Add (or uncomment and set):

gslt="YOUR_TOKEN_HERE"

Save (Ctrl+O, Enter, Ctrl+X).


[ 6. Configure server basics ]

Edit the gameplay config:

nano ~/serverfiles/left4dead2/cfg/server.cfg

Minimum useful contents:

hostname "My L4D2 Server"
sv_search_key "anything"
rcon_password "USE_OPENSSL_RAND_HEX_24"
sv_lan 0
mp_gamemode "coop"
sv_allow_lobby_connect_only 0
sv_steamgroup_exclusive 0
sv_region 1

Generate a strong RCON password with openssl rand -hex 24 (run in another terminal). Don't paste passwords anywhere afterward.

LinuxGSM-specific config (start parameters, hostname, etc.) lives in ~/lgsm/config-lgsm/l4d2server/l4d2server.cfg. The two configs are loaded at different times — l4d2server.cfg (LinuxGSM) is for startup parameters, server.cfg (game engine) is exec'd on each map load.


[ 7. Patch executable stack flags (required on modern Linux) ]

Modern Linux kernels refuse to load shared libraries flagged with executable stacks. L4D2's bundled .so files have this flag set, causing the server to fail silently on startup.

Save this Python script as ~/clear_execstack.py:

#!/usr/bin/env python3
import os, struct, sys

def clear_execstack(path):
    with open(path, 'r+b') as f:
        if f.read(4) != b'\x7fELF':
            return False
        f.seek(0x10)
        e_type = struct.unpack('<H', f.read(2))[0]
        if e_type not in (2, 3):  # EXEC or DYN
            return False
        f.seek(0x20)
        e_phoff = struct.unpack('<I', f.read(4))[0]
        f.seek(0x2A)
        e_phentsize = struct.unpack('<H', f.read(2))[0]
        e_phnum = struct.unpack('<H', f.read(2))[0]
        for i in range(e_phnum):
            f.seek(e_phoff + i * e_phentsize)
            p_type = struct.unpack('<I', f.read(4))[0]
            if p_type == 0x6474e551:  # PT_GNU_STACK
                f.seek(e_phoff + i * e_phentsize + 0x18)
                flags = struct.unpack('<I', f.read(4))[0]
                if flags & 1:  # PF_X set
                    f.seek(e_phoff + i * e_phentsize + 0x18)
                    f.write(struct.pack('<I', flags & ~1))
                    return True
        return False

if __name__ == '__main__':
    target = sys.argv[1] if len(sys.argv) > 1 else '/home/l4d2server/serverfiles'
    fixed = 0
    for root, _, files in os.walk(target):
        for fname in files:
            if fname.endswith('.so') or fname.endswith('.so.1'):
                path = os.path.join(root, fname)
                try:
                    if clear_execstack(path):
                        print(f"Patched: {path}")
                        fixed += 1
                except Exception as e:
                    print(f"Skip {path}: {e}")
    print(f"\n{fixed} files patched.")

Run it:

chmod +x ~/clear_execstack.py
python3 ~/clear_execstack.py

You'll need to re-run this after every L4D2 game update (Valve ships fresh .so files unpatched).


[ 8. First start ]

./l4d2server start
./l4d2server details

details shows hostname, IPs, ports, current status. The server should be running on 27015/udp.

To watch the live console:

./l4d2server console

(Detach without killing the server: Ctrl+B then D.)

If it crashes immediately, check:

tail -50 ~/log/console/l4d2server-console.log

[ 9. Test the connection ]

In L4D2 client, open the in-game console (~ key, must be enabled in Keyboard/Mouse options) and:

connect YOUR_VPS_IP:27015

You should load into the default map (c5m1_waterfront unless you've changed it).


[ 10. Install MetaMod:Source ]

MetaMod is the loader that lets SourceMod hook into the engine.

cd /tmp
wget https://mms.alliedmods.net/mmsdrop/1.12/mmsource-latest-linux.tar.gz
tar xzf mmsource-latest-linux.tar.gz -C ~/serverfiles/left4dead2/

Verify:

ls ~/serverfiles/left4dead2/addons/
# Should show: metamod  metamod.vdf

[ 11. Install SourceMod ]

cd /tmp
wget https://sm.alliedmods.net/smdrop/1.12/sourcemod-latest-linux.tar.gz
tar xzf sourcemod-latest-linux.tar.gz -C ~/serverfiles/left4dead2/

[ 12. Make yourself an admin ]

Find your SteamID in Steam-style format (STEAM_1:1:xxxxx). Easiest way: steamid.io.

Edit:

nano ~/serverfiles/left4dead2/addons/sourcemod/configs/admins_simple.ini

Add at the end:

"STEAM_1:1:YOUR_NUMBER"  "z"

z = root flag (all admin powers).


[ 13. Restart and verify SourceMod loaded ]

./l4d2server restart
sleep 15
./l4d2server send "meta version"
sleep 2
./l4d2server send "sm version"
sleep 2
tail -30 ~/log/console/l4d2server-console.log | grep -iE "metamod|sourcemod"

You should see Metamod and SourceMod version banners with no errors.


[ 14. Useful day-to-day commands ]

./l4d2server start            # start the server
./l4d2server stop             # stop the server
./l4d2server restart          # restart
./l4d2server details          # show status / IPs / ports
./l4d2server console          # attach to live console (Ctrl+B D to detach)
./l4d2server send "command"   # send a console command
./l4d2server update           # update game files (re-run clear_execstack.py after)
./l4d2server update-lgsm      # update LinuxGSM scripts
./l4d2server backup           # back up server files (config + plugins, not game files)

[ 15. Basic hardening ]

# Firewall
sudo apt install -y ufw
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow 22/tcp comment 'SSH'
sudo ufw allow 27015/udp comment 'L4D2 game'
sudo ufw allow 27020/udp comment 'SourceTV'
sudo ufw enable

# Auto-apply security updates
sudo apt install -y unattended-upgrades
sudo dpkg-reconfigure -plow unattended-upgrades

# SSH brute-force protection
sudo apt install -y fail2ban
sudo systemctl enable --now fail2ban

Don't expose 27015/tcp (RCON) unless you specifically use external RCON tools — most admins don't, and it's a brute-force target.


[ 16. Common gotchas ]

Server won't start, no obvious error:

  - Run clear_execstack.py — missing this is the #1 silent failure
    on fresh Debian/Ubuntu
  - Check libsdl2-2.0-0:i386 is installed

LinuxGSM uses l4d2server.cfg, not server.cfg:

  - ~/lgsm/config-lgsm/l4d2server/l4d2server.cfg
       LinuxGSM startup parameters (GSLT, hostname, ports)
  - ~/serverfiles/left4dead2/cfg/server.cfg
       engine-level gameplay cvars, exec'd on map load

Server not visible in browser:

  - GSLT not set, set wrong, or banned by Valve (request a new one)
  - sv_lan 1 accidentally set (use 0 for public)
  - Firewall blocking 27015/udp

Steam "Invalid platform" on SteamCMD:

  Sometimes needed for L4D2 updates: prefix with
  +@sSteamCmdForcePlatformType windows before login (rare workaround)

Can't open in-game console:

  - Steam → Settings → In-Game → enable Developer Console
  - Default key is ~, can be rebound in keyboard options

[ Where to go from here ]

Now you have a base server. Optional next steps:

  - Add persistent player stats with a web UI
    Self-host the dashboard + leaderboard stack like the one running at
    l4d2.magikh0e.pl.
  - Install the L4D2 server pack
    Four small SourceMod plugins for welcome chat, kill leaderboard,
    admin map-jump shortcuts, and auto-rotation after finale wins.
  - Install community plugins — forums.alliedmods.net
    has hundreds, indexed by game.
  - Add custom maps, mutations, or gamemodes.
  - Set up automated backups and a daily cron restart.

The server will run indefinitely with LinuxGSM monitoring it (l4d2server monitor can be cronned every few minutes to auto-restart on crash).

[ Raw markdown ]

This guide is also available as a single markdown file:

📄 l4d2-server-install-guide.md

[ See Also ]