Tag - Linux

1~4/4
  • 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) Ver. 2

    2024-02-09 21:34:54 Palworld 서버를 24시간 열어둘 경우 생기는 문제 어제 위 글을 작성하고 또 무슨 기능이 생겼나 구경하려고 들어갔는데.. ARM 버전이 생겼다? 그것도 FEX-Emu를 사용하지 않는다?? 이게 되면 바로 갈아탈 마음에 바로 사용해 봤다. 실행 docker-compose.yml 파일 작성 후 docker compose up -d 실행 version: "3.9" services: palworld: container_name: palworld restart: unless-stopped stop_grace_period: 30s image: thijsvanloef/palworld-server-docker:latest-arm64 ports: - 8211:8211/udp - 27015:27015/udp env_file: - .env - settings.env environment: - PUID=1001 - PGID=1001 - 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 이 글에서 image 값 끝에 -arm64 추가한 것 외엔 차이가 없다. PUID, PGID는 클라우드로 옮기면서 변경한 것. 문제 발생 처음엔 잘 되는가 싶더니 컨테이너를 그냥 재시작만 했는데 에러가 났다. docker logs -f palworld로 확인한 결과 재시작을 할 때마다 정상적으로 돌아갈 때도 있고, 아래처럼 로그가 찍히면서 혼자 재시작을 하기도 한다. ... *****STARTING SERVER***** ./PalServer-arm64.sh -port=8211 -queryport=27015 EpicApp=PalServer -useperfthreads -NoAsyncLoadingThread -UseMultithreadForDS time="2024-02-08T20:20:05+09:00" level=info msg="read crontab: /home/steam/server/crontab" [S_API] SteamAPI_Init(): Loaded local 'steamclient.so' OK. Shutdown handler: initalize. Increasing per-process limit of core file size to infinity. - Existing per-process limit (soft=18446744073709551615, hard=18446744073709551615) is enough for us (need only 18446744073709551615) CAppInfoCacheReadFromDiskThread took 24 milliseconds to initialize Steam Service Error: Failed to get Steam Service Start function 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. free(): invalid next size (normal) Signal 6 caught. Malloc Size=262146 LargeMemoryPoolOffset=262162 Malloc Size=131160 LargeMemoryPoolOffset=393352 Malloc Size=131160 LargeMemoryPoolOffset=524536 LogPakFile: Display: Found Pak file ../../../Engine/Programs/CrashReportClient/Content/Paks/CrashReportClient.pak attempting to mount. LogPakFile: Display: Mounting pak file ../../../Engine/Programs/CrashReportClient/Content/Paks/CrashReportClient.pak. LogPakFile: Display: Mounted Pak file '../../../Engine/Programs/CrashReportClient/Content/Paks/CrashReportClient.pak', mount point: '../../../Engine/' LogICUInternationalization: ICU TimeZone Detection - Raw Offset: +9:00, Platform Override: '' LogInit: Build: ++UE5+Release-5.1-CL-0 LogInit: Engine Version: 5.1.1-0+++UE5+Release-5.1 LogInit: Compatible Engine Version: 5.1.0-0+++UE5+Release-5.1 LogInit: Net CL: 0 LogInit: OS: Debian GNU/Linux 11 (bullseye) (5.15.0-1052-realtime), CPU: Box64 on Neoverse-N1 @1000 MHz, GPU: UnknownVendor PCI-id: 108e-0010 LogInit: Compiled (64-bit): Dec 31 2023 20:12:22 LogInit: Compiled with Clang: 13.0.1 (https://github.com/llvm/llvm-project 75e33f71c2dae584b13a7d1186ae0a038ba98838) LogInit: Build Configuration: Shipping LogInit: Branch Name: ++UE5+Release-5.1 LogInit: Command Line: -Abslog="/palworld/Pal/Saved/Logs/Pal-CRC.log" -Unattended -ImplicitSend "/palworld/Pal/Saved/Crashes/crashinfo-Pal-pid-111-AE37D7ED12904D579713C0111B657EBB/" -unattended LogInit: Base Directory: /palworld/Engine/Binaries/Linux/ LogInit: Allocator: Mimalloc LogInit: Installed Engine Build: 1 LogInit: Presizing for max 100000 objects, including 0 objects not considered by GC, pre-allocating 0 bytes for permanent pool. LogInit: Object subsystem initialized LogConfig: Applying CVar settings from Section [ConsoleVariables] File [Engine] [2024.02.08-11.20.29:881][ 0]LogInit: Unix hardware info: [2024.02.08-11.20.29:881][ 0]LogInit: - we are the first instance of this executable [2024.02.08-11.20.29:881][ 0]LogInit: - this process' id (pid) is 167, parent process' id (ppid) is 111 [2024.02.08-11.20.29:882][ 0]LogInit: - we are not running under debugger [2024.02.08-11.20.29:882][ 0]LogInit: - machine network name is 'a4f09a0272ae' [2024.02.08-11.20.29:882][ 0]LogInit: - user name is 'steam' (steam) [2024.02.08-11.20.29:883][ 0]LogInit: - we're logged in locally [2024.02.08-11.20.29:883][ 0]LogInit: - we're running with rendering [2024.02.08-11.20.29:883][ 0]LogInit: - CPU: GenuineIntel 'Box64 on Neoverse-N1 @1000 MHz' (signature: 0x601) [2024.02.08-11.20.29:883][ 0]LogInit: - Number of physical cores available for the process: 4 [2024.02.08-11.20.29:883][ 0]LogInit: - Number of logical cores available for the process: 4 [2024.02.08-11.20.29:883][ 0]LogInit: - Cache line size: 64 [2024.02.08-11.20.29:883][ 0]LogInit: - GPU Brand Info: UnknownVendor PCI-id: 108e-0010 [2024.02.08-11.20.29:883][ 0]LogInit: - Memory allocator used: Mimalloc [2024.02.08-11.20.29:884][ 0]LogInit: - This binary is optimized with LTO: no, PGO: no, instrumented for PGO data collection: no [2024.02.08-11.20.29:884][ 0]LogInit: - This is an internal build. [2024.02.08-11.20.29:885][ 0]LogCore: Skipped benchmarking clocks because the engine is running in a standalone program mode - CLOCK_MONOTONIC will be used. [2024.02.08-11.20.29:885][ 0]LogInit: Unix-specific commandline switches: [2024.02.08-11.20.29:885][ 0]LogInit: -ansimalloc - use malloc()/free() from libc (useful for tools like valgrind and electric fence) [2024.02.08-11.20.29:885][ 0]LogInit: -jemalloc - use jemalloc for all memory allocation [2024.02.08-11.20.29:885][ 0]LogInit: -binnedmalloc - use binned malloc for all memory allocation [2024.02.08-11.20.29:885][ 0]LogInit: -filemapcachesize=NUMBER - set the size for case-sensitive file mapping cache [2024.02.08-11.20.29:885][ 0]LogInit: -useksm - uses kernel same-page mapping (KSM) for mapped memory (OFF) [2024.02.08-11.20.29:885][ 0]LogInit: -ksmmergeall - marks all mmap'd memory pages suitable for KSM (OFF) [2024.02.08-11.20.29:885][ 0]LogInit: -preloadmodulesymbols - Loads the main module symbols file into memory (OFF) [2024.02.08-11.20.29:885][ 0]LogInit: -sigdfl=SIGNAL - Allows a specific signal to be set to its default handler rather then ignoring the signal [2024.02.08-11.20.29:885][ 0]LogInit: -crashhandlerstacksize - Allows setting crash handler stack sizes (204800) [2024.02.08-11.20.29:885][ 0]LogInit: -noexclusivelockonwrite - disables marking files created by the engine as exclusive locked while the engine has them opened [2024.02.08-11.20.29:885][ 0]LogInit: -httpproxy=ADDRESS:PORT - redirects HTTP requests to a proxy (only supported if compiled with libcurl) [2024.02.08-11.20.29:886][ 0]LogInit: -reuseconn - allow libcurl to reuse HTTP connections (only matters if compiled with libcurl) [2024.02.08-11.20.29:886][ 0]LogInit: -virtmemkb=NUMBER - sets process virtual memory (address space) limit (overrides VirtualMemoryLimitInKB value from .ini) [2024.02.08-11.20.29:886][ 0]LogInit: - Physical RAM available (not considering process quota): 24 GB (23989 MB, 24564872 KB, 25154428928 bytes) [2024.02.08-11.20.29:886][ 0]LogInit: - VirtualMemoryAllocator pools will grow at scale 1.4 [2024.02.08-11.20.29:886][ 0]LogInit: - MemoryRangeDecommit() will be a no-op (re-run with -vmapoolevict to change) [2024.02.08-11.20.29:886][ 0]LogInit: - PageSize 4096 [2024.02.08-11.20.29:886][ 0]LogInit: - BinnedPageSize 65536 [2024.02.08-11.20.30:006][ 0]LogUObjectArray: 419 objects as part of root set at end of initial load. [2024.02.08-11.20.30:006][ 0]LogUObjectAllocator: 89056 out of 0 bytes used by permanent object pool. [2024.02.08-11.20.30:006][ 0]LogUObjectArray: CloseDisregardForGC: 0/0 objects in disregard for GC pool [2024.02.08-11.20.30:012][ 0]LogPaths: Warning: No paths for game localization data were specifed in the game configuration. [2024.02.08-11.20.30:013][ 0]LogInit: Using OS detected language (en-US-POSIX). [2024.02.08-11.20.30:013][ 0]LogInit: Using OS detected locale (en-US-POSIX). [2024.02.08-11.20.30:014][ 0]LogInit: Warning: No paths for engine localization data were specifed in the engine configuration. [2024.02.08-11.20.30:020][ 0]LogTextLocalizationManager: No localization for 'en-US-POSIX' exists, so 'en' will be used for the language. [2024.02.08-11.20.30:021][ 0]LogTextLocalizationManager: No localization for 'en-US-POSIX' exists, so 'en' will be used for the locale. [2024.02.08-11.20.30:026][ 0]LogInit: Using OS detected language (en-US-POSIX). [2024.02.08-11.20.30:026][ 0]LogInit: Using OS detected locale (en-US-POSIX). [2024.02.08-11.20.30:026][ 0]LogTextLocalizationManager: No localization for 'en-US-POSIX' exists, so 'en' will be used for the language. [2024.02.08-11.20.30:026][ 0]LogTextLocalizationManager: No localization for 'en-US-POSIX' exists, so 'en' will be used for the locale. [2024.02.08-11.20.30:043][ 0]LogPackageLocalizationCache: Processed 2 localized package path(s) for 1 prioritized culture(s) in 0.004851 seconds [2024.02.08-11.20.30:046][ 0]CrashReportCoreLog: CrashReportClientVersion=1.0 [2024.02.08-11.20.30:046][ 0]CrashReportCoreLog: CrashReportReceiver disabled [2024.02.08-11.20.30:047][ 0]CrashReportCoreLog: DataRouterUrl: https://o1291919.ingest.sentry.io/api/6513339/unreal/4a1a3921f51f4975b4cf8dd19022cb20/ [2024.02.08-11.20.30:080][ 0]CrashReportCoreLog: Initial state = Unknown UploadState value [2024.02.08-11.20.30:080][ 0]CrashReportCoreLog: Initial state = Unknown UploadState value [2024.02.08-11.20.30:096][ 0]LogCrashDebugHelper: DepotName: //UE5/Release-5.1 [2024.02.08-11.20.30:096][ 0]LogCrashDebugHelper: BuiltFromCL: 0 [2024.02.08-11.20.30:096][ 0]LogCrashDebugHelper: EngineVersion: 5.1.1-0+++UE5+Release-5.1 [2024.02.08-11.20.30:096][ 0]LogCrashDebugHelper: BuildVersion: ++UE5+Release-5.1-CL-0 [2024.02.08-11.20.31:081][ 0]CrashReportCoreLog: Got 3 pending files to upload from 'crashinfo-Pal-pid-111-AE37D7ED12904D579713C0111B657EBB' [2024.02.08-11.20.31:081][ 0]CrashReportCoreLog: State change from Ready to SendingFiles [2024.02.08-11.20.31:081][ 0]CrashReportCoreLog: CompressAndSendData have 3 pending files [2024.02.08-11.20.31:082][ 0]CrashReportCoreLog: CompressAndSendData compressing 152 bytes ('/palworld/Pal/Saved/Crashes/crashinfo-Pal-pid-111-AE37D7ED12904D579713C0111B657EBB/CrashReportClient.ini') [2024.02.08-11.20.31:083][ 0]CrashReportCoreLog: CompressAndSendData compressing 4518 bytes ('/palworld/Pal/Saved/Crashes/crashinfo-Pal-pid-111-AE37D7ED12904D579713C0111B657EBB/CrashContext.runtime-xml') [2024.02.08-11.20.31:083][ 0]CrashReportCoreLog: CompressAndSendData compressing 385 bytes ('/palworld/Pal/Saved/Crashes/crashinfo-Pal-pid-111-AE37D7ED12904D579713C0111B657EBB/Diagnostics.txt') [2024.02.08-11.20.31:206][ 0]LogInit: Using libcurl 7.83.1 [2024.02.08-11.20.31:206][ 0]LogInit: - built for Linux [2024.02.08-11.20.31:207][ 0]LogInit: - supports SSL with OpenSSL/1.1.1n [2024.02.08-11.20.31:207][ 0]LogInit: - supports HTTP deflate (compression) using libz 1.2.12 [2024.02.08-11.20.31:207][ 0]LogInit: - other features: [2024.02.08-11.20.31:207][ 0]LogInit: CURL_VERSION_SSL [2024.02.08-11.20.31:207][ 0]LogInit: CURL_VERSION_LIBZ [2024.02.08-11.20.31:207][ 0]LogInit: CURL_VERSION_IPV6 [2024.02.08-11.20.31:207][ 0]LogInit: CURL_VERSION_ASYNCHDNS [2024.02.08-11.20.31:208][ 0]LogInit: CURL_VERSION_LARGEFILE [2024.02.08-11.20.31:212][ 0]LogInit: CurlRequestOptions (configurable via config and command line): [2024.02.08-11.20.31:212][ 0]LogInit: - bVerifyPeer = false - Libcurl will NOT verify peer certificate [2024.02.08-11.20.31:212][ 0]LogInit: - bUseHttpProxy = false - Libcurl will NOT use HTTP proxy [2024.02.08-11.20.31:213][ 0]LogInit: - bDontReuseConnections = false - Libcurl will reuse connections [2024.02.08-11.20.31:213][ 0]LogInit: - MaxHostConnections = 16 - Libcurl will limit the number of connections to a host [2024.02.08-11.20.31:213][ 0]LogInit: - LocalHostAddr = Default [2024.02.08-11.20.31:213][ 0]LogInit: - BufferSize = 65536 [2024.02.08-11.20.31:221][ 0]CrashReportCoreLog: Sending HTTP request: https://o1291919.ingest.sentry.io/api/6513339/unreal/4a1a3921f51f4975b4cf8dd19022cb20/?AppID=CrashReporter&AppVersion=5.1.1-0%2B%2B%2BUE5%2BRelease-5.1&AppEnvironment=Release&UploadType=crashreports&UserID=-000003e9%7C%7C [2024.02.08-11.20.31:563][ 0]CrashReportCoreLog: OnProcessRequestComplete(), State=SendingFiles bSucceeded=1 [2024.02.08-11.20.31:563][ 0]CrashReportCoreLog: State change from SendingFiles to SendingFiles [2024.02.08-11.20.31:564][ 0]CrashReportCoreLog: All uploads done [2024.02.08-11.20.31:564][ 0]CrashReportCoreLog: State change from SendingFiles to Finished [2024.02.08-11.20.32:130][ 0]CrashReportCoreLog: Final state (Receiver) = Finished [2024.02.08-11.20.32:130][ 0]CrashReportCoreLog: Final state (Receiver) = Unknown UploadState value [2024.02.08-11.20.32:155][ 0]LogCore: Engine exit requested (reason: CrashReportClientApp RequestExit) [2024.02.08-11.20.32:155][ 0]LogExit: Preparing to exit. [2024.02.08-11.20.32:192][ 0]LogExit: Object subsystem successfully closed. [2024.02.08-11.20.32:196][ 0]LogModuleManager: Shutting down and abandoning module HTTP (12) [2024.02.08-11.20.32:233][ 0]LogModuleManager: Shutting down and abandoning module SSL (11) [2024.02.08-11.20.32:233][ 0]LogModuleManager: Shutting down and abandoning module CrashDebugHelper (8) [2024.02.08-11.20.32:237][ 0]LogModuleManager: Shutting down and abandoning module CoreUObject (6) [2024.02.08-11.20.32:237][ 0]LogModuleManager: Shutting down and abandoning module PakFile (4) [2024.02.08-11.20.32:238][ 0]LogModuleManager: Shutting down and abandoning module RSA (3) [2024.02.08-11.20.32:247][ 0]LogExit: Exiting. CommonUnixCrashHandler: Signal=6 Engine crash handling finished; re-raising signal 6 for the default handler. Good bye. 또는 18번 라인까지만 뜨면서 재시작이 안될 때도 있는데, 이건 그냥 멈춰버린 듯. 접속 시 타임아웃이 발생한다. 해결 (처음 올린 GitHub Issue) 그냥 원래 쓰던 빌드한 이미지로 쓸까 하다가 그냥 Issues에 한 번 올려나 봤다. # 그리고 답글이 달렸고, 해결됐다! 해결 방법은 environment: - BOX64_DYNAREC_STRONGMEM=3 - BOX64_DYNAREC_BIGBLOCK=0 - BOX64_DYNAREC_BLEEDING_EDGE=0 이런 환경변수를 추가하는 것으로, 최종 docker-compose.yml 파일은 아래와 같다. version: "3.9" services: palworld: container_name: palworld restart: unless-stopped stop_grace_period: 30s image: thijsvanloef/palworld-server-docker:latest-arm64 ports: - 8211:8211/udp - 27015:27015/udp env_file: - .env - settings.env environment: - PUID=1001 - PGID=1001 - MULTITHREADING=true - UPDATE_ON_BOOT=true - TZ=Asia/Seoul - BOX64_DYNAREC_STRONGMEM=3 - BOX64_DYNAREC_BIGBLOCK=0 - BOX64_DYNAREC_BLEEDING_EDGE=0 volumes: - ./server:/palworld networks: games: ipv4_address: 172.16.11.11 networks: games: name: games external: true FEX-Emu를 사용하지 않기 때문에 이 문제도 없으니 이제 나도 이 이미지의 모든 기능들을 귀찮게 새로 빌드하지 않고 쉽게 사용할 수 있게 됐다..!
  • 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 # 일시정지 해제