Garry's Mod

Garry's Mod

Not enough ratings
GMod Addons - Linux Dedicated Server
By LycanDID
This guide covers some of what I've figured out over the course of setting up a Source Dedicated Server to run GMod with Murder and Prop Hunt.
   
Award
Favorite
Favorited
Unfavorite
The Setup
For my first attempt at making a Dedicated Server, I used Digital Ocean[www.digitalocean.com] for a VPS. I used their smallest "Droplet" (which spec'd at 512 MB of memory and a 20GB SSD as of October 11, 2014) with Ubuntu 14 on it.

I'm going to assume for the sake of this guide that you have some Linux knowledge, and can handle things.
  • Don't run any of these services as root. I created a user "steam" and run all this out of that home directory
  • Update your kernal and OS, it'll make life easier
  • I used UFW for firewall management. It's very simple, and Digital Ocean has a good tutorial[www.digitalocean.com] on it. Don't just leave all the ports open!
  • You're going to need SteamCMD. There are a lot of tutorials out there for SteamCMD, and I primarily used this one to figure things out.

Using SteamCMD, I installed Garry's Mod, TF2 Dedicated Server, Half-Life 2: Deathmatch, and Counter Strike: Source. All of this fits on my 20GB droplet with about 4GB to spare. I let steamCMD use it's default directory, which on my system came out to:

/home/steam/Steam/steamapps/common/... for Steam servers /home/steam/steamcmd/... for steamCMD itself

Those paths will be used a lot, so be aware!
Getting the Addons
For the Murder server, I run srcds with this tag:

/home/steam/Steam/steamapps/common/GarrysModDS/srcds_run -console -game garrysmod -tickrate 100 -port 27015 -maxplayers 32 +gamemode murder +host_workshop_collection 202743660 -authkey (you'll need your own authkey) +map $MAP -autoupdate +exec mu_server.cfg >> /home/steam/Steam/steamapps/common/GarrysModDS/MurderServer.log 2>&1 &

There's a lot going on here, and I'll explain it all in the Automation section. Prop_Hunt looks similar:

/home/steam/Steam/steamapps/common/GarrysModDS/srcds_run -console -game garrysmod -tickrate 100 -port 27016 -maxplayers 32 +gamemode prop_hunt +host_workshop_collection 177117131 -authkey (you'll need your own authkey) +map $MAP -autoupdate +exec ph_server.cfg >> /home/steam/Steam/steamapps/common/GarrysModDS/Prop_HuntServer.log 2>&1 &

But the important bits here for this sections are this:

  • This system is using the same GMod instance for both servers
  • One server will be connected on port 27015, one will be on 27016
  • The gamemode is set in the command line, which seems to work better than burying it in the server.cfg
  • The two instances load different .cfg files for their settings

You could cut this down like this:

/home/steam/Steam/steamapps/common/GarrysModDS/srcds_run -console -game garrysmod -tickrate 100 -port 27015 -maxplayers 32 +host_workshop_collection 202743660 -authkey (you'll need your own authkey)

And steamCMD would pull the files for collection 202743660 down and drop them in the "addons" folder under the GarrysModDS/garrysmod/ path.

The extra bits here are all because of automation, which I'll discuss later.
Automation
Things I wanted my server to do:

  • Keep Steam up to date
  • Make sure my servers launch when the server reboots
  • Don't always launch with the same map (that's boring)

To this end, I created some scripts. These scripts live in /usr/bin/steam. The permissions should look like this:

-rwxr-xr-x 1 root root 1003 Oct 11 13:10 mu_server.sh -rwxr-xr-x 1 root root 1.1K Oct 11 13:20 ph_server.sh -rwxr-xr-x 1 root root 311 Oct 11 13:16 steamupdate.sh

Keep Steam Up To Date

Here's the steamupdate.sh:

#!/bin/bash echo "" >> /home/steam/steamcmd/update.log echo "=================================" >> /home/steam/steamcmd/update.log echo "Steam Update entries for $(date):" >> /home/steam/steamcmd/update.log /home/steam/steamcmd/steamcmd.sh +runscript update_srcds.txt >> /home/steam/steamcmd/update.log 2>&1 &

What's going on here?

The first line tells the system to execute this in bash (#!/bin/bash) which is a shell for Linux.
The next few lines put a blank line, a divider and the date in a log file. This can be useful if you want to know what happened with your updates, and I'll repeat this sort of code in my other scripts.
The last line does a lot of stuff!

First, we launch steamcmd. We want it to run a script, "update_srcds.txt" This script looks like this, and lives in the same directory as steamcmd.sh.

// Update various Steam components //Keep going even if there is an error, we have more servers to update! @ShutdownOnFailedCommand 0 login anonymous //Update CS:S app_update 232330 //Update HL2:DM app_update 232370 //Update TF2 app_update 232250 //Update GMod app_update 4020 //Logoff gracefully quit

I don't want the terminal to get flooded with messages from steamCMD, so we have the >> to indicate I want output to be appended to a log file (update.log). The 2>&1 means I want all output to go to this logfile, and nothing to come to the terminal. The last "&" beheads the process, so that you can keep doing other things in Linux, like close your session, without killing this process.

The log file will get entries like this:

================================= Steam Update entries for Sat Oct 11 12:42:06 MDT 2014: Redirecting stderr to '/home/steam/Steam/logs/stderr.txt' [ 0%] Checking for available updates... [----] Verifying installation... Steam Console Client (c) Valve Corporation -- type 'quit' to exit -- Loading Steam API...OK. @ShutdownOnFailedCommand 0 "@ShutdownOnFailedCommand" = "0" login anonymous Connecting anonymously to Steam Public...Logged in OK Waiting for license info...OK app_update 232330 Success! App '232330' already up to date. app_update 232370 Success! App '232370' already up to date. app_update 232250 Success! App '232250' already up to date. app_update 4020 Success! App '4020' already up to date. quit

Logging is a good idea, since it gives you somewhere to look if the server gets borked. Now, you can launch this script manually, but we don't want to do that. We want it to happen regularly, so we "su" to the steam user and run crontab -e. We add a line like this one:

0 04,10,16,22 * * * /usr/bin/steam/steamupdate.sh

This means that every day at the top of the hour at 0400, 1000, 1600 and 2200 the system will call my steamupdate.sh script.

Make the Servers Launch at Boot

Now that I've explained the last script, this one will make more sense. I called this one mu_server.cfg.

echo "" >> /home/steam/Steam/steamapps/common/GarrysModDS/MurderServer.log echo "========================================" >> /home/steam/Steam/steamapps/common/GarrysModDS/MurderServer.log echo "Murder Server Launch for $(date):" >> /home/steam/Steam/steamapps/common/GarrysModDS/MurderServer.log /home/steam/Steam/steamapps/common/GarrysModDS/srcds_run -console -game garrysmod -tickrate 100 -port 27015 -maxplayers 32 +gamemode murder +host_workshop_collection 202743660 -authkey (get your own) +map $MAP -autoupdate +exec mu_server.cfg >> /home/steam/Steam/steamapps/common/GarrysModDS/MurderServer.log 2>&1 &

Again, we're putting some lines in a log every time the script runs, including the date. We launch the server, and set a lot of the variables before loading the mu_server.cfg. We output all this to a Server.log, and we behead the process so the system doesn't keep waiting on it to complete.

To make this run at boot, I "su" to steam, go to crontab again, and add a line like this:

@reboot /usr/bin/steam/mu_server.sh

Now everytime my server boots, it'll launch Murder. Prop_Hunt works the same way.

Random Maps

You'll have noticed that the +map variable has $MAP in it. This isn't a valid map name. Source Dedicated Server does come with a +randommap option, but I don't want any random map. I want a random map that'll be good for my gamemode. To that end, here is my complete mu_server.sh:

#!/bin/sh RND=$((RANDOM%5+1)) if (($RND == 1)); then MAP="dm_lockdown" else if (($RND == 2)); then MAP="de_chateau" else if (($RND == 3 )); then MAP="md_clue" else if (($RND == 4)); then MAP="mu_nightmare_church" else if (($RND == 5)); then MAP="de_forest" else echo "We broke it!" MAP="cs_office" fi fi fi fi fi echo "" >> /home/steam/Steam/steamapps/common/GarrysModDS/MurderServer.log echo "========================================" >> /home/steam/Steam/steamapps/common/GarrysModDS/MurderServer.log echo "Murder Server Launch for $(date):" >> /home/steam/Steam/steamapps/common/GarrysModDS/MurderServer.log /home/steam/Steam/steamapps/common/GarrysModDS/srcds_run -console -game garrysmod -tickrate 100 -port 27015 -maxplayers 32 +gamemode murder +host_workshop_collection 202743660 -authkey (get your own) +map $MAP -autoupdate +exec mu_server.cfg >> /home/steam/Steam/steamapps/common/GarrysModDS/MurderServer.log 2>&1 &

So, we start by telling Linux this is to be run in bash.
Next, we create a variable (RND) and set it to a random number between 1 and 5.
Then, we check the value of RND, and based on that value, we set a variable (MAP) to a map name.

This is where the $MAP comes into play in the final execution. If RND was 3, than the srcds will see "+map md_clue" and load Clue.

My loop only allows for 5 maps (6, if you count the catch-all error condition), but you could make as many if-else-fi loops as you want.
Server Configs
Each of my server launch scripts tells srcds to load a different server config file. This way, the same Garry's Mod instance can run two different settings. Before that, we have to get the stuff that'll be the same to work.

Since you hopefully loaded all the content, you'll need to modify garrysmod/cfg/mount.cfg:

// // Use this file to mount additional paths to the filesystem // DO NOT add a slash to the end of the filename // "mountcfg" { "cstrike" "/home/steam/Steam/steamapps/common/Counter-Strike Source Dedicated Server/cstrike" "tf" "/home/steam/Steam/steamapps/common/Team Fortress 2 Dedicated Server/tf" "hl2mp" "/home/steam/Steam/steamapps/common/Half-Life 2 Deathmatch Dedicated Server/hl2mp" }

This'll tell GMode where all that other content you have is. You'll also want to modify garrysmod/cfg/mountdepots.txt:

"gamedepotsystem" { "cstrike" "1" "tf" "1" "hl2mp" "1" }

Now, this cfg directory is where a lot of stuff will live. On my server, that includes my server.cfg files (called by the server launch scripts) and my mapcycle files.

ls -alh /home/steam/Steam/steamapps/common/GarrysModDS/garrysmod/cfg total 80K drwxrwxr-x 2 steam steam 4.0K Oct 8 18:02 . drwxrwxr-x 20 steam steam 4.0K Oct 11 13:21 .. -rwxrwxr-x 1 steam steam 3 Oct 8 16:30 autoexec.cfg -rwxrwxr-x 1 steam steam 0 Oct 11 13:21 banned_ip.cfg -rwxrwxr-x 1 steam steam 0 Oct 11 13:21 banned_user.cfg -rwxrwxr-x 1 steam steam 1.2K Oct 8 16:30 config_default.cfg -rwxrwxr-x 1 steam steam 72 Oct 8 16:30 game.cfg -rwxrwxr-x 1 steam steam 4 Oct 8 16:30 listenserver.cfg -rwxrwxr-x 1 steam steam 415 Oct 9 17:42 mount.cfg -r--r--rwx 1 steam steam 67 Oct 9 17:44 mountdepots.txt -r--r--rwx 1 steam steam 127 Oct 10 20:03 mu_mapcycle.txt -rwxrwxr-x 1 steam steam 2.1K Oct 9 17:38 mu_server.cfg -rwxrwxr-x 1 steam steam 43 Oct 8 16:30 network.cfg -r--r--rwx 1 steam steam 226 Oct 10 20:52 ph_mapcycle.txt -rwxrwxr-x 1 steam steam 2.1K Oct 9 20:27 ph_server.cfg -rwxrwxr-x 1 steam steam 4 Oct 8 16:30 server.cfg -rw-rw-r-- 1 steam steam 184 Oct 11 13:21 server.vdf -rwxrwxr-x 1 steam steam 126 Oct 8 16:30 settings_default.scr -rwxrwxr-x 1 steam steam 5.4K Oct 8 16:30 skill.cfg -rwxrwxr-x 1 steam steam 16 Oct 8 16:30 skill_manifest.cfg -rwxrwxr-x 1 steam steam 0 Oct 8 16:36 userconfig.cfg -rwxrwxr-x 1 steam steam 275 Oct 8 16:30 valve.rc

Let's take a look at the Murder server config, then:

// Damon's Murder Server Config // Server Basics hostname "Husky Servers | Garry's Mod | Murder" rcon_password "wouldn't you like to know?" servercfgfile "mu_server.cfg" sv_region 1 // Server is in US - West Region sv_secure 1 // Enable VAC sv_password "some password" // Keep random yokels off the server sv_pausable 0 // Server cannot be paused sv_lan 0 // 0 = Advertise to Steam, 1 = LAN Only sv_cheats 0 // Disable Cheats sv_pure 1 // Disable some user custom files, while allowing skins and models mapcyclefile "mu_mapcycle.txt" // Access Control sv_logbans 1 // Yes, enforce and record bans exec banned_ip.cfg // Load banned IPs exec banned_user.cfg // Load banned Users sv_rcon_maxfailures "5" // How many failed attempts to access the RCON before being banned? sv_rcon_banpenalty "60" // Minutes to ban a user to failed RCON attempts // Game Mode sv_gamemode "murder" // .sh shoulda done this, but to be safe... // Client Control: Infringe on user's rights fps_max 600 // Set maximum FPS on this server sv_maxrate "20000" //Max bandwidth rate allowed on server, 0 == unlimited sv_maxupdaterate "120" //Maximum updates per second that the server will allow sv_minrate "2500" //Min bandwidth rate allowed on server, 0 == unlimited sv_minupdaterate "10" //Minimum updates per second that the server will allow sv_timeout "90" //After this many seconds without a message from a client, the client is dropped sv_allowupload 1 //Allow clients to upload customizations files sv_allowdownload 1 //Allow clients to download files sv_maxfilesize "5" // Maximum size in MB of a client custom file sv_voiceenable 0 // Disable ingame voice mp_idledealmethod 2 // Kick idle players //Rounds and Game Times mp_bonusroundtime 5 // Wait seconds after a win before next round mp_restartround 0 mp_timelimit 35 // limit in minutes on how long to spend on a map mp_roundlimit 10 // limit in rounds on how long to spend on a map mapcyclefile "mu_mapcycle.txt" // Access Control Part 2 writeid //Writes a list of permanently-banned user IDs to banned_user.cfg. writeip //Save the ban list to banned_ip.cfg.

Caveats
Maybe a great guide to all the server variables is out there somewhere. It seems that some games use some variables differently, and some games expect or ignore different things. I'll go into detail in another section, but this seems to "more-or-less" work. You may see errors launching servers with this exact file.
What Doesn't Work - Help!
I wish I could say that, after a week of messing with it, I had no issues. This section is the things that are still "sorta broke" that I haven't figured out yet. Hopefully it'll shrink or I'll be able to find answers and share them (or maybe you can tell me what to do!)

Murder Never Cycles the Maps
No matter the rounds, the map never changes. Apparently a mapcycle isn't enough. Still investigating.

Prop_Hunt forgets its game mode
The Prop_Hunt addon in the workshop includes this thing called Fretta. It's great for allowing users to vote on the next map. The problems are:
  • Sometimes it changes the gamemode without warning or a vote
  • There doesn't appear to be a way to kick off a vote in-game
  • It shows ALL maps, not just maps defined in the gamemode.txt

I tried to deploy the Simple Map Voting Addon[facepunch.com], hoping it'd get Murder cycling and eliminate the game mode thing, but I think I'm doing it wrong. Even though I've removed the fretta lines from my gamemode.txt under Prop_Hunt and relocated the fretta folder from gamemodes, somehow it lingers!
1 Comments
Karo Apr 10 @ 1:39pm 
Hey I have some questions about hosting dedicated server could you add me on steam ?