1
0
Fork 0
2 Egg basics
Damien FLETY edited this page 2026-04-12 20:46:35 +00:00

🥚 Game Server Eggs: A Beginner's Guide

New to eggs? You're in the right place! This is the first step in your egg-making journey. After reading this, check out Configuration Variables and Extending Eggs.

What is a Game Server Egg? 🤔

Imagine you want to set up a Minecraft server for you and your friends. Instead of spending hours downloading files, configuring settings, and fixing errors, you could use an egg - a pre-made package that does all the hard work for you!

A game server egg is a single JSON file (for example, egg-my-server.json) that acts like a recipe for setting up a game server. Everything lives inside this one file:

  • Instructions for installing and starting the server
  • The installation script (embedded right inside the JSON!)
  • Settings that you can customize
  • Which Docker image to run the server in

Why Use Eggs? 🎮

Fast Setup: Get your server running in minutes instead of hours Easy Customization: Change settings without editing complicated files Consistent Results: Every server using the same egg works the same way Easy Updates: Update all your servers at once Less Frustration: No more dealing with confusing installation errors

What You'll Need 🛠️

Before you start creating eggs, make sure you have:

  1. A computer (Windows, Mac, or Linux)
  2. Basic command line knowledge (how to run commands in Terminal)
  3. A text editor (VS Code, Notepad++, or even Notepad)
  4. Patience and curiosity (you'll learn as you go!)

Understanding Egg Structure 📄

An egg is one JSON file — there are no separate folders, no extra scripts, no config.json sitting next to an install.sh. Everything is bundled together inside the JSON.

Here is what a complete egg file looks like:

{
    "_comment": "DO NOT EDIT: FILE GENERATED AUTOMATICALLY BY PANEL",
    "meta": { "update_url": null, "version": "PTDL_v2" },
    "exported_at": "2024-01-01T00:00:00+00:00",
    "name": "My Game Server",
    "author": "you@example.com",
    "description": "A cool game server",
    "features": null,
    "docker_images": {
        "Java 21": "ghcr.io/ptero-eggs/yolks:java_21",
        "Java 17": "ghcr.io/ptero-eggs/yolks:java_17"
    },
    "file_denylist": [],
    "startup": "java -jar {{SERVER_JARFILE}}",
    "config": {
        "files": "{}",
        "logs": "{}",
        "startup": "{\"done\": \"Server started\"}",
        "stop": "^C"
    },
    "scripts": {
        "installation": {
            "container": "ghcr.io/ptero-eggs/installers:debian",
            "entrypoint": "bash",
            "script": "#!/bin/bash\nmkdir -p /mnt/server\ncd /mnt/server\n# download game files here\necho 'Done!'"
        }
    },
    "variables": [
        {
            "name": "JAR File",
            "description": "The server jar file to run",
            "env_variable": "SERVER_JARFILE",
            "default_value": "server.jar",
            "user_viewable": true,
            "user_editable": true,
            "rules": "required|string|max:50",
            "field_type": "text"
        }
    ]
}

Let's look at each part:

1. name, author, description - Identity 🏷️

These tell the panel what your egg is called and who made it. They show up in the UI.

2. docker_images - The Runtime Environment 🐳

This is the Docker image the server runs inside once it's installed. Think of it like choosing which version of Java or Node.js your server uses. Always use images from ghcr.io/ptero-eggs/yolks:*.

3. startup - The Start Command ▶️

The command the panel runs when someone clicks "Start". You can use {{VARIABLE_NAME}} placeholders here that get replaced with the user's settings.

4. config - Panel Behaviour ⚙️

Tells the panel things like:

  • startup: What text in the server log means "the server is ready"
  • stop: What command to send to stop the server (e.g. ^C or stop)
  • files and logs: Advanced config file parsing settings

5. scripts.installation - The Installer 📥

This is where the magic happens! The installation script is embedded as a string right here inside the JSON, at scripts.installation.script. During install, it runs inside a temporary container (usually ghcr.io/ptero-eggs/installers:debian) and puts server files into /mnt/server. At runtime, those files are available at /home/container.

6. variables - User Settings 🎛️

A list of settings users can change from the panel, like which port to use or how much RAM to give the server. Each variable has a name, description, default value, and validation rules.

Creating Your First Egg: Step by Step 🚀

Let's create a simple egg together! We'll make a single JSON file that you can adapt for any game.

Step 1: Create the JSON File

Open your text editor and create a new file called egg-my-first-server.json.

Paste in this template:

{
    "_comment": "DO NOT EDIT: FILE GENERATED AUTOMATICALLY BY PANEL",
    "meta": { "update_url": null, "version": "PTDL_v2" },
    "exported_at": "2024-01-01T00:00:00+00:00",
    "name": "My First Game Server",
    "author": "you@example.com",
    "description": "A simple game server egg for beginners",
    "features": null,
    "docker_images": {
        "Ubuntu": "ghcr.io/ptero-eggs/yolks:ubuntu"
    },
    "file_denylist": [],
    "startup": "bash start.sh",
    "config": {
        "files": "{}",
        "logs": "{}",
        "startup": "{\"done\": \"Server is ready!\"}",
        "stop": "^C"
    },
    "scripts": {
        "installation": {
            "container": "ghcr.io/ptero-eggs/installers:debian",
            "entrypoint": "bash",
            "script": "#!/bin/bash\n\necho '🚀 Starting installation...'\nmkdir -p /mnt/server\ncd /mnt/server\n\n# Write a simple start script\ncat > start.sh << 'EOF'\n#!/bin/bash\necho \"🌟 Starting ${SERVER_NAME}!\"\necho \"👥 Max players: ${MAX_PLAYERS}\"\necho \"✅ Server is ready!\"\nEOF\n\nchmod +x start.sh\necho '🎉 Installation complete!'"
        }
    },
    "variables": [
        {
            "name": "Server Name",
            "description": "What should we call your server?",
            "env_variable": "SERVER_NAME",
            "default_value": "My Awesome Server",
            "user_viewable": true,
            "user_editable": true,
            "rules": "required|string|max:64",
            "field_type": "text"
        },
        {
            "name": "Max Players",
            "description": "How many players can join at once?",
            "env_variable": "MAX_PLAYERS",
            "default_value": "10",
            "user_viewable": true,
            "user_editable": true,
            "rules": "required|numeric|min:1|max:100",
            "field_type": "text"
        }
    ]
}

That's it — one file and you're done with the structure! 🎉

Step 2: Understand What You Just Wrote

Let's walk through the key pieces:

  • startup: bash start.sh — when the server starts, it runs start.sh from inside /home/container
  • scripts.installation.script: The bash script is embedded as a single string with \n for newlines. It runs in a temporary Debian container, creates files in /mnt/server, which become /home/container at runtime
  • variables: Two settings the user can change — the server name and max players. The egg can read these as ${SERVER_NAME} and ${MAX_PLAYERS} inside the install script

Step 3: Check the Startup Detection

The config.startup field tells the panel when the server has finished starting up:

"startup": "{\"done\": \"Server is ready!\"}"

This means: once the panel sees Server is ready! in the server logs, it marks the server as online. Make sure your startup command actually prints that text!

Step 4: Import Your Egg

  1. Log into your Pterodactyl panel
  2. Go to Admin → Nests and select or create a Nest
  3. Click Import Egg
  4. Upload your egg-my-first-server.json file
  5. Create a server using the egg and watch it install!

Step 5: Iterate and Improve

  • Try changing the variables and re-importing
  • Add more variables for more customization
  • Replace bash start.sh in startup with a real game server command
  • Update the install script to download real game files into /mnt/server

Making a Real Game Server Egg 🎮

Now that you understand the basics, here's how to adapt the template for real games:

For Minecraft (Paper):

The docker_images should point to a Java runtime:

"docker_images": {
    "Java 21": "ghcr.io/ptero-eggs/yolks:java_21",
    "Java 17": "ghcr.io/ptero-eggs/yolks:java_17"
}

The startup command uses Paper's recommended flags:

"startup": "java -Xms128M -XX:MaxRAMPercentage=95.0 -Dterminal.jline=false -Dterminal.ansi=true -jar {{SERVER_JARFILE}}"

The startup detection for Paper looks like:

"startup": "{\"done\": \")! For help, type \"}"

The install script (at scripts.installation.script) downloads Paper into /mnt/server:

#!/bin/bash
mkdir -p /mnt/server
cd /mnt/server

BUILD=$(curl -s https://api.papermc.io/v2/projects/paper/versions/${MINECRAFT_VERSION}/builds \
    | jq -r '.builds | last | .build')

curl -Lo server.jar \
    "https://api.papermc.io/v2/projects/paper/versions/${MINECRAFT_VERSION}/builds/${BUILD}/downloads/paper-${MINECRAFT_VERSION}-${BUILD}.jar"

echo "eula=true" > eula.txt

echo "Done!"

For Counter-Strike 2:

CS2 is installed via SteamCMD, so the runtime image is:

"docker_images": {
    "CS2": "ghcr.io/ptero-eggs/steamcmd:sniper"
}

The startup might look like:

"startup": "./game/bin/linuxsteamrt64/cs2 -dedicated +map {{START_MAP}}"

The install script downloads CS2 using SteamCMD directly into /mnt/server:

#!/bin/bash
mkdir -p /mnt/server
cd /mnt/server

steamcmd +force_install_dir /mnt/server \
    +login anonymous \
    +app_update 730 validate \
    +quit

echo "Done!"

Common Mistakes to Avoid

  1. Thinking the egg is a folder — it's a single .json file. Everything lives inside it!

  2. Installing files to the wrong path — your install script must write files to /mnt/server, not /server or /home/container. The panel maps /mnt/server to /home/container at runtime.

  3. Wrong Docker image registry — always use ghcr.io/ptero-eggs/yolks:* for runtime images and ghcr.io/ptero-eggs/installers:debian (or :alpine) for the installer container. The old ghcr.io/parkervcp/yolks:* registry is outdated.

  4. Broken startup detection — if config.startup.done doesn't match what your server actually prints, the panel will never show the server as online. Check your server logs carefully!

  5. Forgetting to escape newlines in the script — the install script is a JSON string, so newlines must be written as \n. Most editors or the panel's UI handle this automatically, but watch out if you're hand-editing the JSON.

  6. Using hardcoded values instead of variables — put customizable things (like ports, jar filenames, or game versions) in variables so users can change them from the panel without touching the egg.

Next Steps 📚

Now that you understand the basics, here's your learning path:

  1. Configuration Variables Reference ⚙️

    • All variable types explained
    • How to make your eggs customizable
    • Validation and best practices
  2. Extending and Creating Eggs 🔧

    • Learn how to extend existing eggs
    • Real examples from actual eggs
    • Configuration file management
    • Complete working examples
  3. Wings Variables Reference 🌐

    • Special variables the panel provides
    • {{server.build.default.port}} and more
    • Real examples from real eggs
  4. File Parsers Guide 📝

    • How to automatically edit configuration files
    • JSON, YAML, INI, and more
    • Tips and real examples

Documentation Map 🗺️

Here's the complete documentation structure:

Page Level Topics
Egg Basics 🐣 Beginner What are eggs, JSON structure, first egg
Configuration Variables 🛠️ Basic Variable types, customization, validation
Extending Eggs 🔧 Intermediate Extending eggs, creating from scratch, file management
Wings Variables 🌐 Advanced Panel variables, special syntax, real examples
File Parsers 📝 Advanced Config file management, JSON/YAML/INI parsers

Need More Help? 🆘

Stuck? Here are your resources:

  1. Check the documentation - Each page has examples and explanations
  2. Look at real eggs - The docs include examples from real, working eggs
  3. Try small changes - Start simple and gradually add complexity
  4. Experiment freely - You can't break anything permanently!
  5. Ask the community - Community forums are very helpful

Remember: Every expert was once a beginner. Keep learning and have fun! 🎉


Ready to continue?Configuration Variables Reference