Unable to Find Script for Entrypoint with Compose

To preface, I am inexperienced with Docker, and I am struggling to resolve an issue after going through Docker’s documentation as well as combing through other forum posts. If this is an obvious problem to you, please understand that I didn’t come here without exhausting all other options I could think of.

Scenario

I am trying to containerize a GT: New Horizons server instance, which is logically a simple process:

  1. Download the server files
  2. Extract the files to a designated directory
  3. Create a volume for that directory that the host can manipulate as needed
  4. Run the start script provided by the server files as an entrypoint

Implementation

Dockerfile

To begin, I’ve written the following Dockerfile and stored it in a GitHub repository.

# Fetch GTNH Server & Extract
FROM alpine:latest as prepare

ARG GTNH_VERSION=2.6.1
ARG PORT=25565

WORKDIR /tmp

# Download Server
ADD https://downloads.gtnewhorizons.com/ServerPacks/GT_New_Horizons_${GTNH_VERSION}_Server_Java_17-21.zip gtnh.zip

# Extract Server Files
RUN unzip gtnh.zip -d gtnh && rm gtnh.zip

# Reconfigure Server Files
COPY --chmod=+x ["set_config.sh", "/tmp"]
RUN sh set_config.sh eula true gtnh/eula.txt # Agree to EULA
RUN sh set_config.sh server-port "${PORT}" gtnh/server.properties # Update Port
RUN sed -i '/^\s*java/!d' gtnh/startserver-java9.sh # Isolate Start Command

# Deploy Prepared Server
FROM ghcr.io/graalvm/jdk-community:21

COPY --from=prepare ["/tmp/gtnh", "/data"]

WORKDIR /data
VOLUME ["/data"]

EXPOSE ${PORT}

ENTRYPOINT exec sh startserver-java9.sh

To note, the GraalVM JDK instance does not come with an unzip command, so I opted to use a multi-stage build which prepares the server instance in an alpine container and then copies the prepared files into the graalvm container.

Compose File

Additionally, I have written the following Docker Compose file to build and run the instance:

services:
  gtnh-server:
    build:
      context: '/home/user/gtnh-docker' # Contains the Dockerfile and additional scripts
      dockerfile: 'Dockerfile'
      args:
        GTNH_VERSION: '2.6.1'
        PORT: '25566'
    volumes:
      - './data:/data'

My intention is to bind the /data directory in the container which holds the server files to a directory on the host.

Issue

After pruning the system via sudo docker system prune -a, I navigate to the directory containing the compose file and run sudo docker compose up. The build steps execute successfully up until the entrypoint which produces the following error.

[+] Running 2/1
:heavy_check_mark: Network 261_default Created 0.0s
:heavy_check_mark: Container 261-gtnh-server-1 Created 0.0s
Attaching to gtnh-server-1
gtnh-server-1 | sh: startserver-java9.sh: No such file or directory
gtnh-server-1 exited with code 127

However, if I build an instance from the Dockerfile with context via docker build, and then run it via docker run, the script runs as expected.

Finally, after trying to start the instance from either docker run or the compose file, the host directory that’s mounted to the /data volume remains empty.

Attempts & Validation

  • I ran a build with RUN ls /data just before the entrypoint to validate that the directory is populated; this printed out the server files as expected
  • I changed the file references from relative to absolute file paths and vice-versa with no luck
  • I enforced that all new lines were encoded as \n and not \r\n
  • I have tried switching between shell and exec forms for the ENTRYPOINT directive

System Information

I am running on a fresh Ubuntu 24 instance with a standard Docker installation.

Hi,

The problem is that you’re using bind mounts to mount /data to /data, when using bind mounts, then its the HOSTS /data that is mounted into /data, and if the hosts /data is empty, then its also going to be empty in the container.

If you want the containers /data to be replicated to the host, then the only way is via a volume: Volumes | Docker Docs

1 Like

Ah, that makes a lot more sense! I’ve updated my docker compose file to use your suggestions, and it’s working perfectly now.

services:
  gtnh-server:
    build:
      context: '/home/user/gtnh-docker'
      dockerfile: 'Dockerfile'
      args:
        GTNH_VERSION: '2.6.1'
        PORT: '25566'
    volumes:
      - 'data:/data'

volumes:
  data:
    driver: local
    driver_opts:
      type: none
      o: bind
      device: /srv/minecraft/gtnh/2.6.1/data

Thank you for your help!