Tag - Docker

1~3/3
  • Docker로 Longvinter 서버 열기 (AMD64, ARM64)

    2024-04-04 16:04:53 먼저 AMD64 아키텍처에서는 Longvinter에서 공식적으로 사설 서버를 도커로 돌릴 수 있도록 소스 코드를 올려두긴 했다. 하지만 이를 제대로 사용하려면 소스 코드를 수정해야 한다. 그렇지 않으면 단순히 서버를 실행하기만 하는 용도로만 사용할 수 있다. 여기서 사용할 이미지(GitHub)는 Palworld 서버를 열 때 사용한 이미지의 소스 코드를 롱빈터용으로 수정한 것이다. 리눅스에 도커가 설치되어 있다는 가정 하에 진행 이미지 다운로드 이 과정은 생략해도 어차피 나중에 자동으로 다운로드가 진행된다. docker pull kimzuni/longvinter-docker-server:latest 서버 실행 준비 docker-compose.yml 파일 작성 mkdir -p ~/docker/longvinter cd ~/docker/longvinter vi docker-compose.yml 원래 제일 첫 번째 줄에 적던 version: "x.x" 구문은 이제 의미가 없어졌다고 작성하지 않아도 된다고 한다. services: longvinter-server: container_name: longvinter-server image: kimzuni/longvinter-docker-server:latest restart: unless-stopped stop_grace_period: 30s logging: driver: json-file options: max-size: "10m" max-file: "3" ports: - "7777:7777/tcp" - "7777:7777/udp" - "27016:27016/tcp" - "27016:27016/udp" environment: TZ: "UTC" PUID: 1000 PGID: 1000 PORT: 7777 QUERY_PORT: 27016 CFG_SERVER_NAME: "Unnamed Island" CFG_MAX_PLAYERS: 32 CFG_SERVER_MOTD: "Welcome to Longvinter Island!" CFG_PASSWORD: "" CFG_COMMUNITY_WEBSITE: "www.longvinter.com" CFG_COOP_PLAY: false CFG_COOP_SPAWN: 0 CFG_SERVER_TAG: "none" CFG_ADMIN_STEAM_ID: "" CFG_ENABLE_PVP: true CFG_TENT_DECAY: true CFG_MAX_TENTS: 2 volumes: - ./data:/data networks: games: ipv4_address: 172.16.11.12 networks: games: name: games external: true 서버 실행 docker compose up -d # 실행 docker logs -f longvinter-server # 컨테이너 로그 확인 필터링을 위한 비속어가 포함된 굉장히 긴 로그가 나타나고 잠시 후 아래와 같은 로그가 뜨면 서버에 접속할 수 있다. ****Starting Server**** /data/LongvinterServer.sh -Port=7777 -QueryPort=27016 time="2024-04-04T08:50:08Z" level=info msg="read crontab: /home/steam/server/crontab" ... [2024.04.04-09.04.21:243][ 74]LogEOS: Verbose: CreateSession: Successfully created session 'Unnamed Island' with ID 'fb347698360146d5971fe63b8ad04bfe' [2024.04.04-09.04.21:573][ 84]LogNet: ReplicationDriverClass is null! Not using ReplicationDriver. [2024.04.04-09.04.21:573][ 84]LogNetCore: DDoS detection status: detection enabled: 0 analytics enabled: 0 [2024.04.04-09.04.21:573][ 84]LogInit: BSD IPv4/6: Socket queue. Rx: 262144 (config 131072) Tx: 262144 (config 131072) [2024.04.04-09.04.21:573][ 84]LogNet: Created socket for bind address: 0.0.0.0 on port 7787 그 외 docker compose 명령어는 docker-compose.yml 파일이 있는 위치 또는 그 하위에서 실행해야 햔다. docker restart longvinter-server # 재시작 docker compose down # 종료 docker pause longvinter-server # 일시정지 docker unpause longvinter-server # 일시정지 해제 Failed to find object ARM64 버전에선 아래와 같은 경고 메시지가 굉장히 많이 뜨긴 하지만, 서버를 들어가보면 모든 오브젝트들이 아무런 문제 없이 표시되며, 정상적으로 플레이가 가능하다. [2024.04.03-12.41.47:651][ 0]LogUObjectGlobals: Warning: Failed to find object 'Object None.None'
  • Docker로 Palworld 서버 열기 (ARM64)

    2024-02-09 21:25:01 Docker로 Palworld 서버 열기 (ARM64) Ver. 2 위 방법을 사용하자. 이전 글에서 작성한 과정은 노트북에서 진행했고, 서버를 24시간으로 돌리기 위해 오라클 클라우드로 옮겼는데 문제가 발생했다. 사용한 이미지가 AMD 버전만 지원한다는 것을 몰랐다. 그래서 ARM 버전의 이미지가 있는지 찾아보던 중 이전 글에서 사용한 이미지를 ARM 버전으로 Fork한 저장소를 찾았고, 바로 도전. …하려고 했으나 앞서 말했듯 기존 이미지의 업데이트가 매우 빠르기 때문에 Fork한 저장소도 벌써 매우 구 버전이 되어버렸다. 그래서 이 이미지를 바로 사용하기보다는 어떤 것들을 바꿨는지 확인하고 현재 thijsvanloef/palworld-server-docker 저장소의 최신 버전에서 해당 방법을 적용하여 직접 이미지를 빌드해서 사용하고 있다. Dockerfile 최종 Dockerfile의 내용 주요 내용은 AMD 버전만 지원하는 것을 ARM에서 실행하기 위해 FEX-Emu를 사용하는 것이다. # ARM steamcmd: https://github.com/TeriyakiGod/steamcmd-docker-arm64 # FROM teriyakigod/steamcmd:arm64 # CPU_MHZ Error FROM ubuntu:22.04 ENV DEBIAN_FRONTEND=noninteractive RUN apt-get update && \ apt-get install -y \ git \ cmake \ ninja-build \ pkg-config \ ccache \ clang \ llvm \ lld \ binfmt-support \ libsdl2-dev \ libepoxy-dev \ libssl-dev \ python-setuptools \ g++-x86-64-linux-gnu \ nasm \ python3-clang \ libstdc++-10-dev-i386-cross \ libstdc++-10-dev-amd64-cross \ libstdc++-10-dev-arm64-cross \ squashfs-tools \ squashfuse \ libc-bin \ expect \ curl \ fuse \ wget WORKDIR /fex RUN git clone --recurse-submodules https://github.com/FEX-Emu/FEX.git && \ cd FEX && \ mkdir Build && \ cd Build && \ CC=clang CXX=clang++ cmake -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_BUILD_TYPE=Release -DUSE_LINKER=lld -DENABLE_LTO=True -DBUILD_TESTS=False -DENABLE_ASSERTIONS=False -G Ninja .. && \ ninja && \ ninja install && \ ninja binfmt_misc_32 && \ ninja binfmt_misc_64 RUN useradd -m -s /bin/bash steam USER steam WORKDIR /home/steam/.fex-emu/RootFS/ RUN curl -sqL Ubuntu_22_04.tar.gz https://www.dropbox.com/scl/fi/16mhn3jrwvzapdw50gt20/Ubuntu_22_04.tar.gz?rlkey=4m256iahwtcijkpzcv8abn7nf | tar xzf - && \ echo '{"Config":{"RootFS":"Ubuntu_22_04"}}' > ../Config.json WORKDIR /home/steam/steamcmd RUN curl -sqL "https://steamcdn-a.akamaihd.net/client/installer/steamcmd_linux.tar.gz" | tar zxvf - \ && FEXBash -c "/home/steam/steamcmd/steamcmd.sh +quit" \ && mkdir -p ~/.steam/sdk64/ \ && ln -sf ../../steamcmd/linux64/steamclient.so ~/.steam/sdk64/ # Palworld Server on Docker: https://github.com/thijsvanloef/palworld-server-docker USER root ENV RCON_MD5SUM="8601c70dcab2f90cd842c127f700e398" \ SUPERCRONIC_SHA1SUM="512f6736450c56555e01b363144c3c9d23abed4c" \ RCON_VERSION="0.10.3" \ SUPERCRONIC_VERSION="0.2.29" 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 \ && echo -e "#!/usr/bin/env bash\nsu steam -c \"FEXBash -c '`pwd`/rcon-${RCON_VERSION}-amd64_linux/rcon \$@'\"" > /usr/bin/rcon-cli \ && chmod +x /usr/bin/rcon-cli RUN wget --progress=dot:giga https://github.com/aptible/supercronic/releases/download/v${SUPERCRONIC_VERSION}/supercronic-linux-arm64 -O supercronic \ && echo "${SUPERCRONIC_SHA1SUM}" supercronic | sha1sum -c - \ && chmod +x supercronic \ && mv supercronic /usr/local/bin/supercronic ENV PORT= \ PUID=1000 \ PGID=1000 \ PLAYERS= \ MULTITHREADING=false \ COMMUNITY=false \ PUBLIC_IP= \ PUBLIC_PORT= \ SERVER_PASSWORD= \ SERVER_NAME= \ ADMIN_PASSWORD= \ UPDATE_ON_BOOT=true \ RCON_ENABLED=true \ RCON_PORT=25575 \ QUERY_PORT=27015 \ TZ=UTC \ SERVER_DESCRIPTION= \ BACKUP_ENABLED=true \ DELETE_OLD_BACKUPS=false \ OLD_BACKUP_DAYS=30 \ BACKUP_CRON_EXPRESSION="0 0 * * *" \ AUTO_UPDATE_ENABLED=false \ AUTO_UPDATE_CRON_EXPRESSION="0 * * * *" \ AUTO_UPDATE_WARN_MINUTES=30 \ AUTO_REBOOT_ENABLED=false \ AUTO_REBOOT_WARN_MINUTES=5 \ 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/restore.sh /usr/local/bin/restore WORKDIR /home/steam/server HEALTHCHECK --start-period=5m \ CMD pgrep "PalServer-Linux" > /dev/null || exit 1 EXPOSE ${PORT} ${RCON_PORT} ENTRYPOINT ["/home/steam/server/init.sh"] 내가 변경한 주요 내용은 FEX-Emu 설치를 위해 FEX 유저를 만들고 패스워드 없이 sudo 명령어를 사용하도록 함 => 그냥 root로 진행 rcon-cli 명령어를 기존 이미지에서 사용하는 rcon으로 복구 Fork 버전에서는 ARM64 버전을 지원하는 itzg의 rcon-cli를 사용 => rcon으로 명령어를 전송할 때마다 Weird. This response is for another request. 에러가 같이 딸려 나옴 기존 이미지에서는 gorcon의 rcon-cli를 사용 => ARM 버전은 맥 전용밖에 없기 때문에 AMD로 설치하여 FEX-Emu로 실행하도록 함 기존 이미지의 최신 버전에서 supercronic를 사용 => ARM 버전으로 변경 steamclient.so 에러 해결. 참고 steamcmd를 한 번 실행하기 때문에 이미지 용량이 커짐 => start.sh 파일에서 사용하면 됨 대신 이후에 컨테이너를 실행할 때마다 시간 단축됨 ./scripts/* 이미지 빌드 시 복사되는 스크립트 파일들이 담긴 디렉토리. 기존 이미지에서 이 파일들이 매우 많이 업데이트가 되었기 때문에 Fork 버전이 아닌 기존 저장소의 scripts 폴더를 통째로 복사하여 수정했다. init.sh #!/bin/bash :<< "END" if [[ ! "${PUID}" -eq 0 ]] && [[ ! "${PGID}" -eq 0 ]]; then printf "\e[0;32m*****EXECUTING USERMOD*****\e[0m\n" 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" exit 1 fi END mkdir -p /palworld/backups chown -R steam:steam /palworld /home/steam/server # /home/steam/ # shellcheck disable=SC2317 term_handler() { 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 } trap 'term_handler' SIGTERM su steam -c ./start.sh & # Process ID of su killpid="$!" wait "$killpid" mapfile -t backup_pids < <(pgrep backup) if [ "${#backup_pids[@]}" -ne 0 ]; then echo "Waiting for backup to finish" for pid in "${backup_pids[@]}"; do 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 FEX-Emu를 사용하는 것 때문에 /home/steam/.fex-emu/RootFS의 용량이 2~3GB 정도 된다. 그래서 groupmod, chown 명령어 실행 시간이 매우 오래 걸려서 결국 PUID, PGID 설정은 주석 처리, chown 명령어는 /home/steam 대신 /home/steam/server에만 적용해서 시간 단축. 따라서 무조건 PUID, PGID는 1000으로 고정 => Dockerfile에서 유저 만들 때 지정하면 됨 start.sh #!/bin/bash dirExists() { local path="$1" local return_val=0 if ! [ -d "${path}" ]; then echo "${path} does not exist." return_val=1 fi return "$return_val" } fileExists() { local path="$1" local return_val=0 if ! [ -f "${path}" ]; then echo "${path} does not exist." return_val=1 fi return "$return_val" } isReadable() { local path="$1" local return_val=0 if ! [ -e "${path}" ]; then echo "${path} is not readable." return_val=1 fi return "$return_val" } isWritable() { local path="$1" local return_val=0 if ! [ -w "${path}" ]; then echo "${path} is not writable." return_val=1 fi return "$return_val" } isExecutable() { local path="$1" local return_val=0 if ! [ -x "${path}" ]; then echo "${path} is not executable." return_val=1 fi return "$return_val" } dirExists "/palworld" || exit isWritable "/palworld" || exit isExecutable "/palworld" || exit cd /palworld || exit if [ "${UPDATE_ON_BOOT,,}" = true ]; then printf "\e[0;32m*****STARTING INSTALL/UPDATE*****\e[0m\n" FEXBash -c '/home/steam/steamcmd/steamcmd.sh +@sSteamCmdForcePlatformType linux +@sSteamCmdForcePlatformBitness 64 +force_install_dir "/palworld" +login anonymous +app_update 2394010 validate +quit' fi STARTCOMMAND=("./PalServer.sh") if ! fileExists "${STARTCOMMAND[0]}"; then echo "Try restarting with UPDATE_ON_BOOT=true" exit 1 fi isReadable "${STARTCOMMAND[0]}" || exit isExecutable "${STARTCOMMAND[0]}" || exit if [ -n "${PORT}" ]; then STARTCOMMAND+=("-port=${PORT}") fi if [ -n "${QUERY_PORT}" ]; then STARTCOMMAND+=("-queryport=${QUERY_PORT}") fi if [ "${COMMUNITY,,}" = true ]; then STARTCOMMAND+=("EpicApp=PalServer") fi if [ "${MULTITHREADING,,}" = true ]; then STARTCOMMAND+=("-useperfthreads" "-NoAsyncLoadingThread" "-UseMultithreadForDS") fi printf "\e[0;32m*****CHECKING FOR EXISTING CONFIG*****\e[0m\n" # shellcheck disable=SC2143 if [ ! "$(grep -s '[^[:space:]]' /palworld/Pal/Saved/Config/LinuxServer/PalWorldSettings.ini)" ]; then printf "\e[0;32m*****GENERATING CONFIG*****\e[0m\n" # Server will generate all ini files after first run. FEXBash -c 'timeout --preserve-status 15s ./PalServer.sh 1> /dev/null' # Wait for shutdown sleep 5 cp /palworld/DefaultPalWorldSettings.ini /palworld/Pal/Saved/Config/LinuxServer/PalWorldSettings.ini fi fileExists "/palworld/Pal/Saved/Config/LinuxServer/PalWorldSettings.ini" || exit isWritable "/palworld/Pal/Saved/Config/LinuxServer/PalWorldSettings.ini" || exit escape_sed() { printf '%s\n' "$1" | sed -e 's:[][\/.^$*]:\\&:g' } if [ -n "${SERVER_NAME}" ]; then SERVER_NAME=$(escape_sed "$SERVER_NAME" | sed -e 's/^"\(.*\)"$/\1/' -e "s/^'\(.*\)'$/\1/") echo "SERVER_NAME=${SERVER_NAME}" sed -E -i "s/ServerName=\"[^\"]*\"/ServerName=\"$SERVER_NAME\"/" /palworld/Pal/Saved/Config/LinuxServer/PalWorldSettings.ini fi if [ -n "${SERVER_DESCRIPTION}" ]; then SERVER_DESCRIPTION=$(escape_sed "$SERVER_DESCRIPTION" | sed -e 's/^"\(.*\)"$/\1/' -e "s/^'\(.*\)'$/\1/") echo "SERVER_DESCRIPTION=${SERVER_DESCRIPTION}" sed -E -i "s/ServerDescription=\"[^\"]*\"/ServerDescription=\"$SERVER_DESCRIPTION\"/" /palworld/Pal/Saved/Config/LinuxServer/PalWorldSettings.ini fi if [ -n "${SERVER_PASSWORD}" ]; then SERVER_PASSWORD=$(sed -e 's/^"\(.*\)"$/\1/' -e "s/^'\(.*\)'$/\1/" <<< "$SERVER_PASSWORD") echo "SERVER_PASSWORD=${SERVER_PASSWORD}" sed -E -i "s/ServerPassword=\"[^\"]*\"/ServerPassword=\"$SERVER_PASSWORD\"/" /palworld/Pal/Saved/Config/LinuxServer/PalWorldSettings.ini fi if [ -n "${ADMIN_PASSWORD}" ]; then ADMIN_PASSWORD=$(sed -e 's/^"\(.*\)"$/\1/' -e "s/^'\(.*\)'$/\1/" <<< "$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 echo "PLAYERS=${PLAYERS}" sed -E -i "s/ServerPlayerMaxNum=[0-9]*/ServerPlayerMaxNum=$PLAYERS/" /palworld/Pal/Saved/Config/LinuxServer/PalWorldSettings.ini fi if [ -n "${PUBLIC_IP}" ]; then PUBLIC_IP=$(sed -e 's/^"\(.*\)"$/\1/' -e "s/^'\(.*\)'$/\1/" <<< "$PUBLIC_IP") echo "PUBLIC_IP=${PUBLIC_IP}" sed -E -i "s/PublicIP=\"[^\"]*\"/PublicIP=\"$PUBLIC_IP\"/" /palworld/Pal/Saved/Config/LinuxServer/PalWorldSettings.ini fi if [ -n "${PUBLIC_PORT}" ]; then echo "PUBLIC_PORT=${PUBLIC_PORT}" sed -E -i "s/PublicPort=[0-9]*/PublicPort=$PUBLIC_PORT/" /palworld/Pal/Saved/Config/LinuxServer/PalWorldSettings.ini fi if [ -n "${DIFFICULTY}" ]; then echo "DIFFICULTY=$DIFFICULTY" sed -E -i "s/Difficulty=[a-zA-Z]*/Difficulty=$DIFFICULTY/" /palworld/Pal/Saved/Config/LinuxServer/PalWorldSettings.ini fi if [ -n "${DAYTIME_SPEEDRATE}" ]; then echo "DAYTIME_SPEEDRATE=$DAYTIME_SPEEDRATE" sed -E -i "s/DayTimeSpeedRate=[+-]?([0-9]*[.])?[0-9]+/DayTimeSpeedRate=$DAYTIME_SPEEDRATE/" /palworld/Pal/Saved/Config/LinuxServer/PalWorldSettings.ini fi if [ -n "${NIGHTTIME_SPEEDRATE}" ]; then echo "NIGHTTIME_SPEEDRATE=$NIGHTTIME_SPEEDRATE" sed -E -i "s/NightTimeSpeedRate=[+-]?([0-9]*[.])?[0-9]+/NightTimeSpeedRate=$NIGHTTIME_SPEEDRATE/" /palworld/Pal/Saved/Config/LinuxServer/PalWorldSettings.ini fi if [ -n "${EXP_RATE}" ]; then echo "EXP_RATE=$EXP_RATE" sed -E -i "s/ExpRate=[+-]?([0-9]*[.])?[0-9]+/ExpRate=$EXP_RATE/" /palworld/Pal/Saved/Config/LinuxServer/PalWorldSettings.ini fi if [ -n "${PAL_CAPTURE_RATE}" ]; then echo "PAL_CAPTURE_RATE=$PAL_CAPTURE_RATE" sed -E -i "s/PalCaptureRate=[+-]?([0-9]*[.])?[0-9]+/PalCaptureRate=$PAL_CAPTURE_RATE/" /palworld/Pal/Saved/Config/LinuxServer/PalWorldSettings.ini fi if [ -n "${PAL_SPAWN_NUM_RATE}" ]; then echo "PAL_SPAWN_NUM_RATE=$PAL_SPAWN_NUM_RATE" sed -E -i "s/PalSpawnNumRate=[+-]?([0-9]*[.])?[0-9]+/PalSpawnNumRate=$PAL_SPAWN_NUM_RATE/" /palworld/Pal/Saved/Config/LinuxServer/PalWorldSettings.ini fi if [ -n "${PAL_DAMAGE_RATE_ATTACK}" ]; then echo "PAL_DAMAGE_RATE_ATTACK=$PAL_DAMAGE_RATE_ATTACK" sed -E -i "s/PalDamageRateAttack=[+-]?([0-9]*[.])?[0-9]+/PalDamageRateAttack=$PAL_DAMAGE_RATE_ATTACK/" /palworld/Pal/Saved/Config/LinuxServer/PalWorldSettings.ini fi if [ -n "${PAL_DAMAGE_RATE_DEFENSE}" ]; then echo "PAL_DAMAGE_RATE_DEFENSE=$PAL_DAMAGE_RATE_DEFENSE" sed -E -i "s/PalDamageRateDefense=[+-]?([0-9]*[.])?[0-9]+/PalDamageRateDefense=$PAL_DAMAGE_RATE_DEFENSE/" /palworld/Pal/Saved/Config/LinuxServer/PalWorldSettings.ini fi if [ -n "${PLAYER_DAMAGE_RATE_ATTACK}" ]; then echo "PLAYER_DAMAGE_RATE_ATTACK=$PLAYER_DAMAGE_RATE_ATTACK" sed -E -i "s/PlayerDamageRateAttack=[+-]?([0-9]*[.])?[0-9]+/PlayerDamageRateAttack=$PLAYER_DAMAGE_RATE_ATTACK/" /palworld/Pal/Saved/Config/LinuxServer/PalWorldSettings.ini fi if [ -n "${PLAYER_DAMAGE_RATE_DEFENSE}" ]; then echo "PLAYER_DAMAGE_RATE_DEFENSE=$PLAYER_DAMAGE_RATE_DEFENSE" sed -E -i "s/PlayerDamageRateDefense=[+-]?([0-9]*[.])?[0-9]+/PlayerDamageRateDefense=$PLAYER_DAMAGE_RATE_DEFENSE/" /palworld/Pal/Saved/Config/LinuxServer/PalWorldSettings.ini fi if [ -n "${PLAYER_STOMACH_DECREASE_RATE}" ]; then echo "PLAYER_STOMACH_DECREASE_RATE=$PLAYER_STOMACH_DECREASE_RATE" sed -E -i "s/PlayerStomachDecreaceRate=[+-]?([0-9]*[.])?[0-9]+/PlayerStomachDecreaceRate=$PLAYER_STOMACH_DECREASE_RATE/" /palworld/Pal/Saved/Config/LinuxServer/PalWorldSettings.ini fi if [ -n "${PLAYER_STAMINA_DECREASE_RATE}" ]; then echo "PLAYER_STAMINA_DECREASE_RATE=$PLAYER_STAMINA_DECREASE_RATE" sed -E -i "s/PlayerStaminaDecreaceRate=[+-]?([0-9]*[.])?[0-9]+/PlayerStaminaDecreaceRate=$PLAYER_STAMINA_DECREASE_RATE/" /palworld/Pal/Saved/Config/LinuxServer/PalWorldSettings.ini fi if [ -n "${PLAYER_AUTO_HP_REGEN_RATE}" ]; then echo "PLAYER_AUTO_HP_REGEN_RATE=$PLAYER_AUTO_HP_REGEN_RATE" sed -E -i "s/PlayerAutoHPRegeneRate=[+-]?([0-9]*[.])?[0-9]+/PlayerAutoHPRegeneRate=$PLAYER_AUTO_HP_REGEN_RATE/" /palworld/Pal/Saved/Config/LinuxServer/PalWorldSettings.ini fi if [ -n "${PLAYER_AUTO_HP_REGEN_RATE_IN_SLEEP}" ]; then echo "PLAYER_AUTO_HP_REGEN_RATE_IN_SLEEP=$PLAYER_AUTO_HP_REGEN_RATE_IN_SLEEP" sed -E -i "s/PlayerAutoHpRegeneRateInSleep=[+-]?([0-9]*[.])?[0-9]+/PlayerAutoHpRegeneRateInSleep=$PLAYER_AUTO_HP_REGEN_RATE_IN_SLEEP/" /palworld/Pal/Saved/Config/LinuxServer/PalWorldSettings.ini fi if [ -n "${PAL_STOMACH_DECREASE_RATE}" ]; then echo "PAL_STOMACH_DECREASE_RATE=$PAL_STOMACH_DECREASE_RATE" sed -E -i "s/PalStomachDecreaceRate=[+-]?([0-9]*[.])?[0-9]+/PalStomachDecreaceRate=$PAL_STOMACH_DECREASE_RATE/" /palworld/Pal/Saved/Config/LinuxServer/PalWorldSettings.ini fi if [ -n "${PAL_STAMINA_DECREASE_RATE}" ]; then echo "PAL_STAMINA_DECREASE_RATE=$PAL_STAMINA_DECREASE_RATE" sed -E -i "s/PalStaminaDecreaceRate=[+-]?([0-9]*[.])?[0-9]+/PalStaminaDecreaceRate=$PAL_STAMINA_DECREASE_RATE/" /palworld/Pal/Saved/Config/LinuxServer/PalWorldSettings.ini fi if [ -n "${PAL_AUTO_HP_REGEN_RATE}" ]; then echo "PAL_AUTO_HP_REGEN_RATE=$PAL_AUTO_HP_REGEN_RATE" sed -E -i "s/PalAutoHPRegeneRate=[+-]?([0-9]*[.])?[0-9]+/PalAutoHPRegeneRate=$PAL_AUTO_HP_REGEN_RATE/" /palworld/Pal/Saved/Config/LinuxServer/PalWorldSettings.ini fi if [ -n "${PAL_AUTO_HP_REGEN_RATE_IN_SLEEP}" ]; then echo "PAL_AUTO_HP_REGEN_RATE_IN_SLEEP=$PAL_AUTO_HP_REGEN_RATE_IN_SLEEP" sed -E -i "s/PalAutoHpRegeneRateInSleep=[+-]?([0-9]*[.])?[0-9]+/PalAutoHpRegeneRateInSleep=$PAL_AUTO_HP_REGEN_RATE_IN_SLEEP/" /palworld/Pal/Saved/Config/LinuxServer/PalWorldSettings.ini fi if [ -n "${BUILD_OBJECT_DAMAGE_RATE}" ]; then echo "BUILD_OBJECT_DAMAGE_RATE=$BUILD_OBJECT_DAMAGE_RATE" sed -E -i "s/BuildObjectDamageRate=[+-]?([0-9]*[.])?[0-9]+/BuildObjectDamageRate=$BUILD_OBJECT_DAMAGE_RATE/" /palworld/Pal/Saved/Config/LinuxServer/PalWorldSettings.ini fi if [ -n "${BUILD_OBJECT_DETERIORATION_DAMAGE_RATE}" ]; then echo "BUILD_OBJECT_DETERIORATION_DAMAGE_RATE=$BUILD_OBJECT_DETERIORATION_DAMAGE_RATE" sed -E -i "s/BuildObjectDeteriorationDamageRate=[+-]?([0-9]*[.])?[0-9]+/BuildObjectDeteriorationDamageRate=$BUILD_OBJECT_DETERIORATION_DAMAGE_RATE/" /palworld/Pal/Saved/Config/LinuxServer/PalWorldSettings.ini fi if [ -n "${COLLECTION_DROP_RATE}" ]; then echo "COLLECTION_DROP_RATE=$COLLECTION_DROP_RATE" sed -E -i "s/CollectionDropRate=[+-]?([0-9]*[.])?[0-9]+/CollectionDropRate=$COLLECTION_DROP_RATE/" /palworld/Pal/Saved/Config/LinuxServer/PalWorldSettings.ini fi if [ -n "${COLLECTION_OBJECT_HP_RATE}" ]; then echo "COLLECTION_OBJECT_HP_RATE=$COLLECTION_OBJECT_HP_RATE" sed -E -i "s/CollectionObjectHpRate=[+-]?([0-9]*[.])?[0-9]+/CollectionObjectHpRate=$COLLECTION_OBJECT_HP_RATE/" /palworld/Pal/Saved/Config/LinuxServer/PalWorldSettings.ini fi if [ -n "${COLLECTION_OBJECT_RESPAWN_SPEED_RATE}" ]; then echo "COLLECTION_OBJECT_RESPAWN_SPEED_RATE=$COLLECTION_OBJECT_RESPAWN_SPEED_RATE" sed -E -i "s/CollectionObjectRespawnSpeedRate=[+-]?([0-9]*[.])?[0-9]+/CollectionObjectRespawnSpeedRate=$COLLECTION_OBJECT_RESPAWN_SPEED_RATE/" /palworld/Pal/Saved/Config/LinuxServer/PalWorldSettings.ini fi if [ -n "${ENEMY_DROP_ITEM_RATE}" ]; then echo "ENEMY_DROP_ITEM_RATE=$ENEMY_DROP_ITEM_RATE" sed -E -i "s/EnemyDropItemRate=[+-]?([0-9]*[.])?[0-9]+/EnemyDropItemRate=$ENEMY_DROP_ITEM_RATE/" /palworld/Pal/Saved/Config/LinuxServer/PalWorldSettings.ini fi if [ -n "${DEATH_PENALTY}" ]; then echo "DEATH_PENALTY=$DEATH_PENALTY" sed -E -i "s/DeathPenalty=[a-zA-Z]*/DeathPenalty=$DEATH_PENALTY/" /palworld/Pal/Saved/Config/LinuxServer/PalWorldSettings.ini fi if [ -n "${ENABLE_PLAYER_TO_PLAYER_DAMAGE}" ]; then echo "ENABLE_PLAYER_TO_PLAYER_DAMAGE=$ENABLE_PLAYER_TO_PLAYER_DAMAGE" sed -E -i "s/bEnablePlayerToPlayerDamage=[a-zA-Z]*/bEnablePlayerToPlayerDamage=$ENABLE_PLAYER_TO_PLAYER_DAMAGE/" /palworld/Pal/Saved/Config/LinuxServer/PalWorldSettings.ini fi if [ -n "${ENABLE_FRIENDLY_FIRE}" ]; then echo "ENABLE_FRIENDLY_FIRE=$ENABLE_FRIENDLY_FIRE" sed -E -i "s/bEnableFriendlyFire=[a-zA-Z]*/bEnableFriendlyFire=$ENABLE_FRIENDLY_FIRE/" /palworld/Pal/Saved/Config/LinuxServer/PalWorldSettings.ini fi if [ -n "${ENABLE_INVADER_ENEMY}" ]; then echo "ENABLE_INVADER_ENEMY=$ENABLE_INVADER_ENEMY" sed -E -i "s/bEnableInvaderEnemy=[a-zA-Z]*/bEnableInvaderEnemy=$ENABLE_INVADER_ENEMY/" /palworld/Pal/Saved/Config/LinuxServer/PalWorldSettings.ini fi if [ -n "${ACTIVE_UNKO}" ]; then echo "ACTIVE_UNKO=$ACTIVE_UNKO" sed -E -i "s/bActiveUNKO=[a-zA-Z]*/bActiveUNKO=$ACTIVE_UNKO/" /palworld/Pal/Saved/Config/LinuxServer/PalWorldSettings.ini fi if [ -n "${ENABLE_AIM_ASSIST_PAD}" ]; then echo "ENABLE_AIM_ASSIST_PAD=$ENABLE_AIM_ASSIST_PAD" sed -E -i "s/bEnableAimAssistPad=[a-zA-Z]*/bEnableAimAssistPad=$ENABLE_AIM_ASSIST_PAD/" /palworld/Pal/Saved/Config/LinuxServer/PalWorldSettings.ini fi if [ -n "${ENABLE_AIM_ASSIST_KEYBOARD}" ]; then echo "ENABLE_AIM_ASSIST_KEYBOARD=$ENABLE_AIM_ASSIST_KEYBOARD" sed -E -i "s/bEnableAimAssistKeyboard=[a-zA-Z]*/bEnableAimAssistKeyboard=$ENABLE_AIM_ASSIST_KEYBOARD/" /palworld/Pal/Saved/Config/LinuxServer/PalWorldSettings.ini fi if [ -n "${DROP_ITEM_MAX_NUM}" ]; then echo "DROP_ITEM_MAX_NUM=$DROP_ITEM_MAX_NUM" sed -E -i "s/DropItemMaxNum=[0-9]*/DropItemMaxNum=$DROP_ITEM_MAX_NUM/" /palworld/Pal/Saved/Config/LinuxServer/PalWorldSettings.ini fi if [ -n "${DROP_ITEM_MAX_NUM_UNKO}" ]; then echo "DROP_ITEM_MAX_NUM_UNKO=$DROP_ITEM_MAX_NUM_UNKO" sed -E -i "s/DropItemMaxNum_UNKO=[0-9]*/DropItemMaxNum_UNKO=$DROP_ITEM_MAX_NUM_UNKO/" /palworld/Pal/Saved/Config/LinuxServer/PalWorldSettings.ini fi if [ -n "${BASE_CAMP_MAX_NUM}" ]; then echo "BASE_CAMP_MAX_NUM=$BASE_CAMP_MAX_NUM" sed -E -i "s/BaseCampMaxNum=[0-9]*/BaseCampMaxNum=$BASE_CAMP_MAX_NUM/" /palworld/Pal/Saved/Config/LinuxServer/PalWorldSettings.ini fi if [ -n "${BASE_CAMP_WORKER_MAXNUM}" ]; then echo "BASE_CAMP_WORKER_MAXNUM=$BASE_CAMP_WORKER_MAXNUM" sed -E -i "s/BaseCampWorkerMaxNum=[0-9]*/BaseCampWorkerMaxNum=$BASE_CAMP_WORKER_MAXNUM/" /palworld/Pal/Saved/Config/LinuxServer/PalWorldSettings.ini fi if [ -n "${DROP_ITEM_ALIVE_MAX_HOURS}" ]; then echo "DROP_ITEM_ALIVE_MAX_HOURS=$DROP_ITEM_ALIVE_MAX_HOURS" sed -E -i "s/DropItemAliveMaxHours=[+-]?([0-9]*[.])?[0-9]+/DropItemAliveMaxHours=$DROP_ITEM_ALIVE_MAX_HOURS/" /palworld/Pal/Saved/Config/LinuxServer/PalWorldSettings.ini fi if [ -n "${AUTO_RESET_GUILD_NO_ONLINE_PLAYERS}" ]; then echo "AUTO_RESET_GUILD_NO_ONLINE_PLAYERS=$AUTO_RESET_GUILD_NO_ONLINE_PLAYERS" sed -E -i "s/bAutoResetGuildNoOnlinePlayers=[a-zA-Z]*/bAutoResetGuildNoOnlinePlayers=$AUTO_RESET_GUILD_NO_ONLINE_PLAYERS/" /palworld/Pal/Saved/Config/LinuxServer/PalWorldSettings.ini fi if [ -n "${AUTO_RESET_GUILD_TIME_NO_ONLINE_PLAYERS}" ]; then echo "AUTO_RESET_GUILD_TIME_NO_ONLINE_PLAYERS=$AUTO_RESET_GUILD_TIME_NO_ONLINE_PLAYERS" sed -E -i "s/AutoResetGuildTimeNoOnlinePlayers=[+-]?([0-9]*[.])?[0-9]+/AutoResetGuildTimeNoOnlinePlayers=$AUTO_RESET_GUILD_TIME_NO_ONLINE_PLAYERS/" /palworld/Pal/Saved/Config/LinuxServer/PalWorldSettings.ini fi if [ -n "${GUILD_PLAYER_MAX_NUM}" ]; then echo "GUILD_PLAYER_MAX_NUM=$GUILD_PLAYER_MAX_NUM" sed -E -i "s/GuildPlayerMaxNum=[0-9]*/GuildPlayerMaxNum=$GUILD_PLAYER_MAX_NUM/" /palworld/Pal/Saved/Config/LinuxServer/PalWorldSettings.ini fi if [ -n "${PAL_EGG_DEFAULT_HATCHING_TIME}" ]; then echo "PAL_EGG_DEFAULT_HATCHING_TIME=$PAL_EGG_DEFAULT_HATCHING_TIME" sed -E -i "s/PalEggDefaultHatchingTime=[+-]?([0-9]*[.])?[0-9]+/PalEggDefaultHatchingTime=$PAL_EGG_DEFAULT_HATCHING_TIME/" /palworld/Pal/Saved/Config/LinuxServer/PalWorldSettings.ini fi if [ -n "${WORK_SPEED_RATE}" ]; then echo "WORK_SPEED_RATE=$WORK_SPEED_RATE" sed -E -i "s/WorkSpeedRate=[+-]?([0-9]*[.])?[0-9]+/WorkSpeedRate=$WORK_SPEED_RATE/" /palworld/Pal/Saved/Config/LinuxServer/PalWorldSettings.ini fi if [ -n "${IS_MULTIPLAY}" ]; then echo "IS_MULTIPLAY=$IS_MULTIPLAY" sed -E -i "s/bIsMultiplay=[a-zA-Z]*/bIsMultiplay=$IS_MULTIPLAY/" /palworld/Pal/Saved/Config/LinuxServer/PalWorldSettings.ini fi if [ -n "${IS_PVP}" ]; then echo "IS_PVP=$IS_PVP" sed -E -i "s/bIsPvP=[a-zA-Z]*/bIsPvP=$IS_PVP/" /palworld/Pal/Saved/Config/LinuxServer/PalWorldSettings.ini fi if [ -n "${CAN_PICKUP_OTHER_GUILD_DEATH_PENALTY_DROP}" ]; then echo "CAN_PICKUP_OTHER_GUILD_DEATH_PENALTY_DROP=$CAN_PICKUP_OTHER_GUILD_DEATH_PENALTY_DROP" sed -E -i "s/bCanPickupOtherGuildDeathPenaltyDrop=[a-zA-Z]*/bCanPickupOtherGuildDeathPenaltyDrop=$CAN_PICKUP_OTHER_GUILD_DEATH_PENALTY_DROP/" /palworld/Pal/Saved/Config/LinuxServer/PalWorldSettings.ini fi if [ -n "${ENABLE_NON_LOGIN_PENALTY}" ]; then echo "ENABLE_NON_LOGIN_PENALTY=$ENABLE_NON_LOGIN_PENALTY" sed -E -i "s/bEnableNonLoginPenalty=[a-zA-Z]*/bEnableNonLoginPenalty=$ENABLE_NON_LOGIN_PENALTY/" /palworld/Pal/Saved/Config/LinuxServer/PalWorldSettings.ini fi if [ -n "${ENABLE_FAST_TRAVEL}" ]; then echo "ENABLE_FAST_TRAVEL=$ENABLE_FAST_TRAVEL" sed -E -i "s/bEnableFastTravel=[a-zA-Z]*/bEnableFastTravel=$ENABLE_FAST_TRAVEL/" /palworld/Pal/Saved/Config/LinuxServer/PalWorldSettings.ini fi if [ -n "${IS_START_LOCATION_SELECT_BY_MAP}" ]; then echo "IS_START_LOCATION_SELECT_BY_MAP=$IS_START_LOCATION_SELECT_BY_MAP" sed -E -i "s/bIsStartLocationSelectByMap=[a-zA-Z]*/bIsStartLocationSelectByMap=$IS_START_LOCATION_SELECT_BY_MAP/" /palworld/Pal/Saved/Config/LinuxServer/PalWorldSettings.ini fi if [ -n "${EXIST_PLAYER_AFTER_LOGOUT}" ]; then echo "EXIST_PLAYER_AFTER_LOGOUT=$EXIST_PLAYER_AFTER_LOGOUT" sed -E -i "s/bExistPlayerAfterLogout=[a-zA-Z]*/bExistPlayerAfterLogout=$EXIST_PLAYER_AFTER_LOGOUT/" /palworld/Pal/Saved/Config/LinuxServer/PalWorldSettings.ini fi if [ -n "${ENABLE_DEFENSE_OTHER_GUILD_PLAYER}" ]; then echo "ENABLE_DEFENSE_OTHER_GUILD_PLAYER=$ENABLE_DEFENSE_OTHER_GUILD_PLAYER" sed -E -i "s/bEnableDefenseOtherGuildPlayer=[a-zA-Z]*/bEnableDefenseOtherGuildPlayer=$ENABLE_DEFENSE_OTHER_GUILD_PLAYER/" /palworld/Pal/Saved/Config/LinuxServer/PalWorldSettings.ini fi if [ -n "${COOP_PLAYER_MAX_NUM}" ]; then echo "COOP_PLAYER_MAX_NUM=$COOP_PLAYER_MAX_NUM" sed -E -i "s/CoopPlayerMaxNum=[0-9]*/CoopPlayerMaxNum=$COOP_PLAYER_MAX_NUM/" /palworld/Pal/Saved/Config/LinuxServer/PalWorldSettings.ini fi if [ -n "${REGION}" ]; then REGION=$(sed -e 's/^"\(.*\)"$/\1/' -e "s/^'\(.*\)'$/\1/" <<< "$REGION") echo "REGION=$REGION" sed -E -i "s/Region=\"[^\"]*\"/Region=\"$REGION\"/" /palworld/Pal/Saved/Config/LinuxServer/PalWorldSettings.ini fi if [ -n "${USEAUTH}" ]; then echo "USEAUTH=$USEAUTH" sed -E -i "s/bUseAuth=[a-zA-Z]*/bUseAuth=$USEAUTH/" /palworld/Pal/Saved/Config/LinuxServer/PalWorldSettings.ini fi if [ -n "${BAN_LIST_URL}" ]; then BAN_LIST_URL=$(sed -e 's/^"\(.*\)"$/\1/' -e "s/^'\(.*\)'$/\1/" <<< "$BAN_LIST_URL") echo "BAN_LIST_URL=$BAN_LIST_URL" sed -E -i "s~BanListURL=\"[^\"]*\"~BanListURL=\"$BAN_LIST_URL\"~" /palworld/Pal/Saved/Config/LinuxServer/PalWorldSettings.ini fi if [ -n "${RCON_ENABLED,,}" ]; then echo "RCON_ENABLED=${RCON_ENABLED,,}" sed -i "s/RCONEnabled=[a-zA-Z]*/RCONEnabled=$RCON_ENABLED/" /palworld/Pal/Saved/Config/LinuxServer/PalWorldSettings.ini fi if [ -n "${RCON_PORT}" ]; then echo "RCON_PORT=${RCON_PORT}" sed -i "s/RCONPort=[0-9]*/RCONPort=$RCON_PORT/" /palworld/Pal/Saved/Config/LinuxServer/PalWorldSettings.ini 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 if [ "${AUTO_UPDATE_ENABLED,,}" = true ] && [ "${UPDATE_ON_BOOT}" = true ]; then echo "AUTO_UPDATE_ENABLED=${AUTO_UPDATE_ENABLED,,}" echo "$AUTO_UPDATE_CRON_EXPRESSION bash /usr/local/bin/update" >> "/home/steam/server/crontab" fi if [ "${AUTO_REBOOT_ENABLED,,}" = true ] && [ "${RCON_ENABLED,,}" = true ]; then echo "AUTO_REBOOT_ENABLED=${AUTO_REBOOT_ENABLED,,}" echo "$AUTO_REBOOT_CRON_EXPRESSION bash /home/steam/server/auto_reboot.sh" >> "/home/steam/server/crontab" fi if { [ "${AUTO_UPDATE_ENABLED,,}" = true ] && [ "${UPDATE_ON_BOOT,,}" = true ]; } || [ "${BACKUP_ENABLED,,}" = true ] || \ [ "${AUTO_REBOOT_ENABLED,,}" = true ]; then supercronic "/home/steam/server/crontab" & fi # Configure RCON settings cat >/home/steam/server/rcon.yaml <<EOL default: address: 127.0.0.1:${RCON_PORT} password: "${ADMIN_PASSWORD}" EOL printf "\e[0;32m*****STARTING SERVER*****\e[0m\n" echo "${STARTCOMMAND[*]}" FEXBash -c "${STARTCOMMAND[*]}" exit 0 61, 97, 398 라인: FEX-Emu를 통해 ARM에서 문제없이 돌아가도록 함 docker-compose.yml version: "3.9" services: palworld: container_name: palworld restart: unless-stopped stop_grace_period: 30s build: context: . ports: - 8211:8211/udp - 27015:27015/udp env_file: - .env - settings.env environment: - PUID=1001 - PGID=1001 - MULTITHREADING=true - UPDATE_ON_BOOT=false - TZ=Asia/Seoul volumes: - ./server:/palworld networks: games: ipv4_address: 172.16.11.11 networks: games: name: games external: true Build 한 15~20분 정도 걸리는 듯.. docker compose up -d --build 이후부터는 --build 제거 후 사용. 다른 명령어는 이전 글 참고.
  • Docker로 Palworld 서버 열기

    2024-02-09 21:23:49 Docker로 Palworld 서버 열기 (ARM64) Ver. 2 ARM64에 올리는 방법은 위 글 참고. Palworld에서는 공식적으로 도커 이미지를 제공하지 않지만, 역시 누군가 만들어둔 이미지(GitHub)가 있어서 사용해 봤다. 업데이트도 매우 빠르고 각종 기능도 계속 추가되고 있다. 솔직히 GitHub와 Docker 사이트에 실행 방법이 다 나와있기 때문에 별로 설명할 건 없고, docker-compose.yml 파일 내용을 올리기 위해 작성하는 글이다. 리눅스에 도커가 설치되어 있다는 가정 하에 진행 이미지 다운로드 이 과정은 생략해도 어차피 나중에 자동으로 다운로드가 진행된다. docker pull thijsvanloef/palworld-server-docker 서버 실행 준비 docker-compose.yml 파일 작성 mkdir -p ~/docker/palworld cd ~/docker/palworld vi docker-compose.yml version: "3.9" services: palworld: container_name: palworld restart: unless-stopped stop_grace_period: 30s image: thijsvanloef/palworld-server-docker:latest ports: - 8211:8211/udp - 27015:27015/udp env_file: - .env - settings.env environment: - PUID=1000 - PGID=1000 - MULTITHREADING=true - UPDATE_ON_BOOT=true - TZ=Asia/Seoul volumes: - ./server:/palworld networks: games: ipv4_address: 172.16.11.11 networks: games: name: games external: true .env 파일에는 포트 번호, 서버명, 서버 설명, 패스워드 등의 내용이 들어있고, settings.env 파일에는 게임에 적용되는 설정들이 저장되어 있다. 서버 실행 docker compose up -d # 실행 docker logs -f palworld # 컨테이너 로그 확인 아래와 같은 로그가 뜨면 서버 실행 완료. 마지막에 [S_API FAIL] ...이라고 뜨는데, 상관없는지 제대로 돌아간다. *****STARTING SERVER***** ./PalServer.sh -port=8211 -queryport=27015 EpicApp=PalServer -useperfthreads -NoAsyncLoadingThread -UseMultithreadForDS time="2024-02-07T18:14:21+09:00" level=info msg="read crontab: /home/steam/server/crontab" ... Setting breakpad minidump AppID = 2394010 [S_API FAIL] Tried to access Steam interface SteamUser021 before SteamAPI_Init succeeded. [S_API FAIL] Tried to access Steam interface SteamFriends017 before SteamAPI_Init succeeded. [S_API FAIL] Tried to access Steam interface STEAMAPPS_INTERFACE_VERSION008 before SteamAPI_Init succeeded. [S_API FAIL] Tried to access Steam interface SteamNetworkingUtils004 before SteamAPI_Init succeeded. + 처음 실행하거나 Palworld 서버가 설치된 디렉토리를 삭제 또는 이동했다면 서버를 설치해야 하기 때문에 조금 오래 걸린다. 이때 서버를 설치하는 동안의 로그가 실시간으로 뜨지 않고 조금씩 모아져서 한 번에 뜨는 문제가 있기 때문에 특별한 에러가 없다면 멈춘 것이 아니니 기다리면 된다. 그 외 docker compose 명령어는 docker-compose.yml 파일이 있는 위치 또는 그 하위에서 실행해야 한다. docker exec -it palworld rcon-cli # rcon 연결 docker restart palworld # 재시작 docker compose down # 종료 docker pause palworld # 일시정지 docker unpause palworld # 일시정지 해제