Back to Templates
GameCP OfficialAdventure
Verified

Hytale

Hytale is a block-based sandbox game that blends creative building with RPG adventure. Explore procedurally generated worlds filled with unique biomes, dungeons, and creatures. Build anything from simple homes to grand castles, craft items, and battle monsters. Create custom content with built-in modding tools, host your own servers, and shape the experience with plugins and mods. Play solo or with friends in a world designed for both creation and exploration.

v1
1/14/2026

Startup Command

#!/bin/bashBash shell with full features

Default

Default startup command from Pterodactyl egg

Default
#!/bin/bash ################################################################################ # egg-hytale Entry Script # # This script handles: # - Hytale server download and updates # - Authentication with Hytale services # - Session token generation # - Launching the main server startup script # # DO NOT EDIT THIS FILE - it is managed by the Docker image. # To customize server settings, use the egg configuration variables in your # Pelican or Pterodactyl panel instead. ################################################################################ DOWNLOAD_URL="https://downloader.hytale.com/hytale-downloader.zip" DOWNLOAD_FILE="hytale-downloader.zip" DOWNLOADER="./hytale-downloader-linux-amd64" AUTH_CACHE_FILE=".hytale-auth-tokens.json" # Function to extract downloaded server files extract_server_files() { echo "Extracting server files..." SERVER_ZIP="server.zip" if [ -f "$SERVER_ZIP" ]; then echo "Found server archive: $SERVER_ZIP" # Extract to current directory unzip -o "$SERVER_ZIP" if [ $? -ne 0 ]; then echo "Error: Failed to extract $SERVER_ZIP" exit 1 fi echo "Extraction completed successfully." # Move contents from Server folder to current directory if [ -d "Server" ]; then echo "Moving server files from Server directory..." mv Server/* . rmdir Server echo "✓ Server files moved to root directory." fi # Clean up the zip file echo "Cleaning up archive file..." rm "$SERVER_ZIP" echo "✓ Archive removed." else echo "Error: Server archive not found at $SERVER_ZIP" exit 1 fi } # Function to check if cached tokens exist check_cached_tokens() { if [ -f "$AUTH_CACHE_FILE" ]; then # Check if jq is available if ! command -v jq &> /dev/null; then echo "Warning: jq not found, cannot use cached tokens" return 1 fi # Validate JSON format if ! jq empty "$AUTH_CACHE_FILE" 2>/dev/null; then echo "Warning: Invalid cached token file, removing..." rm "$AUTH_CACHE_FILE" return 1 fi echo "✓ Found cached authentication tokens" return 0 fi return 1 } # Function to load cached tokens (refresh_token + profile_uuid only) load_cached_tokens() { REFRESH_TOKEN=$(jq -r '.refresh_token' "$AUTH_CACHE_FILE") PROFILE_UUID=$(jq -r '.profile_uuid' "$AUTH_CACHE_FILE") # Validate required tokens are present if [ -z "$REFRESH_TOKEN" ] || [ "$REFRESH_TOKEN" = "null" ] || \ [ -z "$PROFILE_UUID" ] || [ "$PROFILE_UUID" = "null" ]; then echo "Error: Incomplete cached tokens, re-authenticating..." rm "$AUTH_CACHE_FILE" return 1 fi echo "✓ Loaded cached refresh token + profile UUID" return 0 } # Function to refresh access token using cached refresh token refresh_access_token() { echo "Refreshing access token..." TOKEN_RESPONSE=$(curl -s -X POST "https://oauth.accounts.hytale.com/oauth2/token" \ -H "Content-Type: application/x-www-form-urlencoded" \ -d "client_id=hytale-server" \ -d "grant_type=refresh_token" \ -d "refresh_token=$REFRESH_TOKEN") ERROR=$(echo "$TOKEN_RESPONSE" | jq -r '.error // empty') if [ -n "$ERROR" ]; then echo "Error: Failed to refresh access token: $ERROR" return 1 fi ACCESS_TOKEN=$(echo "$TOKEN_RESPONSE" | jq -r '.access_token') NEW_REFRESH_TOKEN=$(echo "$TOKEN_RESPONSE" | jq -r '.refresh_token // empty') if [ -z "$ACCESS_TOKEN" ] || [ "$ACCESS_TOKEN" = "null" ]; then echo "Error: No access token in refresh response" return 1 fi # Update refresh token if a new one was provided if [ -n "$NEW_REFRESH_TOKEN" ] && [ "$NEW_REFRESH_TOKEN" != "null" ]; then REFRESH_TOKEN="$NEW_REFRESH_TOKEN" fi echo "✓ Access token refreshed" return 0 } # Function to create a new game session create_game_session() { echo "Creating game server session..." SESSION_RESPONSE=$(curl -s -X POST "https://sessions.hytale.com/game-session/new" \ -H "Authorization: Bearer $ACCESS_TOKEN" \ -H "Content-Type: application/json" \ -d "{\"uuid\": \"${PROFILE_UUID}\"}") # Validate JSON response if ! echo "$SESSION_RESPONSE" | jq empty 2>/dev/null; then echo "Error: Invalid JSON response from game session creation" echo "Response: $SESSION_RESPONSE" return 1 fi # Extract session and identity tokens SESSION_TOKEN=$(echo "$SESSION_RESPONSE" | jq -r '.sessionToken') IDENTITY_TOKEN=$(echo "$SESSION_RESPONSE" | jq -r '.identityToken') if [ -z "$SESSION_TOKEN" ] || [ "$SESSION_TOKEN" = "null" ]; then echo "Error: Failed to create game server session" echo "Response: $SESSION_RESPONSE" return 1 fi echo "✓ Game server session created successfully!" return 0 } # Function to save authentication tokens (refresh_token + profile_uuid only) save_auth_tokens() { cat > "$AUTH_CACHE_FILE" << EOF { "refresh_token": "$REFRESH_TOKEN", "profile_uuid": "$PROFILE_UUID", "timestamp": $(date +%s) } EOF echo "✓ Refresh token cached for future use" } # Function to perform full authentication perform_authentication() { echo "Obtaining authentication tokens..." # Step 1: Request device code AUTH_RESPONSE=$(curl -s -X POST "https://oauth.accounts.hytale.com/oauth2/device/auth" \ -H "Content-Type: application/x-www-form-urlencoded" \ -d "client_id=hytale-server" \ -d "scope=openid offline auth:server") # Extract device_code and verification_uri_complete using jq DEVICE_CODE=$(echo "$AUTH_RESPONSE" | jq -r '.device_code') VERIFICATION_URI=$(echo "$AUTH_RESPONSE" | jq -r '.verification_uri_complete') POLL_INTERVAL=$(echo "$AUTH_RESPONSE" | jq -r '.interval') # Display authentication banner echo "" echo "╔═════════════════════════════════════════════════════════════════════════════╗" echo "║ HYTALE SERVER AUTHENTICATION REQUIRED ║" echo "╠═════════════════════════════════════════════════════════════════════════════╣" echo "║ ║" echo "║ Please authenticate the server by visiting the following URL: ║" echo "║ ║" echo "║ $VERIFICATION_URI ║" echo "║ ║" echo "║ 1. Click the link above or copy it to your browser ║" echo "║ 2. Sign in with your Hytale account ║" echo "║ 3. Authorize the server ║" echo "║ ║" echo "║ Waiting for authentication... ║" echo "║ ║" echo "╚═════════════════════════════════════════════════════════════════════════════╝" echo "" # Step 2: Poll for access token ACCESS_TOKEN="" while [ -z "$ACCESS_TOKEN" ]; do sleep $POLL_INTERVAL TOKEN_RESPONSE=$(curl -s -X POST "https://oauth.accounts.hytale.com/oauth2/token" \ -H "Content-Type: application/x-www-form-urlencoded" \ -d "client_id=hytale-server" \ -d "grant_type=urn:ietf:params:oauth:grant-type:device_code" \ -d "device_code=$DEVICE_CODE") # Check if we got an error ERROR=$(echo "$TOKEN_RESPONSE" | jq -r '.error // empty') if [ "$ERROR" = "authorization_pending" ]; then echo "Still waiting for authentication..." continue elif [ -n "$ERROR" ]; then echo "Authentication error: $ERROR" exit 1 else # Successfully authenticated ACCESS_TOKEN=$(echo "$TOKEN_RESPONSE" | jq -r '.access_token') REFRESH_TOKEN=$(echo "$TOKEN_RESPONSE" | jq -r '.refresh_token') echo "" echo "✓ Authentication successful!" echo "" fi done # Fetch available game profiles echo "Fetching game profiles..." PROFILES_RESPONSE=$(curl -s -X GET "https://account-data.hytale.com/my-account/get-profiles" \ -H "Authorization: Bearer $ACCESS_TOKEN") # Check if profiles list is empty PROFILES_COUNT=$(echo "$PROFILES_RESPONSE" | jq '.profiles | length') if [ "$PROFILES_COUNT" -eq 0 ]; then echo "Error: No game profiles found. You need to purchase Hytale to run a server." exit 1 fi # Select profile based on GAME_PROFILE variable if [ -n "$GAME_PROFILE" ]; then # User specified a profile username, find matching UUID echo "Looking for profile: $GAME_PROFILE" PROFILE_UUID=$(echo "$PROFILES_RESPONSE" | jq -r ".profiles[] | select(.username == \"$GAME_PROFILE\") | .uuid") if [ -z "$PROFILE_UUID" ] || [ "$PROFILE_UUID" = "null" ]; then echo "Error: Profile '$GAME_PROFILE' not found." echo "Available profiles:" echo "$PROFILES_RESPONSE" | jq -r '.profiles[] | " - \(.username)"' exit 1 fi echo "✓ Using profile: $GAME_PROFILE (UUID: $PROFILE_UUID)" else # Use first profile from the list PROFILE_UUID=$(echo "$PROFILES_RESPONSE" | jq -r '.profiles[0].uuid') PROFILE_USERNAME=$(echo "$PROFILES_RESPONSE" | jq -r '.profiles[0].username') echo "✓ Using default profile: $PROFILE_USERNAME (UUID: $PROFILE_UUID)" fi echo "" # Save refresh token + profile for future use save_auth_tokens # Create game server session if ! create_game_session; then exit 1 fi echo "" } chmod 755 start.sh # Check if the downloader exists if [ ! -f "$DOWNLOADER" ]; then echo "Error: Hytale downloader not found!" echo "Please run the installation script first." exit 1 fi # Check if the downloader is executable if [ ! -x "$DOWNLOADER" ]; then echo "Setting executable permissions..." chmod +x "$DOWNLOADER" fi INITIAL_SETUP=0 # Check if credentials file exists, if not run the updater if [ ! -f ".hytale-downloader-credentials.json" ]; then INITIAL_SETUP=1 echo "Credentials file not found, running initial setup..." echo "Starting Hytale downloader..." $DOWNLOADER -check-update $DOWNLOADER -patchline $PATCHLINE -download-path server.zip extract_server_files # Save version info after initial setup DOWNLOADER_VERSION=$($DOWNLOADER -print-version) echo "$DOWNLOADER_VERSION" > version.txt echo "Version info saved for later use!" fi # Run automatic update if enabled if [ "${AUTOMATIC_UPDATE}" = "1" ] && [ "${INITIAL_SETUP}" = "0" ]; then echo "Starting Hytale downloader..." # Read local version from file if [ -f "version.txt" ]; then LOCAL_VERSION=$(cat version.txt) else echo "version.txt not found, forcing update" LOCAL_VERSION="" fi # Get remote/downloader version DOWNLOADER_VERSION=$($DOWNLOADER -print-version) echo "Local version: $LOCAL_VERSION" echo "Downloader version: $DOWNLOADER_VERSION" # Compare versions if [ "$LOCAL_VERSION" != "$DOWNLOADER_VERSION" ]; then echo "Version mismatch, running update..." $DOWNLOADER -check-update $DOWNLOADER -patchline $PATCHLINE -download-path server.zip extract_server_files # Update version.txt after successful update echo "$DOWNLOADER_VERSION" > version.txt echo "Version info saved for later use!" else echo "Versions match, skipping update" fi fi # Check if server files were downloaded correctly if [ ! -f "HytaleServer.jar" ]; then echo "Error: HytaleServer.jar not found!" echo "Server files were not downloaded correctly." exit 1 fi # Check for cached authentication tokens if check_cached_tokens && load_cached_tokens; then echo "Using cached authentication..." if refresh_access_token; then # Update cache in case refresh token rotated save_auth_tokens # Create fresh game session if ! create_game_session; then exit 1 fi else # Refresh failed, need full re-auth echo "Refresh token expired, re-authenticating..." rm -f "$AUTH_CACHE_FILE" perform_authentication fi else # Perform full authentication if no valid cache exists perform_authentication fi # Export the session tokens so they're available to start.sh export SESSION_TOKEN export IDENTITY_TOKEN export PROFILE_UUID # Now call the pterodactyl entrypoint which will execute start.sh exec /bin/bash ./start.sh

