Creating a Custom Image
Build your own Docker image for an egg, when the official images do not fit.
Introduction
If none of the official images has what your server needs, build your own. This guide builds a small Debian-based image the same way the official images are built.
You need Docker on the build machine, either a node or your own computer.
How Wings Runs an Image
The image must work with how Wings runs containers:
- The server's files are at
/home/container. Wings mounts the server's directory there. Set the image's working directory to/home/container. - The server does not run as root. Wings runs the container as its
pterodactylsystem user, whose user ID differs between nodes. Do not rely on root, or on a specific user name or ID. - The startup command is in the
STARTUPvariable. Wings does not run the command itself. It passes it in theSTARTUPenvironment variable, with the egg's variables still written as{{NAME}}. The entrypoint must expand and run it. - The stop command
^Cgoes to the main process. If the entrypoint starts the server withexec, the server receives the signal and can shut down cleanly.
The Dockerfile
Create a directory for the image containing a Dockerfile:
FROM --platform=$TARGETOS/$TARGETARCH debian:bookworm-slim
RUN apt-get update \
&& apt-get install -y --no-install-recommends ca-certificates curl iproute2 tzdata \
&& rm -rf /var/lib/apt/lists/* \
&& useradd -m -d /home/container container
USER container
ENV USER=container HOME=/home/container
WORKDIR /home/container
COPY --chmod=755 ./entrypoint.sh /entrypoint.sh
CMD ["/bin/bash", "/entrypoint.sh"]Install everything the server needs to run in the RUN step. The container user and the USER and HOME variables give programs a normal home directory.
The Entrypoint
Next to the Dockerfile, create entrypoint.sh:
#!/bin/bash
cd /home/container || exit 1
# Use UTC unless Wings set a time zone.
export TZ=${TZ:-UTC}
# The container's own IP address, for servers that need to know it.
INTERNAL_IP=$(ip route get 1 | awk '{for (i = 1; i < NF; i++) if ($i == "src") { print $(i + 1); exit }}')
export INTERNAL_IP
# Turn {{NAME}} into ${NAME}, then fill in the values.
PARSED=$(echo "${STARTUP}" | sed -e 's/{{/${/g' -e 's/}}/}/g' | eval echo "$(cat -)")
# Show the command in the console, then replace this script with it.
printf "\033[1m\033[33mcontainer@pterodactyl~ \033[0m%s\n" "$PARSED"
exec env ${PARSED}Like the official images, the last line runs the command directly, not through a shell, so && and | do not work in the startup command. If an egg needs them, change the last line to exec bash -c "${PARSED}".
Building the Image
Build and tag the image. To use it on other nodes, push it to a registry such as the GitHub Container Registry:
docker build -t ghcr.io/your-name/my-image:latest .
docker push ghcr.io/your-name/my-image:latestThen add ghcr.io/your-name/my-image:latest to the egg's Docker Images.
To test on one node without a registry, build the image on that node and prefix its name with ~, such as ~my-image:latest. Wings then uses the local image instead of pulling it. See Local Images.
Last updated on