diff --git a/.vuepress/config.js b/.vuepress/config.js index 736bfcee3..7949fabcc 100644 --- a/.vuepress/config.js +++ b/.vuepress/config.js @@ -91,6 +91,10 @@ module.exports = { collapsable: false, children: [ '/community/config/eggs/creating_a_custom_egg.md', + '/community/config/eggs/egg_docker_images.md', + '/community/config/eggs/egg_config_parser.md', + '/community/config/eggs/egg_variables.md', + '/community/config/eggs/egg_install_script.md', '/community/config/eggs/creating_a_custom_image.md', ], }, diff --git a/.vuepress/public/community/config/eggs/Pterodactyl_Create_New_Egg.png b/.vuepress/public/community/config/eggs/Pterodactyl_Create_New_Egg.png index 23170a40d..24c0b786d 100644 Binary files a/.vuepress/public/community/config/eggs/Pterodactyl_Create_New_Egg.png and b/.vuepress/public/community/config/eggs/Pterodactyl_Create_New_Egg.png differ diff --git a/.vuepress/public/community/config/eggs/Pterodactyl_Create_New_Egg_Copy_Settings_From.png b/.vuepress/public/community/config/eggs/Pterodactyl_Create_New_Egg_Copy_Settings_From.png index d0cf7c097..402a9fc1e 100644 Binary files a/.vuepress/public/community/config/eggs/Pterodactyl_Create_New_Egg_Copy_Settings_From.png and b/.vuepress/public/community/config/eggs/Pterodactyl_Create_New_Egg_Copy_Settings_From.png differ diff --git a/.vuepress/public/community/config/eggs/Pterodactyl_Create_New_Egg_Process_Management.png b/.vuepress/public/community/config/eggs/Pterodactyl_Create_New_Egg_Process_Management.png index eac159d1c..fc27bf4a2 100644 Binary files a/.vuepress/public/community/config/eggs/Pterodactyl_Create_New_Egg_Process_Management.png and b/.vuepress/public/community/config/eggs/Pterodactyl_Create_New_Egg_Process_Management.png differ diff --git a/.vuepress/public/community/config/eggs/Pterodactyl_Create_New_Egg_Select.png b/.vuepress/public/community/config/eggs/Pterodactyl_Create_New_Egg_Select.png index 4e9297c70..cd0ecbb85 100644 Binary files a/.vuepress/public/community/config/eggs/Pterodactyl_Create_New_Egg_Select.png and b/.vuepress/public/community/config/eggs/Pterodactyl_Create_New_Egg_Select.png differ diff --git a/.vuepress/public/community/config/eggs/Pterodactyl_Create_New_Egg_Startup.png b/.vuepress/public/community/config/eggs/Pterodactyl_Create_New_Egg_Startup.png index 42054a53b..1145f0b53 100644 Binary files a/.vuepress/public/community/config/eggs/Pterodactyl_Create_New_Egg_Startup.png and b/.vuepress/public/community/config/eggs/Pterodactyl_Create_New_Egg_Startup.png differ diff --git a/.vuepress/public/community/config/eggs/Pterodactyl_Create_New_Egg_Variables.png b/.vuepress/public/community/config/eggs/Pterodactyl_Create_New_Egg_Variables.png index d0c816209..72db5a3c4 100644 Binary files a/.vuepress/public/community/config/eggs/Pterodactyl_Create_New_Egg_Variables.png and b/.vuepress/public/community/config/eggs/Pterodactyl_Create_New_Egg_Variables.png differ diff --git a/.vuepress/public/community/config/eggs/Pterodactyl_Create_New_Nest.png b/.vuepress/public/community/config/eggs/Pterodactyl_Create_New_Nest.png index 03adf71f6..4373e64f9 100644 Binary files a/.vuepress/public/community/config/eggs/Pterodactyl_Create_New_Nest.png and b/.vuepress/public/community/config/eggs/Pterodactyl_Create_New_Nest.png differ diff --git a/community/config/eggs/creating_a_custom_egg.md b/community/config/eggs/creating_a_custom_egg.md index f458960d3..0b9732abd 100644 --- a/community/config/eggs/creating_a_custom_egg.md +++ b/community/config/eggs/creating_a_custom_egg.md @@ -1,203 +1,53 @@ # Creating a Custom Egg + ::: warning -You should not edit existing services or options that ship with the Panel. Each upgrade we push can make minor -changes to these, and you'll lose any changes you've made. +Do not modify the default Nests or Eggs provided by the Panel. Each Pterodactyl update may alter these defaults and override your changes. ::: [[toc]] -The first thing you'll need to do is create a new service. In this case, the name and description speak for themselves. -The `Folder Name` _must be a unique name_ not being used by any other service, and should only -contain letters, numbers, underscores, and dashes. This is the name of the folder where the daemon will be storing -the service options on the daemon. - -The default start command is also required, however it can be changed per-option. - -## Create New Option -After creating the service, in the bottom right of the page you should see a button titled `New Egg`, press it. - -![](../../../.vuepress/public/community/config/eggs/Pterodactyl_Create_New_Egg_Select.png) - -You will be taken to a new service option page which is where most of the configuration happens. The first thing -you need to do is select your service that you created previously from the `Associated Nest` dropdown. - -![](../../../.vuepress/public/community/config/eggs/Pterodactyl_Create_New_Egg_Process_Management.png) - -After that, enter an Option Name to describe it, in this case I am using `Widget`. You will also need to provide a -_valid_ docker image, as well as a start command to be assigned to servers under this service option (remember, this -can be tweaked per-server if needed). - -_Docker images must be specifically designed to work with Pterodactyl Panel._ You should read more about that in -our [Creating a Docker Image](/community/config/eggs/creating_a_custom_image.md) guide. - -## Configure Process Management -This is perhaps the most important step in this service option configuration, as this tells the Daemon how to run everything. - -![](../../../.vuepress/public/community/config/eggs/Pterodactyl_Create_New_Egg_Process_Management.png) - -The first field you'll encounter is `Copy Settings From`. The default selection is `None`. That is expected, and okay. -This dropdown is discussed at the end of this article. - -### Stop Command -Next, you'll encounter `Stop Command` and, as the name implies, this should be the command used to safely stop the -option. For some games, this is `stop` or `end`. Certain programs and games don't have a specified stop command, so -you can enter `^C` to have the daemon execute a `SIGINT` to end the process. - -### Log Storage -Logs are competely handeled by the daemon now and use the docker logs to output the complete output from the server. -This can be set like below. - -```json -{} -``` - -### Configuration Files -The next block is one of the most complex blocks, the `Configuration Files` descriptor. The Daemon will process this -block prior to booting the server to ensure all of the required settings are defined and set correctly. - -```json -{ - "server.properties": { - "parser": "properties", - "find": { - "server-ip": "0.0.0.0", - "enable-query": "true", - "server-port": "{{server.build.default.port}}", - "query.port": "{{server.build.default.port}}" - } - } -} -``` - -In this example, we are telling the Daemon to read `server.properties` in `/home/container`. Within this block, we -define a `parser`, in this case `properties` but the following are [valid parsers](https://github.com/pterodactyl/wings/blob/develop/parser/parser.go#L25-L30): - -* `file` — This parser goes based on matching the beginning of lines, and not a specific property like the other five. -Avoid using this parser if possible. -* `yaml` (supports `*` notation) -* `properties` -* `ini` -* `json` (supports `*` notation) -* `xml` - -Once you have defined a parser, we then define a `find` block which tells the Daemon what specific elements to find -and replace. In this example, we have provided four separate items within the `server.properties` file that we want to -find and replace to the assigned values. You can use either an exact value, or define a specific server setting from -the `server.json` file. In this case, we're assigning the default server port to be used as the `server-port` and -`query.port`. **These placeholders are case sensitive, and should have no spaces in them.** - -You can have multiple files listed here, the Daemon will process them in parallel before starting the server. When -using `yaml` or `json` you can use more advanced searching for elements. - -```json -{ - "config.yml": { - "parser": "yaml", - "find": { - "listeners[0].query_enabled": true, - "listeners[0].query_port": "{{server.build.default.port}}", - "listeners[0].host": "0.0.0.0:{{server.build.default.port}}", - "servers.*.address": { - "127.0.0.1": "{{config.docker.interface}}", - "localhost": "{{config.docker.interface}}" - } - } - } -} -``` - -In this example, we are parsing `config.yml` using the `yaml` parser. The first three find items are simply assigning -ports and IPs for the first listener block. The last one, `servers.*.address` uses wildcard matching to match any items -within the `servers` block, and then finding each `address` block for those items. - -::: v-pre -An advanced feature of this file configuration is the ability to define multiple find and replace statements for a -single matching line. In this case, we are looking for either `127.0.0.1` or `localhost` and replacing them with the -docker interface defined in the configuration file using `{{config.docker.interface}}`. -::: - -### Start Configuration -The last block to configure is the `Start Configuration` for servers running using this service option. +Before creating a custom Egg, it’s important to understand Pterodactyl’s structure: -```json -{ - "done": ")! For help, type " -} -``` +**Nests** are collections of eggs (like categories for related server types), and **Eggs** are the specific configurations for installing and running a particular game or software. -In the example block above, we define `done` as the entire line, or part of a line that indicates a server is done -starting, and is ready for players to join. When the Daemon sees this output, it will mark the server as `ON` rather -than `STARTING`. +## Creating a New Nest (Category) -That concludes basic service option configuration. +If your egg doesn’t fit into an existing Nest, you should create a new Nest for it. The Nests page can be found in the Admin Dashboard (in the left sidebar, near the bottom). -## Copy Settings From -As mentioned above, there is a unique `Copy Settings From` dropdown when adding a new option. This gives you the -ability to, as the name suggests, copy settings defined above from a different option. +Click the **“Create New”** button on the Nests page to create a new Nest. You will need to provide: -![](../../../.vuepress/public/community/config/eggs/Pterodactyl_Create_New_Egg_Copy_Settings_From.png) +- **Name:** A descriptive name for the category (for example, “Custom Games” or “Minecraft Mods”). -In the panel, we use this to copy settings that remain the same between similar service options, such as many of the -Minecraft options. +- **Description:** (Optional) Details about what eggs in this nest are for. -For example, lets look at the `Sponge (SpongeVanilla)` service option. -As you can see, it as been told to copy settings from `Vanilla Minecraft`. This means that any of the fields that are -left blank will inherit from the assigned parent. We then define a specific `userInteraction` line that is different in -Sponge compared to Vanilla, but tell it that everything else should remain the same. +Once these are filled, save the new Nest. -*Please note that `Copy Settings From` does not support nested copies, you can only copy from a single parent, -and that parent **must not be copying from another option.*** +::: tip +If you have a pre-made Egg JSON file (for example, from the community), you can import it instead of creating one from scratch. Use the **“Import Egg”** button on the Nests page, select the target Nest, and upload the egg’s JSON file. Check out the [Community Egg Repository](https://pterodactyleggs.com) for a large selection of ready-to-use community eggs. +::: -## Egg Variables -One of the great parts of the Egg Variables is the ability to define specific variables that users and/or admins can -control to tweak different settings without letting users modify the startup command. To create new variables, or edit -existing ones, visit the new service option you created, and click the `Variables` tab at the top of the page. Lets take -a look at an example variable that we can create. +## Creating a New Egg -![](../../../.vuepress/public/community/config/eggs/Pterodactyl_Create_New_Egg_Variables.png) +After you have a Nest, you can create a new Egg within that nest. To do this, navigate to the nest’s detail page, then click the **“New Egg”** button at the bottom of the page. -::: v-pre -The name and description are rather self-explanitory, so I'll skip down to the `Environment Variable` box. This should -be an Alpha-Numeric name with underscores, and should be uppercase. This will be the name of the environment variable -which can be accessed in the startup command as `{{WOOZLE_WOO}}`, within file modifications as `{{env.WOOZLE_WOO}}`, or -just `${WOOZLE_WOO}` in any shell scripts (it is passed through in the environment). We also define a default value for -this environment variable in this example, but it is not required to do so. -::: +![](../../../.vuepress/public/community/config/eggs/Pterodactyl_Create_New_Egg_Select.png) -The next section is `Permissions`, which is a dropdown with two options: `Users Can View` and `Users Can Edit`. +This opens the egg configuration form (the “New Egg” page). If not already selected, choose the appropriate Nest from the **Associated Nest** dropdown at the top of the form. -* `Users Can View` — allows a user to view the field on the front-end, as well as the assigned value of that variable. -They will be able to see it replaced in their startup command. -* `Users Can Edit` — allows a user to edit the value of the variable, for example the name of their `server.jar` file -if running Minecraft. +Now fill out the details for your new Egg: -You should use caution here, even if you assign neither of the permissions it does not mean that the value will be -hidden. Crafty users will still be able to get the environment on their server. In most cases this is simply hiding -it from the user, and then used within the Dockerfile to perform actions, thus it is not important for the user to see. +### Basic Details -Finally, you will need to define some input rules to validate the value against. In this example, we use -`required|string|between:1,10`, which means the field is `required`, must be a `string`, and must be between `1` and -`10` characters in length. You can find [all of the available validation rules](https://laravel.com/docs/5.6/validation#available-validation-rules) -on the Laravel website. You can also use ReGEX based validation by using the `regex:` rule flag. For example, -[`required|regex:/^([\w\d._-]+)(\.jar)$/`](https://regex101.com/r/k4oEOn/1) will require the field, and will match the -regex as any letters or numbers (`\w\d`) including underscore (`_`), periods (`.`), and dashes (`-`) ending in `.jar`. +- **Name:** The name of the Egg (e.g. “MyGame Dedicated Server”). This is how the egg will be listed in the panel. -They will then be visible when managing the startup for a server in both the Admin CP and on the Front-End. +- **Description:** A short description of what this egg is or does. -![](../../../.vuepress/public/community/config/eggs/Pterodactyl_Create_New_Egg_Startup.png) -## List of default variables +### Docker Images -The default variables are always accessible to all eggs and don't have to be created separately. They can be used in the egg startup, install script, or the configuration file parser. +Here you select the Docker image(s) that the server will run in. Docker images define the environment (OS and software) available to your server. Pterodactyl provides a variety of [Official images](https://github.com/Ptero-Eggs/yolks) (called “yolks”) for many common use-cases, or you can specify a custom image. -| Variable | Description | Example | -| ------------------------- | ------------------------------------------- | -------------------------------------------------------------- | -| TZ | Time Zone | `Etc/UTC` | -| STARTUP | Startup command of the egg | `java -Xms128M -Xmx{{SERVER_MEMORY}}M -jar {{SERVER_JARFILE}}` | -| SERVER_MEMORY | Memory available for the server in MB | `512` | -| SERVER_IP | Default ip of the server | `127.0.0.1` | -| SERVER_PORT | Primary Server Port | `27015` | -| P_SERVER_LOCATION | Location of the server | `Example City` | -| P_SERVER_UUID | UUID of the server | `539fdca8-4a08-4551-a8d2-8ee5475b50d9` | -| P_SERVER_ALLOCATION_LIMIT | Limit of allocations allowed for the server | `0` | +::: warning +Make sure the Docker image contains all the required runtime dependencies for your server. Any package installed **only in the install script** will **not** be present when the server is running. Also, **the image must include a user named `container` with home directory `/home/container`** (this is required by Pterodactyl for all images). +::: \ No newline at end of file diff --git a/community/config/eggs/creating_a_custom_image.md b/community/config/eggs/creating_a_custom_image.md index cf9063864..e991a738d 100644 --- a/community/config/eggs/creating_a_custom_image.md +++ b/community/config/eggs/creating_a_custom_image.md @@ -2,159 +2,167 @@ [[toc]] -::: warning -This tutorial uses examples from our [`core:java`](https://github.com/pterodactyl/images/tree/java) docker image, -which can be found on GitHub. This tutorial also assumes some knowledge of [Docker](https://docker.io/), we suggest -reading up if this all looks foreign to you. +:::warning +All Pterodactyl containers must have a user named `container`, and the user home must be `/home/container` ::: +This guide explains how to create a custom Docker image for use with Pterodactyl eggs, using a modern base example from the [Ptero-Eggs yolks repository](https://github.com/Ptero-Eggs/yolks/tree/main). -## Creating the Dockerfile +Docker images define the environment in which a server runs—what software is installed, what versions are used, and how everything is launched. Custom images allow you to add packages or modify behavior beyond what official yolks provide. -The most important part of this process is to create the [`Dockerfile`](https://docs.docker.com/engine/reference/builder/) -that will be used by the Daemon. Due to heavy restrictions on server containers, you must setup this file in a specific manner. +## Dockerfile Example -We try to make use of [Alpine Linux](https://alpinelinux.org) as much as possible for our images in order to keep their size down. +Here’s a full Dockerfile example using Java 21 as the base image: -```bash -# ---------------------------------- -# Pterodactyl Core Dockerfile -# Environment: Java -# Minimum Panel Version: 0.6.0 -# ---------------------------------- -FROM openjdk:8-jdk-alpine +```dockerfile +FROM --platform=$TARGETOS/$TARGETARCH eclipse-temurin:21-jdk-jammy -MAINTAINER Pterodactyl Software, +LABEL author="Matthew Penner" maintainer="matthew@pterodactyl.io" +LABEL org.opencontainers.image.source="https://github.com/pterodactyl/yolks" +LABEL org.opencontainers.image.licenses=MIT -RUN apk add --no-cache --update curl ca-certificates openssl git tar bash sqlite fontconfig \ - && adduser --disabled-password --home /home/container container +ENV DEBIAN_FRONTEND=noninteractive -USER container -ENV USER=container HOME=/home/container +RUN apt update -y \ + && apt install -y \ + curl \ + lsof \ + ca-certificates \ + openssl \ + git \ + tar \ + sqlite3 \ + fontconfig \ + tzdata \ + iproute2 \ + libfreetype6 \ + tini \ + zip \ + unzip + +RUN useradd -m -d /home/container -s /bin/bash container +USER container +ENV USER=container HOME=/home/container WORKDIR /home/container -COPY ./entrypoint.sh /entrypoint.sh +COPY --chown=container:container ./entrypoint.sh /entrypoint.sh +RUN chmod +x /entrypoint.sh -CMD ["/bin/bash", "/entrypoint.sh"] +ENTRYPOINT ["/usr/bin/tini", "-g", "--"] +CMD ["/entrypoint.sh"] ``` -Lets walk through the `Dockerfile` above. The first thing you'll notice is the [`FROM`](https://docs.docker.com/engine/reference/builder/#from) declaration. +## Breakdown of the Dockerfile -```bash -FROM openjdk:8-jdk-alpine +### Base Image +```dockerfile +FROM --platform=$TARGETOS/$TARGETARCH eclipse-temurin:21-jdk-jammy ``` +Uses Eclipse Temurin Java 21 JDK on Ubuntu Jammy. The `--platform` flag ensures compatibility with different system architectures. -In this case, we are using [`openjdk:8-jdk-alpine`](https://github.com/docker-library/openjdk) which provides us with Java 8. - -## Installing Dependencies - -The next thing we do is install the dependencies we will need using Alpine's package manager: `apk`. You'll notice some -specific flags that keep the container small, including `--no-cache`, as well as everything being contained in a -single [`RUN`](https://docs.docker.com/engine/reference/builder/#run) block. - -## Creating a Container User - -Within this `RUN` block, you'll notice the `useradd` command. - -```bash -adduser -D -h /home/container container +### Metadata Labels +```dockerfile +LABEL author="..." ``` +Provides metadata such as author, source, and license. Useful for documentation. -::: warning -All Pterodactyl containers must have a user named `container`, and the user home **must** be `/home/container`. -::: - -After we create that user, we then define the default container [`USER`](https://docs.docker.com/engine/reference/builder/#user) -as well as a few [`ENV`](https://docs.docker.com/engine/reference/builder/#env) settings to be applied to things running -within the container. +### Dependencies +```dockerfile +RUN apt update -y && apt install -y [...] +``` +Installs useful server packages: -## Work Directory & Entrypoint +- `curl`, `lsof`, `openssl`: Common CLI tools. +- `fontconfig`, `libfreetype6`: Support Java-based GUI rendering. +- `tini`: Handles signal forwarding and zombie reaping. -One of the last things we do is define a [`WORKDIR`](https://docs.docker.com/engine/reference/builder/#workdir) which -is where everything else will be executed. The `WORKDIR` must be set the `/home/container`. +### User Setup -Finally, we need to copy our [`ENTRYPOINT`](https://docs.docker.com/engine/reference/builder/#entrypoint) script into -the docker image root. This is done using [`COPY`](https://docs.docker.com/engine/reference/builder/#copy), after which -we define the command to be used when the container is started using [`CMD`](https://docs.docker.com/engine/reference/builder/#cmd). -The `CMD` line should always point to the `entrypoint.sh` file. -```bash -COPY ./entrypoint.sh /entrypoint.sh -CMD ["/bin/bash", "/entrypoint.sh"] +```dockerfile +RUN useradd -m -d /home/container -s /bin/bash container ``` +Creates a non-root user `container` to enhance security. -## Entrypoint Script - -In order to complete this `Dockerfile`, we will need an `entrypoint.sh` file which tells Docker how to run this -specific server type. - -These entrypoint files are actually fairly abstracted, and the Daemon will pass in the start command as an environment -variable before processing it and then executing the command. - -```bash -#!/bin/bash -cd /home/container +### Switch User & Set Environment +```dockerfile +USER container +ENV USER=container HOME=/home/container +``` +Switches to the new user and sets key environment variables. -# Output Current Java Version -java -version ## only really needed to show what version is being used. Should be changed for different applications +### Working Directory +```dockerfile +WORKDIR /home/container +``` +Sets the default working directory. -# Replace Startup Variables -MODIFIED_STARTUP=`eval echo $(echo ${STARTUP} | sed -e 's/{{/${/g' -e 's/}}/}/g')` -echo ":/home/container$ ${MODIFIED_STARTUP}" +### Entrypoint Setup +```dockerfile +COPY --chown=container:container ./entrypoint.sh /entrypoint.sh +RUN chmod +x /entrypoint.sh +``` +Copies the startup script and ensures it’s executable. -# Run the Server -${MODIFIED_STARTUP} +### Entry Command +```dockerfile +ENTRYPOINT ["/usr/bin/tini", "-g", "--"] +CMD ["/entrypoint.sh"] ``` +Uses `tini` to launch the container and execute the custom startup script. + +## Example entrypoint.sh -The second command, `cd /home/container`, simply ensures we are in the correct directory when running the rest of the -commands. We then follow that up with `java -version` to output this information to end-users, but that is not necessary. +In order to complete this Dockerfile, we will need an entrypoint.sh file which tells Docker how to run this specific server type. -## Modifying the Startup Command +These entrypoint files are actually fairly abstracted, and the Daemon will pass in the start command as an environment variable before processing it and then executing the command. -The most significant part of this file is the `MODIFIED_STARTUP` environment variable. What we are doing in this case -is parsing the environment `STARTUP` that is passed into the container by the Daemon. In most cases, this variable -looks something like the example below: +#### This script pairs with the Dockerfile above: ```bash -STARTUP="java -Xms128M -Xmx{{SERVER_MEMORY}}M -jar {{SERVER_JARFILE}}" -``` +#!/bin/bash -::: v-pre -You'll notice some placeholders there, specifically `{{SERVER_MEMORY}}` and `{{SERVER_JARFILE}}`. These both refer to -other environment variables being passed in, and they look something like the example below. -::: +# Default the TZ environment variable to UTC. +TZ=${TZ:-UTC} +export TZ -```bash -SERVER_MEMORY=1024 -SERVER_JARFILE=server.jar -``` +# Set environment variable that holds the Internal Docker IP +INTERNAL_IP=$(ip route get 1 | awk '{print $(NF-2);exit}') +export INTERNAL_IP -There are a host of different environment variables, and they change depending on the specific service option -configuration. However, that is not necessarily anything to worry about here. +# Switch to the container's working directory +cd /home/container || exit 1 -```bash -MODIFIED_STARTUP=`eval echo $(echo ${STARTUP} | sed -e 's/{{/${/g' -e 's/}}/}/g')` -``` +# Print Java version +printf "\033[1m\033[33mcontainer@pterodactyl~ \033[0mjava -version\n" +java -version -::: v-pre -The command above simply evaluates the `STARTUP` environment variable, and then replaces anything surrounded in -curly braces `{{EXAMPLE}}` with a matching environment variable (such as `EXAMPLE`). Thus, our `STARTUP` command: -::: +# Convert all of the "{{VARIABLE}}" parts of the command into the expected shell +# variable format of "${VARIABLE}" before evaluating the string and automatically +# replacing the values. +PARSED=$(echo "${STARTUP}" | sed -e 's/{{/${/g' -e 's/}}/}/g' | eval echo "$(cat -)") -```bash -java -Xms128M -Xmx{{SERVER_MEMORY}}M -jar {{SERVER_JARFILE}} +# Display the command we're running in the output, and then execute it with the env +# from the container itself. +printf "\033[1m\033[33mcontainer@pterodactyl~ \033[0m%s\n" "$PARSED" +# shellcheck disable=SC2086 +eval ${PARSED} ``` -Becomes: +### Breakdown -```bash -java -Xms128M -Xmx1024M -jar server.jar -``` +- Navigates to the working directory. +- Outputs the Java version for confirmation. +- Processes and expands the Pterodactyl `STARTUP` variable. +- Executes the startup command. -## Run the Command -The last step is to run this modified startup command, which is done with the line `${MODIFIED_STARTUP}`. +## Final Notes -### Note +- User home must be `/home/container` +- All Pterodactyl containers must have a user named `container` +- Always run as a **non-root** user in Pterodactyl containers. +- Build and test locally with: `docker build -t my-image .` +- Push images to Docker Hub or private registry and specify them in the egg under Docker Image, or run the image locally first if you want to ensure it functions as expected -Sometimes you may need to change the permissions of the `entrypoint.sh` file, on linux you can do this by executing `chmod +x entrypoint.sh` in the directory where the file is. +Creating a custom Docker image lets you fully control the server for uncommon games or special dependencies. \ No newline at end of file diff --git a/community/config/eggs/egg_config_parser.md b/community/config/eggs/egg_config_parser.md new file mode 100644 index 000000000..8be7ee0f0 --- /dev/null +++ b/community/config/eggs/egg_config_parser.md @@ -0,0 +1,101 @@ +# Configuration Files & Startup Detection + +[[toc]] + +After setting the basic egg details, you need to configure how Wings will manage the server process. This includes defining how to start and stop the server, how to handle logs, and how to automatically update any configuration files. These settings are found on the egg’s configuration page (under “Process Management”). + +## Startup Command + +The **Startup Command** is the exact command that will run to start your server. This is executed every time the server is launched (when the user clicks the Start button). You can include egg variables in this command by using the {{VARIABLE}} syntax. For example, a startup command might look like: +```json +java -Xms128M -XX:MaxRAMPercentage=95.0 -jar {{SERVER_JARFILE}} +``` +## Stop Command + +The **Stop Command** is the command or signal used to safely stop the server. By default, many eggs use `^C` (Control+C) to send an interrupt signal, which works for most console-based servers. If the application has a special shutdown command (for example, typing “stop” in a Minecraft server console), you can specify that here instead. Wings will execute this command when a user clicks the Stop button. + +## Log Configuration + +In most cases you can leave the **Log Configuration** field blank (which defaults to an empty JSON `{}`. By default, Wings will stream all output from the container’s console. The log configuration field is used only in advanced cases where the server’s output needs special handling (for example, if the server writes logs only to a file and not to STDOUT, you could configure Wings to tail that file). For typical eggs, this field remains empty. + +## Configuration Files + +::: warning +Using configuration file parsing is generally an advanced feature. If you are new to creating eggs, you may skip this section unless your egg needs it. +::: + +This section allows you to define files that Pterodactyl should automatically modify each time the server starts, to ensure certain settings are always applied. You can provide a JSON object mapping file names to the values that should be set in those files. Wings will then parse and update those files before the server fully starts. + +For example, consider a game that uses a `server.properties` file for its settings. You might add a configuration entry like this: + +```json +{ + "server.properties": { + "parser": "properties", + "find": { + "server-ip": "0.0.0.0", + "server-port": "{{server.build.default.port}}", + "max-players": "{{env.MAX_PLAYERS}}" + } + } +} +``` + +Each time the server starts, Wings checks if `server.properties` exists: +- If it exists, Wings will update those keys to the defined values (inserting the key if it’s missing). +- If the file doesn’t exist, Wings will create it with those keys and values. + +A more advanced example using a YAML file and wildcards: + +```json +{ + "config.yml": { + "parser": "yaml", + "find": { + "listeners[0].query_enabled": true, + "listeners[0].query_port": "{{server.build.default.port}}", + "listeners[0].host": "0.0.0.0:{{server.build.default.port}}", + "servers.*.address": { + "127.0.0.1": "{{config.docker.interface}}", + "localhost": "{{config.docker.interface}}" + } + } + } +} +``` + +## Parser Types +The available Parser Types are: +| Type | Description | +|------|-------------| +| `properties` | `.properties` files with key=value pairs | +| `ini` | Supports `[sections]` and `key=value` pairs | +| `yaml` | Handles nested keys, supports wildcards | +| `json` | Parses full structure, adds missing keys | +| `xml` | Can update attributes/values via xpath | +| `file` | Simple find/replace by line content (avoid if possible) | + +## Startup Configuration + +The Startup Configuration (sometimes called “startup detection”) is a JSON block where you define text that indicates when the server has finished starting up. This helps Pterodactyl know when to mark the server as “Online” (running) versus “Starting”. + +Example: + +```json +{ + "done": [ + "Done (", + "Server is ready" + ] +} +``` + +When any of the strings listed appear in the console output, Wings will consider the server to be fully started. This helps avoid marking the server as “running” before it’s actually ready. + +If this section is omitted, Wings relies on process status or timeout heuristics. + +## Copy Settings From + +The **Copy Settings From** option in an egg allows inheriting settings from another egg. This is useful for reducing duplication (e.g., different Minecraft flavors like Vanilla, Spigot, etc.). + +If you select another egg as a parent in “Copy Settings From,” any field in the current egg that you leave blank will be inherited from the parent egg. This is very useful when you have multiple eggs that share most of their configuration (for example, different versions or mods of the same game) diff --git a/community/config/eggs/egg_docker_images.md b/community/config/eggs/egg_docker_images.md new file mode 100644 index 000000000..17cda7167 --- /dev/null +++ b/community/config/eggs/egg_docker_images.md @@ -0,0 +1,85 @@ +# Egg Docker Images + +[[toc]] + + +The [Ptero-Eggs yolks repository](https://github.com/Ptero-Eggs/yolks) provides a variety of Docker images (called yolks) specifically designed for use with Pterodactyl eggs. + +These images provide the necessary runtime environments for game servers, bots, utilities, databases, and other services. +Pterodactyl eggs run within Docker containers. +The **Docker image** for an egg defines the base operating system and software environment available to the server. Choosing the right image is important: + +- Pterodactyl maintains an official repository of images (called **Yolks**) covering many common games, languages, and services. +- You may also use a [Custom Docker Image](creating_a_custom_image.md) for unique requirements + +## Categories of Yolks +### General Purpose + +| Image | Description | +|-------|-------------| +| `oses` | Base operating system images used to build other yolks. Includes core utilities for most container environments. | +| `installers` | Includes tools like `curl` and `wget`, commonly used to simplify and speed up installation scripts. | + +### Programming Languages + +| Image | Description | +|-------|-------------| +| `go` | An environment for Go (Golang) applications. Used for servers or tools written in Go. | +| `java` | Supports running Java applications, including Minecraft servers and Java-based tools. | +| `nodejs` | Provides Node.js and npm for JavaScript-based apps like bots, utilities, etc. | +| `python` | Used to run or build Python applications, scripts, or automation tools. | +| `rust` | Provides an environment for building or running applications developed in Rust. | + +### Databases + +| Image | Description | +|-------|-------------| +| `mariadb` | A drop-in replacement for MySQL, used for web apps and game server databases. | +| `mongodb` | A NoSQL database suited for dynamic data structures and fast performance. | +| `postgres` | Relational SQL database known for advanced features and data integrity. | +| `redis` | In-memory data structure store, used for caching and high-performance applications. | + +### Game Tools + +| Image | Description | +|-------|-------------| +| `steamcmd` | Allows downloading and managing game servers from Steam (e.g. ARK, CS:GO, Valheim). | +| `wine` | Runs Windows-based applications in Linux containers—useful for games that don’t have Linux builds. | + +### Other + +| Image | Description | +|-------|-------------| +| `mono` | Environment for .NET applications using the Mono runtime. Supports C# programs and older .NET games. | +| `voice` | Optimized for voice servers or tools like TeamSpeak or Mumble. | + +--- + +## Architecture Support + +Most yolks support both `amd64` and `arm64` architectures. Always check the image documentation to confirm compatibility with your server hardware. + +## Custom Images + +Requirements: +- Must include all runtime dependencies. +- Must have a `container` user with UID 1000 and home `/home/container`. +- Use Alpine/Debian minimal bases where possible. + +If you want to build your own Docker image for an egg, refer to the [Creating a Custom Docker Image](creating_a_custom_image.md) guide for best practices on building and tagging images for Pterodactyl. + +## Providing Multiple Images + +An egg can offer **multiple Docker images** for the server owner to choose from. To do this, list each image on a new line in the egg’s Docker Image field (in the egg configuration). You can optionally prepend a display name to each image using the format: +``Display Name|docker/image:tag`` + +For example, you might offer two Java images for a Minecraft egg: +- Java 17|ghcr.io/pterodactyl/yolks:java_17 +- Java 21|ghcr.io/pterodactyl/yolks:java_21 + +This would present the user with a dropdown choice between **“Java 17”** and **“Java 21”** when deploying the server. The text before the `|` is the friendly name shown in the panel, and the text after the `|` is the actual Docker image to use. + +::: tip +If you’re not sure which image to use for your egg, start with one of the [Official Yolks](https://github.com/Ptero-Eggs/yolks) + that closely matches your server’s requirements. These images are maintained by the community and cover most common use cases. +::: \ No newline at end of file diff --git a/community/config/eggs/egg_install_script.md b/community/config/eggs/egg_install_script.md new file mode 100644 index 000000000..d4b6cba3e --- /dev/null +++ b/community/config/eggs/egg_install_script.md @@ -0,0 +1,85 @@ +# Egg Install Script + +[[toc]] + +## What is the Install Script? + +The install script is where the **egg magic** happens. + +When you click on the **Install Script** tab for the egg, you will see four main parts: + +- A large text area to write the script. (Install Script) + +- A field where you can select a different eggs script, default set to 'None' (Copy Script From) + +- A field to select the **Docker image** in which the install script will run (Script Container). + +- A field used to specify the entrypoint command used for the script, usually 'bash' (Script Entrypoint Command) + +You can choose a special Docker image for the installation process (separate from the server’s runtime image). Pterodactyl provides some “installer” images (Alpine or Debian based) that include common utilities like `curl`, `wget`, `unzip`, `git`, etc., to help with installation tasks. If you’re not sure, use one of the official installer images: + +- `ghcr.io/ptero-eggs/installers:alpine` + +- `ghcr.io/ptero-eggs/installers:debian` + +- `ghcr.io/ptero-eggs/installers:ubuntu` + +Then, in the script text area, write the shell commands needed to set up the server. + +::: warning +Anything you install or change **outside of `/mnt/server`** in the install container will **not persist** to the runtime server. The install script runs in a temporary environment. Only the `/mnt/server` directory (which corresponds to the server’s file directory) is transferred to the actual server container. If your server needs specific system packages or libraries, those must be installed in the **runtime Docker image**, not just in the install script. +::: + +**How the install process works:** + +1. **Create the server directory:** The script typically starts by making sure the `/mnt/server` directory exists and is the current working directory. + - For example, you might use: + ```bash + mkdir -p /mnt/server + cd /mnt/server + ``` + - (In many official scripts, the container’s working directory is already set to `/mnt/server`, but it’s good practice to ensure it.) + +2. **Download and prepare files:** Fetch any necessary files (server binaries, mods, configs, etc.) from the internet or local sources. + - Common tools for this are `curl`, `wget`, `git clone`, or using a command pipeline like `curl ... | tar ...`. + - For example, you might download a ZIP of the server software and then unzip it. + +3. **Set up configurations:** If your server requires an initial configuration file or certain directory structure, you can create those here. + - For instance, you might generate a default config file, or rename files, etc. + - You can also use the values of variables by referencing environment variables (e.g. `${MAX_PLAYERS}` in the script will use the value from a custom egg variable if one exists). + +4. **Install any additional dependencies (if needed for installation):** In some cases, the install process itself might require extra tools or packages. Since the official installer images come with common tools, this is rarely needed, but you could install others (e.g., `apk add ...` or `apt install ...`) in the install container. Remember, these tools won’t be present in the runtime container, so this step is only for things needed *during installation* (not for actually running the server). + +## Example Install Script + +```sh +#!/bin/bash +# Create and navigate to the server directory +mkdir -p /mnt/server +cd /mnt/server || exit 1 + +# Install dependencies required for installation +apt update && apt install -y unzip wget + +# Download necessary files +wget -O game-server.zip "https://example.com/game-server.zip" +unzip game-server.zip +rm game-server.zip + +# Set up configuration +echo "max_players=32" > config.cfg + +# Ensure correct permissions +chown -R containeruser:containergroup /mnt/server +chmod -R 755 /mnt/server +``` + +## What Happens After Installation? + +When the install script finishes running: + +- All files and folders **inside** `/mnt/server` (the server’s directory) are retained and moved to the server’s persistent storage. + +- The install container is destroyed. Then the server’s normal runtime container (using the Docker image specified in the egg’s configuration) will start up, and it will have all the files that were in `/mnt/server` available. + +In summary, the install script’s job is to populate `/mnt/server` with everything the server needs. Once that’s done, those files persist, and then the server can be launched in the proper environment. diff --git a/community/config/eggs/egg_variables.md b/community/config/eggs/egg_variables.md new file mode 100644 index 000000000..eef5864dd --- /dev/null +++ b/community/config/eggs/egg_variables.md @@ -0,0 +1,71 @@ +# Egg Variables + +[[toc]] + +One powerful feature of eggs is the ability to define **variables** that can be used to customize the server’s startup and configuration without editing the startup command directly. Egg variables are exposed as environment variables to the server and can be referenced in the install script or config files. + +To manage an egg’s variables, create the egg (or edit an existing one) and navigate to the **Variables** tab on the egg configuration page. + +![](../../../.vuepress/public/community/config/eggs/Pterodactyl_Create_New_Egg_Variables.png) + +## Types of Egg Variables + +- **Default Variables:** These are provided by the Panel/Wings automatically for every server. (You do **not** need to create these; they always exist.) + +- **Custom Variables:** These are defined by you on the egg’s Variables tab. + +## Default Variables + +These are injected into every server environment by default and can be referenced using the following syntaxes: + +- In the startup command, reference it as {{VARIABLE}}. +- In scripts: $VARIABLE_NAME or {{server.build.default.VARIABLE_NAME}} +- In configuration parser entries, reference it as {{env.VARIABLE}}. + +| Variable Name | Description | Example | +|-----------------------------|--------------------------------------------------------------------------|--------------------------------| +| `TZ` | Time Zone set in the panel's `.env` file | `Etc/UTC` | +| `STARTUP` | The actual resolved startup command for the server | `./run.sh -arg1` | +| `SERVER_MEMORY` | Allocated memory for the server in megabytes | `1024` | +| `SERVER_IP` | The IP address assigned to the primary allocation | `192.168.1.2` | +| `SERVER_PORT` | The main port assigned to the server | `27015` | +| `P_SERVER_LOCATION` | The name of the location (set by the admin in the panel) | `Amsterdam-01` | +| `P_SERVER_UUID` | UUID of the server instance (used for tracking within Wings) | `ab12cd34-5678-90ef-ghij-klmn12345678` | +| `P_SERVER_ALLOCATION_LIMIT` | The maximum number of allocations available to this server (if set) | `3` | +| `USER` | The user executing processes inside the container | `container` | +| `HOME` | The home directory inside the container | `/home/container` | + + +## Custom Variables + +Each variable allows you to define: +- The Environment Variable, For example: `MAX_PLAYERS` +- A default value +- Description (shown to the user in the panel) +- Validation Rules +- Whether it is viewable or editable by the user + +## Creating a New Variable +When creating a new custom variable, you will provide: + +- **Name:** A friendly name for the variable (e.g. “Max Players”). + +- **Description:** A description shown to the user (explain what the variable does). + +- **Environment Variable:** The actual environment variable name used in code (use **UPPERCASE** letters, numbers, and underscores only). For example, `MAX_PLAYERS`. This is the name that will be referenced in the startup command or configuration files. + +- **Default Value:** (Optional) A default value for this variable. This will be used if the user doesn’t input anything else. + +- **User Permissions:** Whether the user can view and/or edit this variable on their server: + - *Users Can View* – If set, the user can see this variable (and its value) in their server’s settings. + - *Users Can Edit* – If set, the user can change the value of this variable from the default. + (If neither option is enabled, the variable is essentially hidden from the user’s front-end view, though it still exists in the server’s environment.) + +### Validation Rules +- **Rules:** Validation rules for the user’s input. This uses Laravel’s validation rule format. For example, `required|string|between:1,10` means the value is required, must be a string, and 1 to 10 characters in length. You can also use regex patterns. For instance, to require a value ending in “.jar”, you could use a rule like `required|regex:/^([\w\d._-]+)(\.jar)$/` which will only accept values that match that pattern. + +::: warning +Even if you choose not to allow users to view or edit a variable, **be aware that it’s not truly secret from the user**. Advanced users could still find the variable’s value (since it exists in the server environment). Typically, hiding a variable is just to prevent casual users from changing or seeing it when it’s not necessary for them to interact with (for example, a variable that is used internally by the egg). +::: + +After creating custom variables, both the custom and default variables can be seen when viewing the server’s startup in the Panel (in both Admin and client views). The startup command preview will show these variables substituted with their actual values.