├── .github └── workflows │ └── docker-image.yml ├── Dockerfile ├── LICENSE ├── README.md └── example ├── .env ├── .gitignore ├── README.md ├── addons └── anyname │ └── lua │ └── autorun │ └── somefile.lua ├── docker-compose.yml ├── start.sh └── sv.db /.github/workflows/docker-image.yml: -------------------------------------------------------------------------------- 1 | name: Build and publish Docker image 2 | 3 | on: 4 | schedule: 5 | - cron: "37 13 * * 1" 6 | workflow_dispatch: 7 | push: 8 | branches: [ "master" ] 9 | tags: [ "v*" ] 10 | 11 | env: 12 | REGISTRY: ghcr.io 13 | IMAGE_NAME: ${{ github.repository }} # / 14 | 15 | jobs: 16 | build_and_publish: 17 | runs-on: ubuntu-latest 18 | steps: 19 | - uses: actions/checkout@v4 20 | - uses: docker/login-action@v3 21 | with: 22 | registry: ${{ env.REGISTRY }} 23 | username: ${{ github.actor }} 24 | password: ${{ secrets.GITHUB_TOKEN }} 25 | 26 | - id: meta 27 | uses: docker/metadata-action@v5 28 | with: 29 | images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} 30 | # При обычном коммите делает тег master (ветка) вместо latest. Логично, но некрасиво. Ниже изменения 31 | # 1. Применяет тег "latest", если текущий ref является тегом 32 | # 2. Применяет тег, основанный на имени ветки 33 | # 3. Применяет тег, основанный на хэше коммита 34 | # 4. Применяет тег, аналогичный тегу рефа, если текущий ref является тегом 35 | # Альтернативный вариант: https://github.com/strato-earth/workflow-task-template/blob/038f51662aff7e1b9fd6cf98c13e0e3ee8c65855/github/build.yml#L34-L44C17 36 | tags: | 37 | type=raw,value=latest,enable=${{ startsWith(github.ref, 'refs/tags/') }} 38 | type=ref,event=branch 39 | type=sha,format=short 40 | type=raw,value=${{ github.ref_name }},enable=${{ startsWith(github.ref, 'refs/tags/') }} 41 | 42 | - uses: docker/build-push-action@v6 43 | with: 44 | context: . 45 | push: true 46 | tags: ${{ steps.meta.outputs.tags }} 47 | labels: ${{ steps.meta.outputs.labels }} 48 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:22.04 2 | 3 | LABEL MAINTAINER="_AMD_ (me@amd-nick.me)" 4 | 5 | # Prepare Gmod server and CSS content 6 | # =================================== 7 | 8 | RUN dpkg --add-architecture i386 \ 9 | && apt update \ 10 | && apt -y upgrade \ 11 | && apt -y --no-install-recommends install curl lib32stdc++6 libtinfo5:i386 ca-certificates 12 | # /\ for steamcmd /\ fixes readline: https://forum.gm-donate.net/t/7645 13 | 14 | 15 | # Cleanup 16 | # =================================== 17 | 18 | RUN apt-get clean \ 19 | && rm -rf /tmp/* /var/lib/apt/lists/* 20 | 21 | 22 | # Security 23 | # P.S. 25.04 has default user ubuntu 1000:1000 24 | # =================================== 25 | 26 | RUN groupadd -g 1000 steam \ 27 | && useradd -r -m -d /gmodserv -u 1000 -g steam steam 28 | 29 | USER steam 30 | ENV HOME=/gmodserv 31 | 32 | 33 | # SteamCMD + GMOD + CSS 34 | # =================================== 35 | 36 | WORKDIR /gmodserv/steamcmd 37 | 38 | RUN curl -O https://steamcdn-a.akamaihd.net/client/installer/steamcmd_linux.tar.gz \ 39 | && tar -xvzf steamcmd_linux.tar.gz \ 40 | && rm steamcmd_linux.tar.gz 41 | 42 | RUN ./steamcmd.sh \ 43 | +force_install_dir /gmodserv/content/css \ 44 | +login anonymous \ 45 | +app_update 232330 -validate \ 46 | +quit 47 | 48 | RUN ./steamcmd.sh \ 49 | +force_install_dir /gmodserv \ 50 | +login anonymous \ 51 | +app_update 4020 -validate \ 52 | +quit 53 | 54 | RUN echo '"mountcfg" {"cstrike" "/gmodserv/content/css/cstrike"}' > /gmodserv/garrysmod/cfg/mount.cfg 55 | 56 | 57 | # Run server 58 | # =================================== 59 | 60 | WORKDIR /gmodserv 61 | ENTRYPOINT ["./srcds_run", "-game garrysmod", "-console", "-norestart", "-strictportbind"] 62 | CMD ["-port 27015", "-tickrate 32", "-maxplayers 16", "-insecure", "+map gm_construct"] 63 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 _AMD_ 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 |

2 | 3 |

4 | 5 | 13 | 14 |

15 | 16 | 17 | 18 | 19 | 20 | 21 |