Environment Variables

ACCEPT_EARLY_PLUGINS

Required

Accept Early Plugins

Acknowledge that loading early plugins is unsupported and may cause stability issues

Default
0

ALLOW_OP

Required

Allow Operators

Do you wish to allow operators or not

Default
0

ASSET_PACK

Asset Pack

Assets pack (.zip) that are being send to player

Default
Assets.zip

AUTH_MODE

Required

Auth Mode

Authentication mode

Default
authenticated

AUTOMATIC_UPDATE

Required

Automatic Update

Update the hytale server automaticly

Default
1

BACKUP_FREQUENCY

Required

Backup Frequency

Backup interval in minutes

Default
30

DISABLE_SENTRY

Required

Disable Sentry Crash Reporting

Important: Disable Sentry during active plugin development. Hytale use Sentry to track crashes. Disable it to avoid submitting your development errors

Default
1

ENABLE_BACKUPS

Required

Enable Backups

Enable automatic backups

Default
0

JVM_ARGS

JVM Arguments

Additional Java Virtual Machine arguments for advanced configuration. Warning: Improper JVM settings can lead to poor performance, crashes, or failure to start. Only modify if you understand what these parameters do.

Default
-XX:+UseG1GC -XX:+ParallelRefProcEnabled -XX:MaxGCPauseMillis=200 -XX:+UnlockExperimentalVMOptions -XX:+DisableExplicitGC -XX:G1NewSizePercent=30 -XX:G1MaxNewSizePercent=40 -XX:G1HeapRegionSize=8M -XX:G1ReservePercent=20 -XX:G1HeapWastePercent=5 -XX:G1MixedGCCountTarget=4 -XX:InitiatingHeapOccupancyPercent=15 -XX:G1MixedGCLiveThresholdPercent=90 -XX:SurvivorRatio=32 -XX:+PerfDisableSharedMem -XX:MaxTenuringThreshold=1

