diff --git a/Dockerfile b/Dockerfile index 5187dc946..6a6885829 100644 --- a/Dockerfile +++ b/Dockerfile @@ -11,6 +11,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ procps=2:3.3.17-5 \ wget=1.21-1+deb11u1 \ xdg-user-dirs=0.17-2 \ + jo=1.3-2 \ && apt-get clean \ && rm -rf /var/lib/apt/lists/* @@ -27,16 +28,16 @@ ENV RCON_MD5SUM="8601c70dcab2f90cd842c127f700e398" \ SHELL ["/bin/bash", "-o", "pipefail", "-c"] RUN wget --progress=dot:giga https://github.com/gorcon/rcon-cli/releases/download/v${RCON_VERSION}/rcon-${RCON_VERSION}-amd64_linux.tar.gz -O rcon.tar.gz \ - && echo "${RCON_MD5SUM}" rcon.tar.gz | md5sum -c - \ - && tar -xzvf rcon.tar.gz \ - && rm rcon.tar.gz \ - && mv rcon-${RCON_VERSION}-amd64_linux/rcon /usr/bin/rcon-cli \ - && rmdir /tmp/dumps + && echo "${RCON_MD5SUM}" rcon.tar.gz | md5sum -c - \ + && tar -xzvf rcon.tar.gz \ + && rm rcon.tar.gz \ + && mv rcon-${RCON_VERSION}-amd64_linux/rcon /usr/bin/rcon-cli \ + && rmdir /tmp/dumps RUN wget --progress=dot:giga https://github.com/aptible/supercronic/releases/download/v${SUPERCRONIC_VERSION}/supercronic-linux-amd64 -O supercronic \ - && echo "${SUPERCRONIC_SHA1SUM}" supercronic | sha1sum -c - \ - && chmod +x supercronic \ - && mv supercronic /usr/local/bin/supercronic + && echo "${SUPERCRONIC_SHA1SUM}" supercronic | sha1sum -c - \ + && chmod +x supercronic \ + && mv supercronic /usr/local/bin/supercronic ENV PORT= \ PUID=1000 \ @@ -64,7 +65,15 @@ ENV PORT= \ AUTO_UPDATE_WARN_MINUTES=30 \ AUTO_REBOOT_ENABLED=false \ AUTO_REBOOT_WARN_MINUTES=5 \ - AUTO_REBOOT_CRON_EXPRESSION="0 0 * * *" + AUTO_REBOOT_CRON_EXPRESSION="0 0 * * *" \ + DISCORD_WEBHOOK_URL= \ + DISCORD_CONNECT_TIMEOUT=30 \ + DISCORD_MAX_TIMEOUT=30 \ + DISCORD_PRE_UPDATE_BOOT_MESSAGE="Server is updating..." \ + DISCORD_POST_UPDATE_BOOT_MESSAGE="Server update complete!" \ + DISCORD_PRE_START_MESSAGE="Server has been started!" \ + DISCORD_PRE_SHUTDOWN_MESSAGE="Server is shutting down..." \ + DISCORD_POST_SHUTDOWN_MESSAGE="Server has been stopped!" COPY ./scripts/* /home/steam/server/ diff --git a/README.md b/README.md index d71647bee..afd66514a 100644 --- a/README.md +++ b/README.md @@ -155,8 +155,8 @@ It is highly recommended you set the following environment values before startin * PUID * PGID -| Variable | Info | Default Values | Allowed Values | -|--------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|----------------|------------------------------------------------------------------------------------------------------------| +| Variable | Info | Default Values | Allowed Values | +|--------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|----------------|---------------------------------------------------------------------------------------| | TZ | Timezone used for time stamping backup server | UTC | See [TZ Identifiers](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones#Time_Zone_abbreviations) | | PLAYERS* | Max amount of players that are able to join the server | 16 | 1-32 | | PORT* | UDP port that the server will expose | 8211 | 1024-65535 | @@ -184,6 +184,14 @@ It is highly recommended you set the following environment values before startin | AUTO_REBOOT_CRON_EXPRESSION | Setting affects frequency of automatic updates. | 0 0 \* \* \* | Needs a Cron-Expression - See [Configuring Automatic Backups with Cron](#configuring-automatic-reboots-with-cron) | | AUTO_REBOOT_ENABLED | Enables automatic reboots | false | true/false | | AUTO_REBOOT_WARN_MINUTES | How long to wait to reboot the server, after the player were informed. | 5 | !0 | +| DISCORD_WEBHOOK_URL | Discord webhook url found after creating a webhook on a discord server | | `https://discord.com/api/webhooks/` | +| DISCORD_CONNECT_TIMEOUT | Discord command initial connection timeout | 30 | !0 | +| DISCORD_MAX_TIMEOUT | Discord total hook timeout | 30 | !0 | +| DISCORD_PRE_UPDATE_BOOT_MESSAGE | Discord message sent when server begins updating | Server is updating... | "string" | +| DISCORD_POST_UPDATE_BOOT_MESSAGE | Discord message sent when server completes updating | Server update complete! | "string" | +| DISCORD_PRE_START_MESSAGE | Discord message sent when server begins to start | Server is started! | "string" | +| DISCORD_PRE_SHUTDOWN_MESSAGE | Discord message sent when server begins to shutdown | Server is shutting down... | "string" | +| DISCORD_POST_SHUTDOWN_MESSAGE | Discord message sent when server has stopped | Server is stopped! | "string" | *highly recommended to set @@ -425,6 +433,26 @@ Please keep in mind that the ENV variables will always overwrite the changes mad For a more detailed list of explanations of server settings go to: [shockbyte](https://shockbyte.com/billing/knowledgebase/1189/How-to-Configure-your-Palworld-server.html) +## Using discord webhooks + +1. Generate a webhook url for your discord server in your discord's server settings. + +2. Set the environment variable with the unique token at the end of the discord webhook url example: discord.com/api/webhooks/ + +send discord messages with docker run: + +```sh +-e DISCORD_WEBHOOK="xxxx/xxxxx" \ +-e DISCORD_PRE_UPDATE_BOOT_MESSAGE="Server is updating..." \ +``` + +send discord messages with docker compose: + +```yaml +- DISCORD_WEBHOOK=xxxx/xxxxx +- DISCORD_PRE_UPDATE_BOOT_MESSAGE=Server is updating... +``` + ## Reporting Issues/Feature Requests Issues/Feature requests can be submitted by using [this link](https://github.com/thijsvanloef/palworld-server-docker/issues/new/choose). diff --git a/docker-compose.yml b/docker-compose.yml index 90c2b84eb..d0b0937e5 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,25 +1,25 @@ services: - palworld: - image: thijsvanloef/palworld-server-docker:latest - restart: unless-stopped - container_name: palworld-server - stop_grace_period: 30s # Set to however long you are willing to wait for the container to gracefully stop - ports: - - 8211:8211/udp - - 27015:27015/udp # Required if you want your server to show up in the community servers tab - environment: - - PUID=1000 - - PGID=1000 - - PORT=8211 # Optional but recommended - - PLAYERS=16 # Optional but recommended - - SERVER_PASSWORD=worldofpals # Optional but recommended - - MULTITHREADING=true - - RCON_ENABLED=true - - RCON_PORT=25575 - - TZ=UTC - - ADMIN_PASSWORD=adminPasswordHere - - COMMUNITY=false # Enable this if you want your server to show up in the community servers tab, USE WITH SERVER_PASSWORD! - - SERVER_NAME=World of Pals - - SERVER_DESCRIPTION=palworld-server-docker by Thijs van Loef - volumes: - - ./palworld:/palworld/ + palworld: + image: thijsvanloef/palworld-server-docker:latest + restart: unless-stopped + container_name: palworld-server + stop_grace_period: 30s # Set to however long you are willing to wait for the container to gracefully stop + ports: + - 8211:8211/udp + - 27015:27015/udp # Required if you want your server to show up in the community servers tab + environment: + - PUID=1000 + - PGID=1000 + - PORT=8211 # Optional but recommended + - PLAYERS=16 # Optional but recommended + - SERVER_PASSWORD=worldofpals # Optional but recommended + - MULTITHREADING=true + - RCON_ENABLED=true + - RCON_PORT=25575 + - TZ=UTC + - ADMIN_PASSWORD=adminPasswordHere + - COMMUNITY=false # Enable this if you want your server to show up in the community servers tab, USE WITH SERVER_PASSWORD! + - SERVER_NAME=World of Pals + - SERVER_DESCRIPTION=palworld-server-docker by Thijs van Loef + volumes: + - ./palworld:/palworld/ diff --git a/scripts/backup.sh b/scripts/backup.sh index 805326234..c82909e5a 100644 --- a/scripts/backup.sh +++ b/scripts/backup.sh @@ -1,5 +1,9 @@ #!/bin/bash +if [ -n "${DISCORD_WEBHOOK_URL}" ]; then + /home/steam/server/discord.sh "Creating backup..." "in-progress" & +fi + if [ "${RCON_ENABLED,,}" = true ]; then rcon-cli -c /home/steam/server/rcon.yaml save fi @@ -15,15 +19,31 @@ if [ "$(id -u)" -eq 0 ]; then chown steam:steam "$FILE_PATH" fi -echo "backup created at $FILE_PATH" +echo "Backup created at ${FILE_PATH}" +if [ -n "${DISCORD_WEBHOOK_URL}" ]; then + /home/steam/server/discord.sh "Backup created at ${FILE_PATH}" "success" +fi if [ "${DELETE_OLD_BACKUPS,,}" = true ]; then + if [ -z "${OLD_BACKUP_DAYS}" ]; then - echo "Unable to deleted old backups, OLD_BACKUP_DAYS is empty." + echo "Unable to delete old backups, OLD_BACKUP_DAYS is empty." + if [ -n "${DISCORD_WEBHOOK_URL}" ]; then + /home/steam/server/discord.sh "Unable to delete old backups, OLD_BACKUP_DAYS is empty." "warn" + fi elif [[ "${OLD_BACKUP_DAYS}" =~ ^[0-9]+$ ]]; then - echo "removing backups older than ${OLD_BACKUP_DAYS} days" + echo "Removing backups older than ${OLD_BACKUP_DAYS} days" + if [ -n "${DISCORD_WEBHOOK_URL}" ] && [ -n "${DISCORD_PRE_BACKUP_DELETE_MESSAGE}" ]; then + /home/steam/server/discord.sh "Removing backups older than ${OLD_BACKUP_DAYS} days..." "in-progress" & + fi find /palworld/backups/ -mindepth 1 -maxdepth 1 -mtime "+${OLD_BACKUP_DAYS}" -type f -name 'palworld-save-*.tar.gz' -print -delete + if [ -n "${DISCORD_WEBHOOK_URL}" ]; then + /home/steam/server/discord.sh "Removed backups older than ${OLD_BACKUP_DAYS} days" "success" + fi else - echo "Unable to deleted old backups, OLD_BACKUP_DAYS is not an integer. OLD_BACKUP_DAYS=${OLD_BACKUP_DAYS}" + echo "Unable to delete old backups, OLD_BACKUP_DAYS is not an integer. OLD_BACKUP_DAYS=${OLD_BACKUP_DAYS}" + if [ -n "${DISCORD_WEBHOOK_URL}" ]; then + /home/steam/server/discord.sh "Unable to delete old backups, OLD_BACKUP_DAYS is not an integer. OLD_BACKUP_DAYS=${OLD_BACKUP_DAYS}" "failure" + fi fi -fi +fi \ No newline at end of file diff --git a/scripts/discord.sh b/scripts/discord.sh new file mode 100644 index 000000000..6cae70147 --- /dev/null +++ b/scripts/discord.sh @@ -0,0 +1,59 @@ +#!/bin/bash + +# Defaults +DEFAULT_CONNECT_TIMEOUT=30 +DEFAULT_MAX_TIMEOUT=30 +DEFAULT_LEVEL="info" +DISCORD_BLUE=1127128 +DISCORD_YELLOW=15258703 +DISCORD_ORANGE=14177041 +DISCORD_RED=14614528 +DISCORD_GREEN=52224 + +# Parse arguments +MESSAGE=$1 +LEVEL=$2 + +if [ -n "${DISCORD_CONNECT_TIMEOUT}" ] && [[ "${DISCORD_CONNECT_TIMEOUT}" =~ ^[0-9]+$ ]]; then + CONNECT_TIMEOUT=$DISCORD_CONNECT_TIMEOUT +else + echo "CONNECT_TIMEOUT is not an integer, using default ${DEFAULT_CONNECT_TIMEOUT} seconds." + CONNECT_TIMEOUT=$DEFAULT_CONNECT_TIMEOUT +fi + +if [ -n "${DISCORD_MAX_TIMEOUT}" ] && [[ "${DISCORD_MAX_TIMEOUT}" =~ ^[0-9]+$ ]]; then + MAX_TIMEOUT=$DISCORD_MAX_TIMEOUT +else + echo "MAX_TIMEOUT is not an integer, using default ${DEFAULT_MAX_TIMEOUT} seconds." + MAX_TIMEOUT=$DEFAULT_MAX_TIMEOUT +fi + +if [ -n "${LEVEL}" ]; then + case $LEVEL in + info ) + COLOR=$DISCORD_BLUE + ;; + in-progress ) + COLOR=$DISCORD_YELLOW + ;; + warn ) + COLOR=$DISCORD_ORANGE + ;; + failure ) + COLOR=$DISCORD_RED + ;; + success ) + COLOR=$DISCORD_GREEN + ;; + * ) + echo "Could not find \"${LEVEL}\", using \"${DEFAULT_LEVEL}\"" + COLOR=$DISCORD_BLUE + ;; + esac +else + COLOR=$DISCORD_BLUE +fi + +JSON=$(jo embeds[]="$(jo title="$MESSAGE" color=$COLOR)") +echo "Sending Discord json: ${JSON}" +curl -sfSL --connect-timeout "$CONNECT_TIMEOUT" --max-time "$MAX_TIMEOUT" -H "Content-Type: application/json" -d "$JSON" "$DISCORD_WEBHOOK_URL" diff --git a/scripts/init.sh b/scripts/init.sh index ba664050d..35ee2253a 100644 --- a/scripts/init.sh +++ b/scripts/init.sh @@ -5,7 +5,7 @@ if [[ ! "${PUID}" -eq 0 ]] && [[ ! "${PGID}" -eq 0 ]]; then usermod -o -u "${PUID}" steam groupmod -o -g "${PGID}" steam else - printf "\033[31mRunning as root is not supported, please fix your PUID and PGID!\n" + printf "\033[31m%s\n" "Running as root is not supported, please fix your PUID and PGID!" exit 1 fi @@ -14,12 +14,17 @@ chown -R steam:steam /palworld /home/steam/ # shellcheck disable=SC2317 term_handler() { + if [ -n "${DISCORD_WEBHOOK_URL}" ] && [ -n "${DISCORD_PRE_SHUTDOWN_MESSAGE}" ]; then + su steam -c "/home/steam/server/discord.sh '${DISCORD_PRE_SHUTDOWN_MESSAGE}' in-progress" & + fi + if [ "${RCON_ENABLED,,}" = true ]; then rcon-cli save rcon-cli "shutdown 1" else # Does not save kill -SIGTERM "$(pidof PalServer-Linux-Test)" fi + tail --pid="$killpid" -f 2>/dev/null } diff --git a/scripts/start.sh b/scripts/start.sh index ceb1a7300..ad7ab56c2 100644 --- a/scripts/start.sh +++ b/scripts/start.sh @@ -57,8 +57,17 @@ isExecutable "/palworld" || exit cd /palworld || exit if [ "${UPDATE_ON_BOOT,,}" = true ]; then - printf "\e[0;32m*****STARTING INSTALL/UPDATE*****\e[0m\n" + printf "\e[0;32m%s\e[0m\n" "*****STARTING INSTALL/UPDATE*****" + + if [ -n "${DISCORD_WEBHOOK_URL}" ] && [ -n "${DISCORD_PRE_UPDATE_BOOT_MESSAGE}" ]; then + /home/steam/server/discord.sh "${DISCORD_PRE_UPDATE_BOOT_MESSAGE}" "in-progress" & + fi + /home/steam/steamcmd/steamcmd.sh +@sSteamCmdForcePlatformType linux +@sSteamCmdForcePlatformBitness 64 +force_install_dir "/palworld" +login anonymous +app_update 2394010 validate +quit + + if [ -n "${DISCORD_WEBHOOK_URL}" ] && [ -n "${DISCORD_POST_UPDATE_BOOT_MESSAGE}" ]; then + /home/steam/server/discord.sh "${DISCORD_POST_UPDATE_BOOT_MESSAGE}" "success" + fi fi STARTCOMMAND=("./PalServer.sh") @@ -86,12 +95,12 @@ if [ "${MULTITHREADING,,}" = true ]; then STARTCOMMAND+=("-useperfthreads" "-NoAsyncLoadingThread" "-UseMultithreadForDS") fi -printf "\e[0;32m*****CHECKING FOR EXISTING CONFIG*****\e[0m\n" +printf "\e[0;32m%s\e[0m\n" "*****CHECKING FOR EXISTING CONFIG*****" # shellcheck disable=SC2143 if [ ! "$(grep -s '[^[:space:]]' /palworld/Pal/Saved/Config/LinuxServer/PalWorldSettings.ini)" ]; then - printf "\e[0;32m*****GENERATING CONFIG*****\e[0m\n" + printf "\e[0;32m%s\e[0m\n" "*****GENERATING CONFIG*****" # Server will generate all ini files after first run. timeout --preserve-status 15s ./PalServer.sh 1> /dev/null @@ -125,7 +134,7 @@ if [ -n "${SERVER_PASSWORD}" ]; then fi if [ -n "${ADMIN_PASSWORD}" ]; then ADMIN_PASSWORD=$(sed -e 's/^"\(.*\)"$/\1/' -e "s/^'\(.*\)'$/\1/" <<< "$ADMIN_PASSWORD") - echo "ADMIN_PASSWORD=${ADMIN_PASSWORD}" + echo "ADMIN_PASSWORD=${ADMIN_PASSWORD}" sed -E -i "s/AdminPassword=\"[^\"]*\"/AdminPassword=\"$ADMIN_PASSWORD\"/" /palworld/Pal/Saved/Config/LinuxServer/PalWorldSettings.ini fi if [ -n "${PLAYERS}" ]; then @@ -367,7 +376,6 @@ fi rm -f "/home/steam/server/crontab" if [ "${BACKUP_ENABLED,,}" = true ]; then echo "BACKUP_ENABLED=${BACKUP_ENABLED,,}" - echo "$BACKUP_CRON_EXPRESSION bash /usr/local/bin/backup" >> "/home/steam/server/crontab" fi @@ -393,7 +401,16 @@ default: password: "${ADMIN_PASSWORD}" EOL -printf "\e[0;32m*****STARTING SERVER*****\e[0m\n" +printf "\e[0;32m%s\e[0m\n" "*****STARTING SERVER*****" +if [ -n "${DISCORD_WEBHOOK_URL}" ] && [ -n "${DISCORD_PRE_START_MESSAGE}" ]; then + /home/steam/server/discord.sh "${DISCORD_PRE_START_MESSAGE}" "success" & +fi + echo "${STARTCOMMAND[*]}" "${STARTCOMMAND[@]}" + +if [ -n "${DISCORD_WEBHOOK_URL}" ] && [ -n "${DISCORD_POST_SHUTDOWN_MESSAGE}" ]; then + /home/steam/server/discord.sh "${DISCORD_POST_SHUTDOWN_MESSAGE}" "failure" +fi + exit 0 diff --git a/scripts/update.sh b/scripts/update.sh index a20798c4c..614597a74 100644 --- a/scripts/update.sh +++ b/scripts/update.sh @@ -2,6 +2,9 @@ if [ "${UPDATE_ON_BOOT}" = false ]; then echo "Update on Boot needs to be enabled for auto updating" + if [ -n "${DISCORD_WEBHOOK_URL}" ]; then + /home/steam/server/discord.sh "Update on Boot needs to be enabled for auto updating" "warn" + fi exit 0 fi @@ -14,11 +17,17 @@ rm "$temp_file" if [ "$http_code" -ne 200 ]; then echo "There was a problem reaching the Steam api. Unable to check for updates!" + if [ -n "${DISCORD_WEBHOOK_URL}" ]; then + /home/steam/server/discord.sh "There was a problem reaching the Steam api. Unable to check for updates!" "failure" & + fi exit 1 fi if [ -z "$TARGETBUILD" ]; then echo "The server response does not contain the expected BuildID. Unable to check for updates!" + if [ -n "${DISCORD_WEBHOOK_URL}" ]; then + /home/steam/server/discord.sh "Steam servers response does not contain the expected BuildID. Unable to check for updates!" "failure" & + fi exit 1 fi @@ -26,12 +35,18 @@ if [ "$CURRENTBUILD" != "$TARGETBUILD" ]; then echo "New Build was found. Updating the server from $CURRENTBUILD to $TARGETBUILD." if [ "${RCON_ENABLED,,}" = true ]; then rm /palworld/steamapps/appmanifest_2394010.acf + if [ -n "${DISCORD_WEBHOOK_URL}" ]; then + /home/steam/server/discord.sh "Server will update in ${AUTO_UPDATE_WARN_MINUTES} minutes" "info" & + fi rcon-cli -c /home/steam/server/rcon.yaml "broadcast The_Server_will_update_in_${AUTO_UPDATE_WARN_MINUTES}_Minutes" sleep "${AUTO_UPDATE_WARN_MINUTES}m" backup rcon-cli -c /home/steam/server/rcon.yaml "shutdown 1" else echo "An update is available however auto updating without rcon is not supported" + if [ -n "${DISCORD_WEBHOOK_URL}" ]; then + /home/steam/server/discord.sh "An update is available however auto updating without rcon is not supported" "warn" + fi fi else echo "The Server is up to date!"