├── .gitignore ├── LICENSE ├── README.md ├── run.sh └── src ├── .dockerignore ├── Dockerfile ├── build.sh └── start-server.sh /.gitignore: -------------------------------------------------------------------------------- 1 | workshop_builder/build_all_gamemodes.sh 2 | .idea 3 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Suchipi Izumi 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Idiot-proof TTT linux Server installation using Docker 2 | =================================== 3 | Supporting Addons using Steam collections 4 | 5 | ## Before you begin 6 | 7 | 1. Go to the [Steam Workshop](https://steamcommunity.com/workshop/browse/?appid=4000&searchtext=ttt&childpublishedfileid=0&browsesort=trend§ion=collections) and choose a collection you like. 8 | You can also create your own. 9 | 10 | 2. Get an [Steam API Key](https://steamcommunity.com/dev/apikey) by entering anything to the Domain Field. (Email/Server IP or a domain that isn't in use already) 11 | 12 | 3. Get a Server with a linux distribution installed on it (I'm using debian in this example). 13 | 14 | # Your first start 15 | 16 | You can use [this Guide](https://plusbryan.com/my-first-5-minutes-on-a-server-or-essential-security-for-linux-servers) to set up a safe server. Keep in mind that you have to allow ports 27015 and 27005 using ufw. 17 | 18 | Now that you have a secure server we can start. SSH on the server and [install docker](https://docs.docker.com/install/) 19 | and wget: 20 | 21 | 22 | ``` 23 | ~$ sudo apt-get install docker.io wget 24 | ``` 25 | 26 | I encourage you to find out more about Docker! 27 | 28 | Now download my vanilla TTT image: 29 | 30 | ``` 31 | ~$ sudo docker pull fosefx/ttt-server 32 | ``` 33 | 34 | It's 8GB+ big, so this might take a while 35 | 36 | To create a customized version you first need to run the image with certain parameters. 37 | To make it as easy as possible I wrote a script, you can download: 38 | 39 | ``` 40 | ~$ wget https://raw.githubusercontent.com/FoseFx/Idiot-proof-ttt-server-setup-docker/master/run.sh 41 | ~$ chmod +x run.sh 42 | ``` 43 | 44 | First get the image's id using 45 | ``` 46 | ~$ sudo docker images 47 | ``` 48 | And copy it. Now execute the script. 49 | ``` 50 | ~$ sudo sh run.sh 51 | ``` 52 | 53 | You can find your collections ID at the end of it's URL (`https://steamcommunity.com/sharedfiles/filedetails/?id=XXXXXXXXXX`) 54 | 55 | Now this will take a while, depending on the amount of addons that needs to be downloaded to the server. 56 | 57 | 58 | When the last line prints something with `VAC` you can close the server again using `Ctrl + C` 59 | 60 | ## Change the config files 61 | At this point in time you can edit the config files which are now in the following directory: 62 | 63 | `/var/lib/docker/volumes/garrysmod/_data` 64 | (you can change your directory using the `cd` command, `cd ..` will elevate you one folder level, note: `/var/lib/docker` probably needs to be accessed by the `root` user, use `sudo -s` to become root first) 65 | 66 | You can find examples all over the internet. 67 | 68 | ## Add Workshop.lua 69 | 70 | Now locate this folder: 71 | 72 | `/var/lib/docker/volumes/garrysmod/_data/lua/autorun/server` 73 | 74 | And create a `workshop.lua` (`sudo touch /var/lib/docker/volumes/garrysmod/_data/lua/autorun/server/workshop.lua`). 75 | Here you have to copy the output of [this generator in](https://csite.io/tools/gmod-universal-workshop) into. 76 | [You don't know how to edit a file from the terminal? Here is a guide on nano.][how-to-nano] 77 | 78 | `cd ~` after that 79 | 80 | ## Create a unique image 81 | 82 | Create a [dockerhub](https://hub.docker.com) account and `sudo docker login` with your credentials. 83 | 84 | Your Container should be listed here: `sudo docker container list -a`. 85 | 86 | To create an unique image for your configuration type 87 | 88 | ``` 89 | ~$ sudo docker commit / 90 | ``` 91 | 92 | Now push it to the docker hub where you can pull it from anytime. 93 | ``` 94 | ~$ sudo docker push / 95 | ``` 96 | 97 | ## Cleaning 98 | 99 | 1. Stop and remove the 'old' container 100 | - `sudo docker stop ` 101 | - `sudo docker rm ` 102 | 2. Remove the old image 103 | - get the image `sudo docker images` 104 | - remove it `sudo docker rmi ` 105 | 3. Remove the old Volume 106 | - `sudo docker volume rm garrysmod` 107 | 4. Start new Container 108 | - `sudo sh run.sh ` 109 | 110 | ## Attach 111 | 112 | See nothing? That's good. The container is now in 'detached mode'. 113 | To interact with the console use 114 | ``` 115 | ~$ sudo docker ps 116 | ~$ sudo docker attach 117 | ``` 118 | ### READ THIS FIRST! 119 | Using `Ctrl + C` you will `Stop the server`! 120 | When you want to detach from the container without stopping it use: 121 | `Ctrl + P` followed by `Ctrl + Q`. 122 | 123 | When you see your bash input you are safe to `exit`, the server will stay! 124 | 125 | When the Server stopped you can restart it using 126 | ``` 127 | ~$ sudo docker container -a 128 | ~$ sudo docker restart 129 | ``` 130 | 131 | You can remove all containers using 132 | ``` 133 | sudo docker rm $(docker container list -q) 134 | ``` 135 | 136 | # Redeploy 137 | 138 | So your server died or you want to start another one. 139 | Because you now have a unique Docker Image uploaded to DockerHub 140 | you just have to reinstall Docker, login and start the server. 141 | 142 | ``` 143 | ~$ sudo apt-get install docker.io wget 144 | ~$ wget https://raw.githubusercontent.com/FoseFx/Idiot-proof-ttt-server-setup-docker/master/run.sh 145 | ~$ chmod +x run.s 146 | ``` 147 | 148 | Now use `docker login` again to login and then 149 | ``` 150 | ~$ sudo docker pull / 151 | ``` 152 | 153 | Start the server with `sudo sh run.sh ` and your done. 154 | 155 | # Auto-restart 156 | 157 | Docker will not restart containers if your system goes down, however you can tell it to do so. 158 | When you start the container use the `--restart unless-stopped` argument. [More here][docker-always-restart]. 159 | You can add this flag to running containers using `docker update --restart unless-stopped `. 160 | 161 | This Guide is based on [this repository](https://github.com/suchipi/gmod-server-docker/) 162 | 163 | [how-to-nano]: https://www.howtogeek.com/howto/42980/the-beginners-guide-to-nano-the-linux-command-line-text-editor/ 164 | [docker-always-restart]: https://docs.docker.com/config/containers/start-containers-automatically/ 165 | -------------------------------------------------------------------------------- /run.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | if [ -z "$1" ]; then 3 | echo "Use: sh run.sh [ ]" 4 | fi 5 | 6 | read -p "Enter a RCON Password (for Admin stuff): " rcon 7 | read -p "Enter a Hostname (displayed in the server list): " hostname 8 | read -p "Enter max payers: " maxplayers 9 | read -p "Enter the initial map choice (nothing: 'gm_construct'): " map 10 | 11 | if [ -z "$map" ]; then 12 | map="gm_construct" 13 | fi 14 | 15 | docker volume create garrysmod 16 | 17 | if [ -z "$2" ] && [ -z "$3" ]; then 18 | 19 | docker run -d -t \ 20 | -p 27015:27015 -p 27015:27015/udp -p 27005:27005 -p 27005:27005/udp \ 21 | -v garrysmod:/gmod-base/garrysmod \ 22 | -e "ARGS=+rcon_password $rcon" \ 23 | -e "G_HOSTNAME=$hostname" \ 24 | -e "MAXPLAYERS=$maxplayers" \ 25 | --name gmod-ttt $1 26 | else 27 | if [ -n "$2" ] && [ -z "$3" ]; then 28 | echo "Use: sh run.sh [ ]" 29 | fi 30 | if [ -z "$2" ] && [ -n "$3" ]; then 31 | echo "Use: sh run.sh [ ]" 32 | fi 33 | if [ -n "$2" ] && [ -n "$3" ]; then 34 | docker run -i -t \ 35 | -p 27015:27015 -p 27015:27015/udp -p 27005:27005 -p 27005:27005/udp \ 36 | -v garrysmod:/gmod-base/garrysmod \ 37 | --name gmod-ttt \ 38 | -e "AUTHKEY=$2" \ 39 | -e "G_HOSTNAME=$hostname" \ 40 | -e "MAXPLAYERS=$maxplayers" \ 41 | -e "HOST_WORKSHOP_COLLECTION=$3" \ 42 | -e "ARGS=+rcon_password $rcon" $1 43 | 44 | fi 45 | fi 46 | 47 | 48 | -------------------------------------------------------------------------------- /src/.dockerignore: -------------------------------------------------------------------------------- 1 | .git 2 | -------------------------------------------------------------------------------- /src/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM debian:7-slim 2 | 3 | # ------------ 4 | # Prepare Gmod 5 | # ------------ 6 | 7 | RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install --no-install-recommends -y ca-certificates lib32tinfo5 lib32gcc1 lib32stdc++6 lib32z1 lib32z1-dev wget 8 | RUN update-ca-certificates 9 | RUN mkdir /steamcmd 10 | WORKDIR /steamcmd 11 | RUN wget http://media.steampowered.com/installer/steamcmd_linux.tar.gz 12 | RUN tar -xvzf steamcmd_linux.tar.gz 13 | RUN mkdir /gmod-base 14 | 15 | RUN useradd steam 16 | RUN chown -R steam /steamcmd /gmod-base 17 | USER steam 18 | 19 | RUN /steamcmd/steamcmd.sh +login anonymous +force_install_dir /gmod-base +app_update 4020 validate +quit 20 | 21 | # ---------------- 22 | # Annoying lib fix 23 | # ---------------- 24 | USER root 25 | 26 | 27 | RUN mkdir /gmod-libs 28 | WORKDIR /gmod-libs 29 | RUN wget http://launchpadlibrarian.net/195509222/libc6_2.15-0ubuntu10.10_i386.deb 30 | RUN dpkg -x libc6_2.15-0ubuntu10.10_i386.deb . 31 | RUN cp -a lib/i386-linux-gnu/. /gmod-base/bin/ 32 | WORKDIR / 33 | RUN rm -rf /gmod-libs 34 | RUN cp /steamcmd/linux32/libstdc++.so.6 /gmod-base/bin/ 35 | 36 | RUN mkdir -p /home/steam/.steam/sdk32/ 37 | RUN cp -a /steamcmd/linux32/. /home/steam/.steam/sdk32/ 38 | 39 | # ---------------------- 40 | # Setup Volume and Union 41 | # ---------------------- 42 | 43 | RUN mkdir /gmod-volume 44 | VOLUME /gmod-volume 45 | RUN chown -R steam /gmod-volume /gmod-base /steamcmd /home/steam 46 | 47 | # --------------- 48 | # Setup Container 49 | # --------------- 50 | 51 | ADD start-server.sh /start-server.sh 52 | EXPOSE 27015/udp 53 | EXPOSE 27015/tcp 54 | EXPOSE 27005/udp 55 | EXPOSE 27006/tcp 56 | 57 | ENV PORT="27015" 58 | ENV MAXPLAYERS="16" 59 | ENV G_HOSTNAME="Garry's Mod" 60 | ENV GAMEMODE="terrortown" 61 | ENV MAP="gm_construct" 62 | ENV HOST_WORKSHOP_COLLECTION = "" 63 | ENV AUTHKEY = "" 64 | USER steam 65 | CMD ["/bin/sh", "/start-server.sh"] 66 | -------------------------------------------------------------------------------- /src/build.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | docker build -t fosefx/ttt-server . 3 | -------------------------------------------------------------------------------- /src/start-server.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | while true; do 4 | /gmod-base/srcds_run -game garrysmod -norestart -port ${PORT} \ 5 | +maxplayers ${MAXPLAYERS} \ 6 | +hostname "${G_HOSTNAME}" \ 7 | +gamemode ${GAMEMODE}\ 8 | +host_workshop_collection ${HOST_WORKSHOP_COLLECTION} \ 9 | -authkey ${AUTHKEY} \ 10 | "${ARGS}" \ 11 | +map ${MAP} 12 | done 13 | 14 | --------------------------------------------------------------------------------