LEVERAGE_AHEAD_OF_TIME_CACHE

Required

Leverage Ahead-Of-Time Cache

The server ships with a pre-trained AOT cache (HytaleServer.aot) that improves boot times by skipping JIT warmup. See https://openjdk.org/jeps/514

Default
1

GAME_PROFILE

Game Profile (username)

Specify which Hytale profile should be used for server authentication. How to find your profile username: 1. Visit https://accounts.hytale.com/ 2. Click "Game Profiles" in the left side menu 3. Copy the username of the profile you want to use 4. Paste it into this field Leave empty to use your default/first profile automatically.

Default
(empty)

PATCHLINE

Required

Patchline

What release channel you want to use

Default
release

MEMORY_OVERHEAD

Required

Memory overhead

The amount of RAM (in MB) kept aside for the system so the server doesn’t use everything. Java will get the rest.

Default
0

Lifecycle Scripts

Installation Script

Installation script imported from Pterodactyl egg

before installghcr.io/pterodactyl/installers:debian
#!/bin/bash
DOWNLOAD_URL="https://downloader.hytale.com/hytale-downloader.zip"
DOWNLOAD_FILE="hytale-downloader.zip"

apt update
apt install -y curl unzip jq

cd /mnt/server

# Downloads and extracts the Hytale downloader
echo "Starting Hytale downloader installation..."

# Download the file
echo "Downloading hytale-downloader.zip..."
curl -L -o "${DOWNLOAD_FILE}" "${DOWNLOAD_URL}"

if [ $? -ne 0 ]; then
    echo "Error: Failed to download ${DOWNLOAD_URL}"
    exit 1
fi

echo "Download completed...

Install Plugins

after install
#!/bin/bash
set -e  # Exit on any error

echo "Installing Hytale Query Plugins..."

# Install curl
apt-get update && apt-get install -y curl

cd /mnt/server
mkdir -p mods

# Download Nitrado:WebServer JAR from releases
echo "Downloading Nitrado:WebServer v1.0.0..."
curl -L -o /mnt/server/mods/Nitrado-WebServer.jar \
    "https://github.com/nitrado/hytale-plugin-webserver/releases/download/v1.0.0/nitrado-webserver-1.0.0.jar"

# Download Nitrado:Query JAR from releases
echo "Downloading Nitrado:Qu...

Container Configuration

Docker Image

ghcr.io/parkervcp/yolks:java_25

Technical Profile

Template ID

hytale

Author

Community

Last Updated

January 14, 2026

Status

Active