diff --git a/Dockerfile b/Dockerfile index 963f15a8f..712644e36 100644 --- a/Dockerfile +++ b/Dockerfile @@ -19,10 +19,10 @@ ENV SUPERCRONIC_URL=https://github.com/aptible/supercronic/releases/download/v0. SUPERCRONIC_SHA1SUM=cd48d45c4b10f3f0bfdd3a57d054cd05ac96812b RUN wget -q "$SUPERCRONIC_URL" \ - && echo "${SUPERCRONIC_SHA1SUM} ${SUPERCRONIC}" | sha1sum -c - \ - && chmod +x "$SUPERCRONIC" \ - && mv "$SUPERCRONIC" "/usr/local/bin/${SUPERCRONIC}" \ - && ln -s "/usr/local/bin/${SUPERCRONIC}" /usr/local/bin/supercronic + && echo "${SUPERCRONIC_SHA1SUM} ${SUPERCRONIC}" | sha1sum -c - \ + && chmod +x "$SUPERCRONIC" \ + && mv "$SUPERCRONIC" "/usr/local/bin/${SUPERCRONIC}" \ + && ln -s "/usr/local/bin/${SUPERCRONIC}" /usr/local/bin/supercronic ENV PORT= \ PUID=1000 \ @@ -53,9 +53,11 @@ ENV PORT= \ AUTO_REBOOT_CRON_EXPRESSION="0 0 * * *" COPY ./scripts/* /home/steam/server/ + RUN chmod +x /home/steam/server/*.sh && \ mv /home/steam/server/backup.sh /usr/local/bin/backup && \ - mv /home/steam/server/update.sh /usr/local/bin/update + mv /home/steam/server/update.sh /usr/local/bin/update && \ + mv /home/steam/server/restore.sh /usr/local/bin/restore WORKDIR /home/steam/server diff --git a/README.md b/README.md index 85e29814d..cf2ab5af5 100644 --- a/README.md +++ b/README.md @@ -245,6 +245,21 @@ This will create a backup at `/palworld/backups/` The server will run a save before the backup if rcon is enabled. +## Restore from a backup + +To restore from a backup, use the command: + +```bash +docker exec -it palworld-server restore +``` + +The `RCON_ENABLED` environment variable must be set to `true` to use this command. +> [!IMPORTANT] +> If docker restart is not set to policy `always` or `unless-stopped` then the server will shutdown and will need to be +> manually restarted. +> +> The example docker run command and docker compose file in [How to Use](#how-to-use) already uses the needed policy + ## Manually restore from a backup Locate the backup you want to restore in `/palworld/backups/` and decompress it. diff --git a/docs/kr/README.md b/docs/kr/README.md index 820f76801..a9b0dadd6 100644 --- a/docs/kr/README.md +++ b/docs/kr/README.md @@ -13,14 +13,14 @@ [English](/README.md) | [한국어](/docs/kr/README.md) | [简体中文](/docs/zh-CN/README.md) -> [!Tip] +> [!TIP] > 어떻게 시작해야 할지 모르시나요? [제가 작성한 이 가이드](https://tice.tips/containerization/palworld-server-docker/)를 확인해 보세요 [Palworld](https://store.steampowered.com/app/1623730/Palworld/) 전용 서버 호스팅을 시작하는 데 도움이 되는 Docker 컨테이너입니다. 이 도커 컨테이너는 테스트되었으며 Linux(Ubuntu/Debian), Windows 10 및 macOS (Apple Silicon 포함) 모두에서 작동합니다. -> [!Important] +> [!IMPORTANT] > 현재 Xbox Gamepass/Xbox 콘솔 플레이어는 전용 서버에 참여할 수 없습니다. > > 초대 코드를 통해 다른 플레이어들과 함께 게임을 즐길 수 있으며, 게임은 최대 4명의 플레이어로 제한됩니다. @@ -188,7 +188,7 @@ docker exec -it palworld-server rcon-cli ## 백업 만들기 -현재 시점의 게임 세이브 백업을 생성하려면 다음 명령을 사용합니다. +현재 시점의 게임 세이브 백업을 생성하려면 다음 명령을 사용합니다: ```bash docker exec palworld-server backup @@ -198,11 +198,26 @@ docker exec palworld-server backup rcon이 활성화된 경우 서버는 백업 전에 저장을 실행합니다. +## 백업 복원 하기 + +백업을 복원하려면 다음 명령을 사용합니다: + +```bash +docker exec -it palworld-server restore +``` + +복원 명령어를 사용하려면 `RCON_ENABLED` 환경 변수가 `true`여야 합니다. + +> [!IMPORTANT] +> 도커 `restart` 정책이 `always` 또는 `unless-stopped`로 설정 되어있지 않다면 복원 이후 컨테이너가 종료되므로 수동으로 재시작 해야 합니다. +> +> [사용하기](#사용하기)에서 제공된 Docker 실행 명령어와 Docker Compose 파일 예시는 이미 필요한 정책을 적용하고 있습니다. + ## 서버 설정 편집 ### 환경 변수 사용 설정 -> [!Important] +> [!IMPORTANT] > > 게임이 아직 베타버전이므로 이러한 환경 변수/설정은 변경될 수 있습니다 @@ -276,7 +291,7 @@ rcon이 활성화된 경우 서버는 백업 전에 저장을 실행합니다. 서버 설정에 대한 자세한 설명 목록을 보려면 다음을 참조하세요: [shockbyte](https://shockbyte.com/billing/knowledgebase/1189/How-to-Configure-your-Palworld-server.html) -> [!Tip] +> [!TIP] > 만약 `/Pal/Saved/Config/LinuxServer/PalWorldSettings.ini` 파일 내부가 비어 있으면, > 파일을 삭제하고 서버를 다시 시작하면 콘텐츠가 포함된 새 파일이 생성됩니다. diff --git a/scripts/init.sh b/scripts/init.sh index d4d99e4c0..47102401c 100644 --- a/scripts/init.sh +++ b/scripts/init.sh @@ -36,3 +36,11 @@ if [ "${#backup_pids[@]}" -ne 0 ]; then tail --pid="$pid" -f 2>/dev/null done fi + +mapfile -t restore_pids < <(pgrep restore) +if [ "${#restore_pids[@]}" -ne 0 ]; then + echo "Waiting for restore to finish" + for pid in "${restore_pids[@]}"; do + tail --pid="$pid" -f 2>/dev/null + done +fi diff --git a/scripts/restore.sh b/scripts/restore.sh new file mode 100644 index 000000000..e0f287273 --- /dev/null +++ b/scripts/restore.sh @@ -0,0 +1,126 @@ +#!/bin/bash + +# Backup file directory path +BACKUP_DIRECTORY_PATH="/palworld/backups" + +# Resotre path +RESTORE_PATH="/palworld/Pal" + +# Copy the save file before restore temporary path +TMP_SAVE_PATH="/palworld/backups/restore-"$(date +"%Y-%m-%d_%H-%M-%S") + +# shellcheck disable=SC2317 +term_error_handler() { + echo "An error occurred during server shutdown." + exit 1 +} + +# shellcheck disable=SC2317 +restore_error_handler() { + printf "\033[0;31mAn error occurred during restore.\033[0m\n" + if [ -d "$TMP_SAVE_PATH/Saved" ]; then + read -rp "I have a backup before recovery can proceed. Do you want to recovery it? (y/n): " RUN_ANSWER + if [[ ${RUN_ANSWER,,} == "y" ]]; then + rm -rf "$RESTORE_PATH/Saved" + mv "$TMP_SAVE_PATH/Saved" "$RESTORE_PATH" + printf "\e[0;32mRecovery complete.\e[0m\n" + fi + fi + + echo "Clean up the temporary directory." + rm -rf "$TMP_PATH" "$TMP_SAVE_PATH" + + exit 1 +} + +if [ "${RCON_ENABLED}" != true ]; then + echo "RCON is not enabled. Please enable RCON to use this feature." + exit 1 +fi + +# Show up backup list +echo "Backup List:" +mapfile -t BACKUP_FILES < <(find "$BACKUP_DIRECTORY_PATH" -type f -name "*.tar.gz" | sort) +select BACKUP_FILE in "${BACKUP_FILES[@]}"; do + if [ -n "$BACKUP_FILE" ]; then + echo "Selected backup: $BACKUP_FILE" + break + else + echo "Invalid selection. Please try again." + fi +done + +if [ -f "$BACKUP_FILE" ]; then + printf "\033[0;31mThis script has been designed to help you restore; however, I am not responsible for any data loss. It is recommended that you create a backup beforehand, and in the event of script failure, be prepared to restore it manually.\033[0m\n" + echo "Do you understand the above and would you like to proceed with this command?" + read -rp "When you run it, the server will be stopped and the recovery will proceed. (y/n): " RUN_ANSWER + if [[ ${RUN_ANSWER,,} == "y" ]]; then + printf "\e[0;32m*****STARTING PROCESS*****\e[0m\n" + # Shutdown server + trap 'term_error_handler' ERR + + if [ "${RCON_ENABLED}" = true ]; then + printf "\e[0;32m*****SHUTDOWN SERVER*****\e[0m\n" + rcon-cli -c /home/steam/server/rcon.yaml save + rcon-cli -c /home/steam/server/rcon.yaml "shutdown 1" + else + echo "RCON is not enabled. Please enable RCON to use this feature. Unable to restore backup." + exit 1 + fi + printf "\e[0;32mShutdown complete.\e[0m\n" + + trap - ERR + + trap 'restore_error_handler' ERR + + printf "\e[0;32m*****START RESTORE*****\e[0m\n" + + # Recheck the backup file + if [ -f "$BACKUP_FILE" ]; then + # Copy the save file before restore + if [ -d "$RESTORE_PATH/Saved" ]; then + echo "Saves the current state before the restore proceeds." + echo "$TMP_SAVE_PATH" + mkdir -p "$TMP_SAVE_PATH" + if [ "$(id -u)" -eq 0 ]; then + chown steam:steam "$TMP_SAVE_PATH" + fi + \cp -rf "$RESTORE_PATH/Saved" "$TMP_SAVE_PATH/Saved" + + while [ ! -d "$TMP_SAVE_PATH/Saved" ]; do + sleep 1 + done + + printf "\e[0;32mSave complete.\e[0m\n" + fi + + # Create tmp directory + TMP_PATH=$(mktemp -d -p "/palworld/backups") + if [ "$(id -u)" -eq 0 ]; then + chown steam:steam "$TMP_PATH" + fi + + # Decompress the backup file in tmp directory + tar -zxvf "$BACKUP_FILE" -C "$TMP_PATH" + + # Move the backup file to the restore directory + \cp -rf -f "$TMP_PATH/Saved/" "$RESTORE_PATH" + + echo "Clean up the temporary directory." + rm -rf "$TMP_PATH" "$TMP_SAVE_PATH" + + printf "\e[0;32mRestore complete!!!! Please restart the Docker container\e[0m\n" + + exit 0 + else + echo "The selected backup file does not exist." + exit 1 + fi + else + echo "Abort the recovery." + exit 1 + fi +else + echo "The selected backup file does not exist." + exit 1 +fi \ No newline at end of file