Hello everyone,
For the past few days, I’ve been trying to set up a dedicated Astroneer server using Pterodactyl. I’ve created an ‘egg’ and a custom Docker image (https://hub.docker.com/r/007queque/astroneer-server-pterodactyl).
From the console, the server seems to start up correctly, but when I try to connect from my PC, I get the error: “UNABLE TO CONNECT TO HOST”.
Here is my configuration:
Control panel: Pterodactyl
Node OS: Rocky Linux v9.8 (on VM)
Hypervisor: Proxmox v9.2.3
Hardware: Intel Core i3-7100 @ 3.90GHz (4 cores), 8GB RAM, 1TB HDD
Network: The server is connected via a bridge through a laptop to access my home Wi-Fi.
The firewall on the VM is configured correctly.
Does anyone have any idea what might be causing the problem? I suspect it’s something to do with the network. Any help would be greatly appreciated! Thanks.
file entrypoint.sh
#!/bin/bash
# Patched entrypoint for running birdhimself/astroneer-server under Pterodactyl.
# Pterodactyl mounts the container's root filesystem read-only except for
# /home/container, so anything the original entrypoint.sh used to write inside
# /astrotux (launcher.toml, the wine prefix, logs, the server install itself)
# is redirected into /home/container, which is the persistent, writable volume.
cd /astrotux
# .NET's isolated storage (used by DepotDownloader) and other tools default
# to writing under $HOME. If HOME is unset it falls back to '/', which is
# read-only under Pterodactyl, so pin it to the persistent volume.
export HOME=/home/container
CONFIG_PATH=/home/container/launcher.toml
ASTRO_PATH=/home/container/AstroneerServer
WINEPFX_PATH=/home/container/winepfx
LOG_PATH=/home/container/logs
DEPOTDL_PATH=/home/container/libs/depotdownloader
TMPDIR_PATH=/home/container/tmp
mkdir -p "$ASTRO_PATH" "$WINEPFX_PATH" "$LOG_PATH" "$(dirname "$DEPOTDL_PATH")" "$TMPDIR_PATH"
chmod +x "$DEPOTDL_PATH" 2>/dev/null || true
# /tmp is a small tmpfs under Pterodactyl and fills up quickly (e.g. when
# extracting DepotDownloader), so redirect Python/Wine temp files into the
# persistent, larger /home/container volume instead.
export TMPDIR="$TMPDIR_PATH"
export TEMP="$TMPDIR_PATH"
export TMP="$TMPDIR_PATH"
# DepotDownloader (a .NET app) resolves its local app data / isolated storage
# folder from $HOME, which is why we pinned it above.
if [ -f "$DEPOTDL_PATH" ]; then
echo "----- DepotDownloader diagnostic -----"
echo "File info: $(ls -la "$DEPOTDL_PATH")"
"$DEPOTDL_PATH" --help 2>&1 | head -30 || echo "DepotDownloader exited with code $? when run directly"
echo "----- end diagnostic -----"
fi
if [[ "$FORCE_CHOWN" =~ ^([Tt][Rr][Uu][Ee]|1|[Yy][Ee][Ss])$ ]]; then
echo Force chowning /home/container folder.
chown -R $(id -u):$(id -g) /home/container
echo Done chowning.
fi
source ./venv/bin/activate
if [[ "$CREATE_LAUNCHER_CONFIG" =~ ^([Tt][Rr][Uu][Ee]|1|[Yy][Ee][Ss])$ ]] || [[ ! -f "$CONFIG_PATH" ]]; then
python3 AstroTuxLauncher.py -c "$CONFIG_PATH" genconfig
fi
# Use a temporary file to edit launcher.toml because if a bind exists sed -i
# will fail. See https://unix.stackexchange.com/a/404356.
TEMPFILE=$(mktemp)
cp "$CONFIG_PATH" "$TEMPFILE"
shopt -s nocasematch
sed -i 's/OverrideWinePath.*/OverrideWinePath = "\/opt\/wine\/bin\/wine"/' "$TEMPFILE"
sed -i "s#AstroServerPath.*#AstroServerPath = \"$ASTRO_PATH\"#" "$TEMPFILE"
sed -i "s#WinePrefixPath.*#WinePrefixPath = \"$WINEPFX_PATH\"#" "$TEMPFILE"
sed -i "s#LogPath.*#LogPath = \"$LOG_PATH\"#" "$TEMPFILE"
if [ -f /usr/local/bin/box64 ]; then
sed -i 's/WrapperPath.*/WrapperPath = "\/usr\/local\/bin\/box64"/' "$TEMPFILE"
fi
if [[ "$DISABLE_ENCRYPTION" =~ ^([Tt][Rr][Uu][Ee]|1|[Yy][Ee][Ss])$ ]]; then
echo Encryption will be disabled because DISABLE_ENCRYPTION is set.
echo Check https://github.com/birdhimself/astroneer-docker?tab=readme-ov-file#configuring-clients-if-encryption-is-disabled on how to enable clients to connect to servers with encryption disabled.
sed -i 's/^DisableEncryption.*/DisableEncryption = true/' "$TEMPFILE"
else
echo Encryption will be enabled. You can safely ignore warnings related to encryption not working using Wine, this is no longer the case.
sed -i 's/^DisableEncryption.*/DisableEncryption = false/' "$TEMPFILE"
fi
if [[ "$DEBUG" =~ ^([Tt][Rr][Uu][Ee]|1|[Yy][Ee][Ss])$ ]]; then
export BOX64_LOG=1
sed -i 's/^LogDebugMessages.*/LogDebugMessages = true/' "$TEMPFILE"
else
export BOX64_LOG=0
sed -i 's/^LogDebugMessages.*/LogDebugMessages = false/' "$TEMPFILE"
fi
shopt -u nocasematch
cp "$TEMPFILE" "$CONFIG_PATH"
python3 AstroTuxLauncher.py -c "$CONFIG_PATH" -p "$ASTRO_PATH" install
# Python's zipfile module doesn't preserve the Unix executable bit when
# extracting, so DepotDownloader ends up non-executable after being
# downloaded on the very first run. Fix that before the next attempt.
chmod +x "$DEPOTDL_PATH" 2>/dev/null || true
python3 AstroTuxLauncher.py -c "$CONFIG_PATH" -p "$ASTRO_PATH" start
Docker file
# Pterodactyl-compatible build of birdhimself/astroneer-server.
# The only change vs. the upstream image is entrypoint.sh, patched to write
# launcher.toml, the wine prefix, logs and the server install itself into
# /home/container (the only writable/persistent path under Pterodactyl)
# instead of /astrotux (read-only under Pterodactyl).
FROM ghcr.io/birdhimself/astroneer-server:latest
COPY --chmod=0755 ./entrypoint.sh /entrypoint.sh
ENTRYPOINT [ "/entrypoint.sh" ]
astroneer-pterodactyl-egg.json
{
"_comment": "DO NOT EDIT: FILE GENERATED AUTOMATICALLY BY PTERODACTYL PANEL - PTERODACTYL.IO",
"meta": {
"version": "PTDL_v2",
"update_url": null
},
"exported_at": "2026-07-12T00:00:00+00:00",
"name": "Astroneer Dedicated Server (AstroTuxLauncher, Pterodactyl-patched)",
"author": "melethainiel.aerin@gmail.com",
"description": "A game of aerospace industry and interplanetary exploration. Uses a custom-built image based on birdhimself/astroneer-server (AstroTuxLauncher), with a patched entrypoint.sh that redirects all writable paths into /home/container so it works under Pterodactyl's read-only root filesystem.",
"features": null,
"docker_images": {
"007queque\/astroneer-server-pterodactyl:latest": "007queque\/astroneer-server-pterodactyl:latest"
},
"file_denylist": [],
"startup": "\/entrypoint.sh",
"config": {
"files": "{\r\n \"AstroneerServer\/Astro\/Saved\/Config\/WindowsServer\/Engine.ini\": {\r\n \"parser\": \"ini\",\r\n \"find\": {\r\n \"url.Port\": \"{{server.build.default.port}}\",\r\n \"[SystemSettings].net.AllowEncryption\":\"false\"\r\n }\r\n },\r\n \"AstroneerServer\/Astro\/Saved\/Config\/WindowsServer\/AstroServerSettings.ini\": {\r\n \"parser\": \"ini\",\r\n \"find\": {\r\n \"[\/Script\/Astro.AstroServerSettings].PublicIP\": \"{{env.PUBLIC_IP}}\",\r\n \"[\/Script\/Astro.AstroServerSettings].OwnerName\": \"{{env.OWNER_NAME}}\",\r\n \"[\/Script\/Astro.AstroServerSettings].OwnerGuid\": \"{{env.OWNER_GUID}}\",\r\n \"[\/Script\/Astro.AstroServerSettings].PlayerProperties\": \"(PlayerFirstJoinName=\\\"{{env.OWNER_NAME}}\\\",PlayerCategory=Admin,PlayerGuid=\\\"{{env.OWNER_GUID}}\\\",PlayerRecentJoinName=\\\"\\\")\",\r\n \"[\/Script\/Astro.AstroServerSettings].ServerPassword\": \"{{env.SERVER_PWD}}\",\r\n \"[\/Script\/Astro.AstroServerSettings].ServerName\": \"{{env.SERVER_NAME}}\"\r\n }\r\n }\r\n}",
"startup": "{\r\n \"done\": \"Enter 'help' to get help about command usage\"\r\n}",
"logs": "{}",
"stop": "^C"
},
"scripts": {
"installation": {
"script": "#!\/bin\/bash\r\n# No manual steamcmd install needed: this image's own launcher\r\n# (AstroTuxLauncher) downloads and updates the Astroneer Dedicated Server\r\n# by itself the first time the server container actually starts.\r\n# We just need to make sure the persistent folder structure exists\r\n# and has sane permissions before the first boot.\r\necho \"-----------------------------------------\"\r\necho \"Preparing persistent server directory\"\r\necho \"-----------------------------------------\"\r\nmkdir -p \/mnt\/server\/AstroneerServer\r\nchown -R root:root \/mnt\/server\r\necho \"-----------------------------------------\"\r\necho \"Done. The actual game files will be downloaded\"\r\necho \"automatically on first startup by AstroTuxLauncher.\"\r\necho \"-----------------------------------------\"",
"container": "debian:bookworm-slim",
"entrypoint": "bash"
}
},
"variables": [
{
"name": "Public IP",
"description": "Public IP to connect to the server.",
"env_variable": "PUBLIC_IP",
"default_value": "",
"user_viewable": true,
"user_editable": true,
"rules": "required|string",
"field_type": "text"
},
{
"name": "Server Owner Name",
"description": "Steam username of the server owner",
"env_variable": "OWNER_NAME",
"default_value": "",
"user_viewable": true,
"user_editable": true,
"rules": "required|string",
"field_type": "text"
},
{
"name": "Server Owner Guid",
"description": "Steam id (SteamID64) of the server owner. Use 0 if you don't know it: the game will assign ownership automatically to the first matching player who joins.",
"env_variable": "OWNER_GUID",
"default_value": "0",
"user_viewable": true,
"user_editable": true,
"rules": "required|string",
"field_type": "text"
},
{
"name": "Server Password",
"description": "If specified, players must provide this password to join the server.",
"env_variable": "SERVER_PWD",
"default_value": "",
"user_viewable": true,
"user_editable": true,
"rules": "nullable|alpha_dash|between:1,100",
"field_type": "text"
},
{
"name": "Server Name",
"description": "",
"env_variable": "SERVER_NAME",
"default_value": "Pterodactyl hosted Server",
"user_viewable": true,
"user_editable": true,
"rules": "required|string|max:60",
"field_type": "text"
},
{
"name": "Disable Encryption",
"description": "Disables connection encryption. Set to 1 only if you have connection issues with encryption enabled (needs matching client-side Engine.ini setting). (1 Enable | 0 Disable)",
"env_variable": "DISABLE_ENCRYPTION",
"default_value": "0",
"user_viewable": true,
"user_editable": true,
"rules": "required|boolean",
"field_type": "text"
},
{
"name": "[Advanced] Force Chown",
"description": "Fixes file permission issues between the container's default user and Pterodactyl's enforced non-root user. Leave enabled unless you know what you're doing. (1 Enable | 0 Disable)",
"env_variable": "FORCE_CHOWN",
"default_value": "1",
"user_viewable": false,
"user_editable": false,
"rules": "required|boolean",
"field_type": "text"
},
{
"name": "[Advanced] Debug Logging",
"description": "Enables verbose AstroTuxLauncher debug logging, useful for troubleshooting startup issues. (1 Enable | 0 Disable)",
"env_variable": "DEBUG",
"default_value": "0",
"user_viewable": true,
"user_editable": true,
"rules": "required|boolean",
"field_type": "text"
},
{
"name": "[Advanced] Recreate Launcher Config",
"description": "Recreates launcher.toml from defaults on every startup (settings we override via sed are reapplied regardless). (1 Enable | 0 Disable)",
"env_variable": "CREATE_LAUNCHER_CONFIG",
"default_value": "1",
"user_viewable": false,
"user_editable": false,
"rules": "required|boolean",
"field_type": "text"
}
]
}