22 | 23 | 24 | 25 | # Dockerized Garry's Mod server 26 | 27 | Runs your Garry's Mod server inside Docker container as an executable 28 | 29 | ## Features 30 | 31 | - Gmod running under non-root user (steam) 32 | - Working luarefresh. You can update your scripts and changes will apply instantly 33 | - Installed CSS content 34 | - You can run commands in your container like it's not containered server 35 | - Correct `GetConVarString("hostip")` if run with docker-compose (if you edit ip inside .env) 36 | - tmysql4, luasocket and some .dll modules works fine 37 | 38 | ## Examples 39 | 40 | For advanced example and docker-compose file look inside [example folder](/example). 41 | 42 | Also you can run your server with `docker run`. Simple example: 43 | 44 | ```bash 45 | docker build -t gmod-server . ; docker run --rm -it --name gmod \ 46 | -p 27015:27015/udp \ 47 | -v $PWD/addons:/gmodserv/garrysmod/addons/ \ 48 | gmod-server \ 49 | -port 27015 \ 50 | -tickrate 32 \ 51 | -maxplayers 8 \ 52 | +map gm_construct \ 53 | ``` 54 | 55 | ## Notes 56 | 57 | - This image requires ~7GB of free space 58 | - Main locations inside containter is `/gmodserv/garrysmod`, `/gmodserv/steamcmd` and `/gmodserv/content/css` 59 | - Ready to use (builded) images located on ghcr.io, not on docker hub 60 | - Such modules like `gmsv_socket_linux.dll` requires additional port forwarding rules. Example. If you plan to use `27030/tcp` then you need to add following option to `docker run` command: `-p 27030:27030/tcp` 61 | 62 | ## docker run tips and tricks 63 | 64 | - `--rm` option. If you use it the container will automatically removed after srcds process being killed. You should not remove trash containers by hands with this param 65 | - `--name anyname` assign pretty name to your container, so you can delete it by name instead of hash 66 | - `-d` option runs container in background. You can attach them with `docker attach container_name` (don't use with --rm). 67 | - `-it` there is 2 options where -t allocate a pseudo-TTY (required) and -i which allow you to interact with gmod console (run commands etc) 68 | - `docker logs -f container_name` let's receive logs from server! 69 | - `docker exec -it container_name bash` connect to container shell 70 | -------------------------------------------------------------------------------- /example/.env: -------------------------------------------------------------------------------- 1 | HOSTIP=116.203.45.167 2 | PORT=27015 3 | -------------------------------------------------------------------------------- /example/.gitignore: -------------------------------------------------------------------------------- 1 | addons/ulx_ulib 2 | darkrp 3 | data/* 4 | -------------------------------------------------------------------------------- /example/README.md: -------------------------------------------------------------------------------- 1 | # Example 2 | 3 | Just `sh start.sh` 4 | -------------------------------------------------------------------------------- /example/addons/anyname/lua/autorun/somefile.lua: -------------------------------------------------------------------------------- 1 | local global_I = cookie.GetNumber("key_from_sv_db", 0) + 1 2 | cookie.Set("key_from_sv_db", global_I) 3 | 4 | for i = 1, 10 do 5 | print("Hello world! It's a " .. global_I .. " time when this server starts") 6 | end 7 | -------------------------------------------------------------------------------- /example/docker-compose.yml: -------------------------------------------------------------------------------- 1 | services: 2 | gmod: 3 | build: 4 | context: .. 5 | command: -port $PORT \ 6 | -tickrate 32 \ 7 | -maxplayers 16 \ 8 | -insecure \ 9 | +gamemode darkrp \ 10 | +map gm_construct 11 | stdin_open: true 12 | tty: true 13 | ports: 14 | - "$PORT:$PORT/udp" 15 | volumes: 16 | - $PWD/addons:/gmodserv/garrysmod/addons/ 17 | - $PWD/data:/gmodserv/garrysmod/data/ 18 | - $PWD/darkrp:/gmodserv/garrysmod/gamemodes/darkrp/ 19 | - $PWD/gmas:/gmodserv/garrysmod/cache/srcds/ 20 | - $PWD/luabin:/gmodserv/garrysmod/lua/bin/ 21 | - $PWD/sv.db:/gmodserv/garrysmod/sv.db 22 | # How to fix that docker shit? 23 | # https://img.qweqwe.ovh/1532284325896.png 24 | hostname: keklol 25 | extra_hosts: 26 | - keklol:$HOSTIP 27 | networks: 28 | - gmodnet 29 | 30 | #redis: 31 | # image: redis 32 | # command: redis-server #/data/redis.conf #--appendonly yes 33 | # #ports: 34 | # # - "6379:6379" 35 | # volumes: 36 | # - "$PWD/redis:/data" 37 | # networks: 38 | # - gmodnet 39 | 40 | networks: 41 | gmodnet: 42 | -------------------------------------------------------------------------------- /example/start.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Run clean darkrp server with ulx admin mode 4 | 5 | # git clone https://github.com/AMD-NICK/docker-garrysmod-server.git gmod-docker 6 | # cd gmod-docker 7 | # sh start.sh 8 | 9 | mkdir -p addons data luabin gmas 10 | touch sv.db 11 | chown 1000:1000 sv.db data/ gmas/ 12 | 13 | if [ ! -d "darkrp" ]; then 14 | echo "Installing DarkRP" 15 | git clone https://github.com/FPtje/DarkRP.git darkrp 16 | fi 17 | 18 | if [ ! -d "addons/ulx_ulib" ]; then 19 | echo "Installing Ulx and Ulib" 20 | 21 | mkdir -p tmp/ulx_ulib 22 | cd tmp 23 | 24 | git clone 'https://github.com/TeamUlysses/ulx.git' 25 | git clone 'https://github.com/TeamUlysses/ulib.git' 26 | 27 | cp -r 'ulx/lua' ulx_ulib/ 28 | cp -r 'ulib/lua' ulx_ulib/ 29 | 30 | mv ulx_ulib/ ../addons 31 | 32 | cd .. 33 | rm -rf tmp 34 | fi 35 | 36 | docker compose up --force-recreate 37 | -------------------------------------------------------------------------------- /example/sv.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AMD-NICK/docker-garrysmod-server/8b9a0b624daae80e4c36d1ad905630f69fc8fe50/example/sv.db --------------------------------------------------------------------------------