├── .editorconfig ├── scripts ├── lgsm_console.sh ├── lgsm_bootstrap.sh └── lgsm_configuration.sh ├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md ├── stale.yml └── workflows │ └── build.yml ├── Dockerfile └── README.md /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig is awesome: https://EditorConfig.org 2 | 3 | root = true 4 | 5 | [*] 6 | end_of_line = lf 7 | insert_final_newline = true 8 | indent_style = space 9 | indent_size = 2 10 | -------------------------------------------------------------------------------- /scripts/lgsm_console.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | source /lgsm_functions.sh 4 | source /lgsm_variables.sh 5 | 6 | fn_check_user 7 | fn_check_lgsm_installed 8 | 9 | log_dir="${HOME}/log" 10 | log_file="${log_dir}/console/${LGSM_GAMESERVER}-console.log" 11 | 12 | if [ ! -z "${LGSM_GAMESERVER_RENAME}" ] 13 | then 14 | log_file="${log_dir}/console/${LGSM_GAMESERVER_RENAME}-console.log" 15 | fi 16 | 17 | 18 | if [ "${LGSM_GAMESERVER_START}" != "true" ] 19 | then 20 | exit 0 21 | fi 22 | 23 | # Wait for file creation 24 | while [ ! -f "${log_file}" ] 25 | do 26 | sleep 1 27 | done 28 | 29 | # Display logs 30 | tail -f "${log_file}" 31 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **Additional context** 27 | Add any other context about the problem here. 28 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /.github/stale.yml: -------------------------------------------------------------------------------- 1 | # Number of days of inactivity before an issue becomes stale 2 | daysUntilStale: 60 3 | # Number of days of inactivity before a stale issue is closed 4 | daysUntilClose: 7 5 | # Issues with these labels will never be considered stale 6 | exemptLabels: 7 | - pinned 8 | - security 9 | # Label to use when marking an issue as stale 10 | staleLabel: wontfix 11 | # Comment to post when marking an issue as stale. Set to `false` to disable 12 | markComment: > 13 | This issue has been automatically marked as stale because it has not had 14 | recent activity. It will be closed if no further activity occurs. Thank you 15 | for your contributions. 16 | # Comment to post when closing a stale issue. Set to `false` to disable 17 | closeComment: false 18 | -------------------------------------------------------------------------------- /scripts/lgsm_bootstrap.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | source /lgsm_functions.sh 4 | 5 | fn_check_user 6 | 7 | export LGSM_GAMESERVER="pzserver" 8 | 9 | if [ "${SERVER_NAME}" != "${LGSM_GAMESERVER}" ] 10 | then 11 | export LGSM_GAMESERVER_RENAME="$(fn_sanitize_string "${SERVER_NAME}")" 12 | fi 13 | 14 | export LGSM_GAMESERVER_START="${SERVER_START:-true}" 15 | 16 | # Check if both directory are writable 17 | if [ ! -L /server-data ] || [ ! -w $(readlink -fn /server-data) ] 18 | then 19 | echo "[Error] Can't access your data directory. Check permissions on your mapped directory with /server-data." 20 | exit 1 21 | fi 22 | 23 | if [ ! -L /server-files ] || [ ! -w $(readlink -fn /server-files) ] 24 | then 25 | echo "[Error] Can't access your server files directory. Check permissions on your mapped directory with /server-files." 26 | exit 1 27 | fi 28 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: Docker Image CI 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | tags: 8 | - v[0-9]+.[0-9]+.[0-9]+ 9 | pull_request: 10 | branches: 11 | - main 12 | 13 | jobs: 14 | main: 15 | runs-on: ubuntu-latest 16 | steps: 17 | - name: Checkout 18 | uses: actions/checkout@v2 19 | - name: Extract version_tag 20 | id: version_tag 21 | uses: cyrale/github-actions/docker-tag@main 22 | with: 23 | tag_replace_pattern: "v" 24 | - name: Set up QEMU 25 | uses: docker/setup-qemu-action@v1 26 | - name: Set up Docker Buildx 27 | uses: docker/setup-buildx-action@v1 28 | - name: Login to DockerHub 29 | uses: docker/login-action@v1 30 | with: 31 | username: ${{ secrets.DOCKERHUB_USERNAME }} 32 | password: ${{ secrets.DOCKERHUB_TOKEN }} 33 | - name: Login to GitHub Container Registry 34 | uses: docker/login-action@v1 35 | with: 36 | registry: ghcr.io 37 | username: ${{ github.repository_owner }} 38 | password: ${{ secrets.GHCR_TOKEN }} 39 | - name: Build and push 40 | id: docker_build 41 | uses: docker/build-push-action@v2 42 | with: 43 | push: true 44 | tags: | 45 | cyrale/project-zomboid:${{ steps.version_tag.outputs.tag }} 46 | ghcr.io/cyrale/project-zomboid:${{ steps.version_tag.outputs.tag }} 47 | - name: Image digest 48 | run: echo ${{ steps.docker_build.outputs.digest }} 49 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ghcr.io/cyrale/linuxgsm:0.2.1 2 | 3 | # Steam ports 4 | ENV STEAM_PORT_1=8766 \ 5 | STEAM_PORT_2=8767 \ 6 | # RCON 7 | RCON_PORT=27015 \ 8 | RCON_PASSWORD="rcon-password" \ 9 | # Server informations 10 | SERVER_NAME="pzserver" \ 11 | SERVER_PASSWORD="" \ 12 | SERVER_PUBLIC_NAME="Project Zomboid Server" \ 13 | SERVER_PUBLIC_DESC="" \ 14 | SERVER_BRANCH="" \ 15 | SERVER_BETA_PASSWORD="" \ 16 | # Admin DB Password (required for the first launch) 17 | ADMIN_PASSWORD="pzserver-password" \ 18 | # Server port 19 | SERVER_PORT=16261 \ 20 | # Game UDP port to allow player to contact the server (by default : 10 players) 21 | PLAYER_PORTS=16262-16272 22 | 23 | # Switch to root to use apt-get 24 | USER root 25 | 26 | # Install dependencies 27 | RUN apt-get update && \ 28 | apt-get install --no-install-recommends -y \ 29 | rng-tools && \ 30 | apt-get -y autoremove && \ 31 | apt-get -y clean && \ 32 | rm -rf /var/lib/apt/lists/* && \ 33 | rm -rf /tmp/* && \ 34 | rm -rf /var/tmp/* 35 | 36 | # Create server directories and link to access them 37 | RUN [ -d /home/linuxgsm/Zomboid ] || mkdir -p /home/linuxgsm/Zomboid && \ 38 | chown linuxgsm:linuxgsm /home/linuxgsm/Zomboid && \ 39 | ln -s /home/linuxgsm/Zomboid /server-data && \ 40 | [ -d /home/linuxgsm/serverfiles ] || mkdir -p /home/linuxgsm/serverfiles && \ 41 | chown linuxgsm:linuxgsm /home/linuxgsm/serverfiles && \ 42 | ln -s /home/linuxgsm/serverfiles /server-files 43 | 44 | # Copy scripts 45 | COPY ./scripts/*.sh / 46 | RUN chmod +x /*.sh 47 | 48 | # Switch to the user steam 49 | USER linuxgsm 50 | 51 | # Make server port available to host : (10 slots) 52 | EXPOSE ${STEAM_PORT_1}/udp ${STEAM_PORT_2}/udp ${SERVER_PORT}/udp ${PLAYER_PORTS} ${RCON_PORT} 53 | 54 | # Persistant folder with server data : /server-data 55 | VOLUME ["/server-data", "/server-files"] 56 | -------------------------------------------------------------------------------- /scripts/lgsm_configuration.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | source /lgsm_functions.sh 4 | source /lgsm_variables.sh 5 | 6 | fn_configuration_already_set() { 7 | local var_name="${1}=" 8 | 9 | if [[ ( ! -z "${LGSM_COMMON_CONFIG}" && ! -z "$(echo "${LGSM_COMMON_CONFIG}" | grep "${var_name}")" ) \ 10 | || (! -z "${LGSM_COMMON_CONFIG_FILE}" && ! -z "$(grep "${var_name}" "${LGSM_COMMON_CONFIG_FILE}")" ) \ 11 | || ( ! -z "${LGSM_SERVER_CONFIG}" && ! -z "$(echo "${LGSM_SERVER_CONFIG}" | grep "${var_name}")" ) \ 12 | || ( ! -z "${LGSM_SERVER_CONFIG_FILE}" && ! -z "$(grep "${var_name}" "${LGSM_SERVER_CONFIG_FILE}")" ) ]] 13 | then 14 | return 1 15 | fi 16 | 17 | return 0 18 | } 19 | 20 | fn_configure_variable () { 21 | fn_configuration_already_set "${1}" 22 | local already_set=$? 23 | 24 | if [[ $already_set -eq 0 ]] 25 | then 26 | if [ -z "$(grep "${1}" "${server_config_file}")" ] 27 | then 28 | echo "${1}=\"${2}\"" >> "${server_config_file}" 29 | else 30 | sed -ri "s/^${1}=\"(.*)\"$/${1}=\"${2}\"/" "${server_config_file}" 31 | fi 32 | fi 33 | } 34 | 35 | fn_check_user 36 | fn_check_lgsm_installed 37 | 38 | cd "${HOME}" 39 | 40 | server_ini_file="/home/linuxgsm/Zomboid/Server/${LGSM_GAMESERVER}.ini" 41 | 42 | if [ ! -z "${LGSM_GAMESERVER_RENAME}" ] 43 | then 44 | server_ini_file="/home/linuxgsm/Zomboid/Server/${LGSM_GAMESERVER_RENAME}.ini" 45 | fi 46 | 47 | # Change LGSM configuration 48 | if [ -f $server_config_file ] 49 | then 50 | ips=($(hostname -I)) 51 | 52 | fn_configure_variable "ip" "${ips[0]}" 53 | fn_configure_variable "adminpassword" $ADMIN_PASSWORD 54 | fn_configure_variable "branch" $SERVER_BRANCH 55 | fn_configure_variable "betapassword" $SERVER_BETA_PASSWORD 56 | fi 57 | 58 | # Change server configuration 59 | if [ -f $server_ini_file ] 60 | then 61 | sed -ri "s/^Password=(.*)$/Password=${SERVER_PASSWORD}/" "${server_ini_file}" 62 | sed -ri "s/^PublicName=(.*)$/PublicName=${SERVER_PUBLIC_NAME}/" "${server_ini_file}" 63 | sed -ri "s/^PublicDescription=(.*)$/PublicDescription=${SERVER_PUBLIC_DESC}/" "${server_ini_file}" 64 | 65 | sed -ri "s/^DefaultPort=([0-9]+)$/DefaultPort=${SERVER_PORT}/" "${server_ini_file}" 66 | sed -ri "s/^SteamPort1=([0-9]+)$/SteamPort1=${STEAM_PORT_1}/" "${server_ini_file}" 67 | sed -ri "s/^SteamPort2=([0-9]+)$/SteamPort2=${STEAM_PORT_2}/" "${server_ini_file}" 68 | sed -ri "s/^RCONPort=([0-9]+)$/RCONPort=${RCON_PORT}/" "${server_ini_file}" 69 | sed -ri "s/^RCONPassword=(.*)$/RCONPassword=${RCON_PASSWORD}/" "${server_ini_file}" 70 | fi 71 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ⚠️ 2 | 3 | Sorry, I have no more time to maintain this project and I no longer play ProjectZomboid to properly follow its progress. Feel free to fork this project and continue this work on your side. 4 | 5 | # Project Zomboid server - Docker image 6 | 7 | Docker version of the Project Zomboid steam server. 8 | 9 | ## How to use this image 10 | 11 | ### Before starting 12 | 13 | Create two directories where you want to run your server : 14 | 15 | - `server-data`: mandatory if you want to keep configuration between each restart 16 | - `server-files`: optional, contains all the files of the application 17 | 18 | If you have any errors with the permissions of these two directories, you can adjust it. It could be done with this commands: 19 | 20 | ```bash 21 | chown 1000:1000 server-data 22 | chown 1000:1000 server-files 23 | ``` 24 | 25 | `1000:1000` represent the user and the group of the LinuxGSM\_ user that run server in the image. 26 | 27 | ### Bridge networking 28 | 29 | #### Docker command 30 | 31 | ```bash 32 | docker run -d --name project-zomboid \ 33 | -e SERVER_NAME="pzserver" \ 34 | -e ADMIN_PASSWORD="pzserver-password" \ 35 | -v $(pwd)/server-data:/server-data \ 36 | -p 8766:8766/udp \ 37 | -p 8767:8767/udp \ 38 | -p 16261:16261/udp \ 39 | -p 16262-16272:16262-16272 \ 40 | -p 27015:27015 \ 41 | ghcr.io/cyrale/project-zomboid 42 | ``` 43 | 44 | #### Docker Compose 45 | 46 | Alternatively, you could use Docker Compose with this `docker-compose.yml` file: 47 | 48 | ```yaml 49 | version: "3.7" 50 | 51 | services: 52 | project-zomboid: 53 | image: ghcr.io/cyrale/project-zomboid 54 | restart: unless-stopped 55 | environment: 56 | SERVER_NAME: "pzserver" 57 | ADMIN_PASSWORD: "pzserver-password" 58 | ports: 59 | - "8766:8766/udp" 60 | - "8767:8767/udp" 61 | - "16261:16261/udp" 62 | - "16262-16272:16262-16272" 63 | - "27015:27015" 64 | volumes: 65 | - ./server-data:/server-data 66 | ``` 67 | 68 | After creating this file, launch the server with `docker-compose up`. 69 | 70 | ### Host networking 71 | 72 | #### Docker command 73 | 74 | ```bash 75 | docker run -d --name project-zomboid \ 76 | --network=host \ 77 | -e SERVER_NAME="pzserver" \ 78 | -e ADMIN_PASSWORD="pzserver-password" \ 79 | -v $(pwd)/server-data:/server-data \ 80 | ghcr.io/cyrale/project-zomboid 81 | ``` 82 | 83 | #### Docker Compose 84 | 85 | Alternatively, you could use Docker Compose with this `docker-compose.yml` file: 86 | 87 | ```yaml 88 | version: "3.7" 89 | 90 | services: 91 | project-zomboid: 92 | image: ghcr.io/cyrale/project-zomboid 93 | restart: unless-stopped 94 | environment: 95 | SERVER_NAME: "pzserver" 96 | ADMIN_PASSWORD: "pzserver-password" 97 | network_mode: host 98 | volumes: 99 | - ./server-data:/server-data 100 | ``` 101 | 102 | After creating this file, launch the server with `docker-compose up`. 103 | 104 | #### Specifying IP address 105 | 106 | In this network mode, you could specify the IP address of the host instead of letting the program do it automatically. 107 | 108 | In the command line, add the parameter `-e LGSM_SERVER_CONFIG='ip="xx.xx.xx.xx"'`. 109 | 110 | In the docker compose file, add this environment variable: 111 | 112 | ```yaml 113 | LGSM_SERVER_CONFIG: | 114 | ip="xx.xx.xx.xx" 115 | ``` 116 | 117 | ### After starting 118 | 119 | Once you have run the docker for the first time, you can edit your config file in your mapped directory `/server-data/Server/$SERVER_NAME.ini`. When it's done, restart your server. 120 | 121 | Some of options are not used in these two examples. Look below if you want to adjust your settings. 122 | 123 | ## Variables 124 | 125 | Some variables are inherited from [cyrale/linuxgsm](https://github.com/cyrale/linuxgsm#variables). 126 | 127 | - **STEAM_PORT_1** Steam port 1 (default: 8766) 128 | - **STEAM_PORT_2** Steam port 2 (default: 8767) 129 | - **RCON_PORT** RCON port (default: 27015) 130 | - **RCON_PASSWORD** RCON password 131 | - **SERVER_NAME** Name of your server (for db & ini file). **Warning:** don't use special characters or spaces. 132 | - **SERVER_PASSWORD** Password of your server used to connect to it 133 | - **SERVER_PUBLIC_NAME** Public name of your server 134 | - **SERVER_PUBLIC_DESC** Public description of your server 135 | - **SERVER_BRANCH** Name of the beta branch 136 | - **SERVER_BETA_PASSWORD** Password for the beta branch 137 | - **ADMIN_PASSWORD** Admin password on your server 138 | - **SERVER_PORT** Game server port 139 | - **PLAYER_PORTS** Game ports to allow player to contact the server (by default : 16262-16272 to allow 10 players) 140 | 141 | **STEAM_PORT_1**, **STEAM_PORT_2**, **RCON_PORT**, **RCON_PASSWORD**, **SERVER_PASSWORD**, **SERVER_PUBLIC_NAME**, **SERVER_PUBLIC_DESC** and **SERVER_PORT** are optional if you have access to the file `/server-data/Server/$SERVER_NAME.ini` where the values are. 142 | 143 | **SERVER_BRANCH**, **SERVER_BETA_PASSWORD** and **ADMIN_PASSWORD** are not used if these values are set by **LGSM_COMMON_CONFIG**, **LGSM_COMMON_CONFIG_FILE**, **LGSM_SERVER_CONFIG** or **LGSM_SERVER_CONFIG_FILE**. These 4 variables from [cyrale/linuxgsm](https://github.com/cyrale/linuxgsm#variables) can override default settings from LinuxGSM\_: [\_default.cfg](https://github.com/GameServerManagers/LinuxGSM/blob/master/lgsm/config-default/config-lgsm/pzserver/_default.cfg). 144 | 145 | ## Volumes 146 | 147 | - **/server-data** Data directory of the server. Contains db, config files... 148 | - **/server-files** Application dir of the server. 149 | 150 | ## Expose 151 | 152 | - **8766** Steam port 1 (udp) 153 | - **8767** Steam port 2 (udp) 154 | - **27015** RCON 155 | - **16261** Game server (udp) 156 | - **16262-16XXX** Clients slots 157 | 158 | You need to bind X ports for client connection. (Example: If you have 10 slots, you need to put `-p 16262-16272:16262-16272`, if you have 100 slots, you need to put `-p 16262-16362:16262-16362`). 159 | --------------------------------------------------------------------------------