Table of Contents
- 🥚 Game Server Eggs: A Beginner's Guide
- What is a Game Server Egg? 🤔
- Why Use Eggs? 🎮
- What You'll Need 🛠️
- Understanding Egg Structure 📄
- Creating Your First Egg: Step by Step 🚀
- Step 1: Create the JSON File
- Step 2: Understand What You Just Wrote
- Step 3: Check the Startup Detection
- Step 4: Import Your Egg
- Step 5: Iterate and Improve
- Making a Real Game Server Egg 🎮
- Common Mistakes to Avoid ❌
- Next Steps 📚
- Documentation Map 🗺️
- Need More Help? 🆘
🥚 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:
- A computer (Windows, Mac, or Linux)
- Basic command line knowledge (how to run commands in Terminal)
- A text editor (VS Code, Notepad++, or even Notepad)
- 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.^Corstop)filesandlogs: 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 runsstart.shfrom inside/home/containerscripts.installation.script: The bash script is embedded as a single string with\nfor newlines. It runs in a temporary Debian container, creates files in/mnt/server, which become/home/containerat runtimevariables: 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
- Log into your Pterodactyl panel
- Go to Admin → Nests and select or create a Nest
- Click Import Egg
- Upload your
egg-my-first-server.jsonfile - 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.shinstartupwith 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 ❌
-
Thinking the egg is a folder — it's a single
.jsonfile. Everything lives inside it! -
Installing files to the wrong path — your install script must write files to
/mnt/server, not/serveror/home/container. The panel maps/mnt/serverto/home/containerat runtime. -
Wrong Docker image registry — always use
ghcr.io/ptero-eggs/yolks:*for runtime images andghcr.io/ptero-eggs/installers:debian(or:alpine) for the installer container. The oldghcr.io/parkervcp/yolks:*registry is outdated. -
Broken startup detection — if
config.startup.donedoesn't match what your server actually prints, the panel will never show the server as online. Check your server logs carefully! -
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. -
Using hardcoded values instead of variables — put customizable things (like ports, jar filenames, or game versions) in
variablesso users can change them from the panel without touching the egg.
Next Steps 📚
Now that you understand the basics, here's your learning path:
-
Configuration Variables Reference ⚙️
- All variable types explained
- How to make your eggs customizable
- Validation and best practices
-
- Learn how to extend existing eggs
- Real examples from actual eggs
- Configuration file management
- Complete working examples
-
- Special variables the panel provides
{{server.build.default.port}}and more- Real examples from real eggs
-
- 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:
- Check the documentation - Each page has examples and explanations
- Look at real eggs - The docs include examples from real, working eggs
- Try small changes - Start simple and gradually add complexity
- Experiment freely - You can't break anything permanently!
- 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