Durk’s Ultimate Guide to Hosting Level 5 Space Station 14 Servers Using Pterodactyl (without losing your mind in the process)
So, like me, you’ve decided to deploy your entire infrastructure in containers using a game server panel and a bunch of questionable workarounds. Well, you’re in luck! My predecessor, Aves Maximus, and I have already done the hard work for you. All you need to do is follow this (somewhat) simple guide, where I’ll walk you through:
- Installing Pterodactyl Wings and Panel
- Configuring multiple nodes
- Installing eggs for:
- PostgreSQL
- Prometheus & Grafana
- SS14.Admin
- CDN
- Game servers
- Redbot with OOC relays
- WikiJS
- NGINX configs for reverse proxying
- Setting up replays
- DNS Configuration
You will need:
- Basic Linux CLI knowledge -- You can copy and paste everything in this guide, but experience helps.
- A SSH Client -- I recommend MobaXterm for Windows.
- A Dedicated Server -- Recommended: Hetzner (EU) or H4Y (US). A VPS works, but high player counts will bottleneck on single-core performance.
- Linux Operating System -- Preferably Ubuntu 24.04 LTS, as this guide assumes you’re using it.
- A Domain Name -- I’ll be using Namecheap, but any registrar (e.g., Cloudflare) works.
- A dedicated IP -- Required for proper networking and SSL. There are workarounds for dynamic and shared IPs, but I will not be going through them in this guide.
- A few hours, a cup of coffee, and a pack of cigarettes.
- Hetzner Robot, Rescue & Installation
- Namecheap Domain Registration
- Pterodactyl Getting Started
- Wiki.js Documentation
The following guides will most likely be inaccurate as they do not pertain to hosting with Pterodactyl, you may still find them useful for general debugging.
- SS14 Server Hosting
- SS14.Admin Setup
- SS14.Changelog Setup -- We use Delta-V's Changelog Webhook, I will make a guide for this in the future but currently you will have to figure it out yourself.
- Robust.CDN Setup
- Replays Setup
- Redbot Setup
I recommend doing the following steps after you first install Ubuntu: Run the following commands to update everything:
sudo apt-get update
sudo apt-get upgrade
sudo apt-get dist-upgradeThen
Alias trash to rm, this will stop you from doing stupid shit and permenantly deleting files from your server on accident.
sudo apt install trash-cli
echo "alias rm='trash-put'" >> ~/.bashrc
source ~/.bashrcI also recommend disabling UFW using
sudo ufw disableas it will constantly try to get in the way.
You must be logged in as root for this section.
Run
bash <(curl -s https://pterodactyl-installer.se)to start the installer.
Enter 2 to install both wings and the panel.
You will be prompted to enter the database name, database username and database password. You can hit enter for each of these options to skip through them, the install script will handle all this for you.
Next you'll be prompted to set a timezone, you can find a list of all options @ https://www.php.net/manual/en/timezones.america.php.
I'll be using America/Chicago.
You will then enter an email for your SSL Certificates, I recommend a business email if you have one, i'll be using goobstation14@gmail.com.
You will then setup your admistrator account for the panel, you should use your normal email, fill out the username and password with whatever you like but write it down, you will need this to access the panel.
You will now set the FQDN of your panel, for example panel.goobstation.com. From here you will need to add an A DNS record to your domain directed at your server's ip, which will look something like this:
DNS records can take a while to populate, if you just entered them give it a few minutes before continuing.
You'll be asked a few questions afterwards, you should answer with the following:
* Do you want to automatically configure UFW (firewall)? (y/N): N
* Do you want to automatically configure HTTPS using Lets Encrypt? (y/N): y
* I agree that this HTTPS request is performed (y/N): y
* Initial configuration completed. Continue with installation? (y/N): Y
* Enable sending anonymous telemetry data? (yes/no) [yes]: yes
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Please read the Terms of Service at
https://letsencrypt.org/documents/LE-SA-v1.4-April-3-2024.pdf. You must agree in
order to register with the ACME server. Do you agree?
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
(Y)es/(N)o: Y
* Installation of panel completed. Do you want to proceed to wings installation? (y/N): Y
* Do you want to automatically configure UFW (firewall)? (y/N): N
* Do you want to automatically configure a user for database hosts? (y/N): N
* Do you want to automatically configure HTTPS using Lets Encrypt? (y/N): Y
* Set the FQDN to use for Let's Encrypt (node.example.com):For the final question you will enter the domain name you want to use for the node, I'll be using hyperion.goobstation.com. You'll have to setup another A DNS record for this as well, same as shown before.

More questions to answer:
* Do you want to automatically configure UFW (firewall)? (y/N): N
* Do you want to automatically configure a user for database hosts? (y/N): N
* I agree that this HTTPS request is performed (y/N): y
* Enter email address for Let's Encrypt: youremail@email.com
* Proceed with installation? (y/N): yInstallation is complete! You should be able to view the panel at panel.yourdomain.com now! You won't be able to deploy any servers yet, but you are close!
Login to your panel, in the top right you should now see a gear icon, click this to enter the admin section.
From here you'll have to add a location, hit locations on the left side, create new, and enter a short code for your location. This can be anything, I'll set mine to eu.germany.
Now head to the Nodes section, click create new. Here you'll have to enter some information,
Name: Whatever you want, mine will be Hyperion. Description: Whatever you want once again, or nothing. Node Visiblity: Public FQDN: You set this up a moment ago while installing wings, make sure you use the same link. Communicate Over SSL: Use SSL Connection Behind Proxy: Not Behind Proxy
This next section will depend on your server setup, I won't be running anything outside of pterodactly, so I'll give most of my resources to wings, make sure to leave a little head room for other services in the background.
Daemon Server File Directory: /var/lib/pterodactyl/volumes Total Memory: System Memory minus 2-4 GB Memory Over-Allocation: 0 Total Disk Space: System Total Disk Space minus ~20 GB Disk Over-Allocation: 0 Daemon Port: 8080 Daemon SFTP Port: 2022
Now click create node in the bottom right, and it should pop you into the next page. Click Configuration at the top, and copy all the text, it should appear to be something like this:
debug: false
uuid: *************
token_id: *************
token: *************
api:
host: 0.0.0.0
port: 8080
ssl:
enabled: true
cert: /etc/letsencrypt/live/hyperion.goobstation.com/fullchain.pem
key: /etc/letsencrypt/live/hyperion.goobstation.com/privkey.pem
upload_limit: 100
system:
data: /var/lib/pterodactyl/volumes
sftp:
bind_port: 2022
allowed_mounts: []
remote: 'https://panel.goobstation.com'
Head back to your server's terminal and enter the following command:
sudo nano /etc/pterodactyl/config.ymlPaste the contents of your clipboard and hit Ctrl+X and then Y to save and exit. Now run:
sudo systemctl start wingsYou can go back to the main nodes tab in the panel and you should see a green heart next to the node.
Next you'll have to allocate some ports for your eggs, re-enter the node and hit Allocation.
In IP Address enter the IP for your node, and give it a few ports in Ports, I usually use ports in the range of 20000-30000. Hit sumbit, and you allocations should look a little something like this:

Congrats! You're now ready to start installing eggs.
Run
sudo nano /etc/nginx/proxy_paramsand paste
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
hit Ctrl+X and Y to save and exit, then run
sudo mkdir /etc/nginx/sites-available/containersFrom within the admin section on the panel, head to Nests on the bottom left, click create new, and enter a name.
Now head back to the main nests page, click import egg, set the associated nest to goob, and select your egg file.
You will have to do this several times for each egg, all of the eggs we will be using can be found here: https://github.com/Goob-Station/Eggs
Head to the Servers tab in the admin panel, click Create New enter the following information
Server Name: SS14 CDN Server Owner: Enter the name for you admin account, it should autofill Start Server when Installed: False Default Allocation: Choose whatever port you'd like Memory: 0 (I recommend watching this overtime, figure out what it sticks around and set it a little above that) Disk Space: 0 (same as above) Nest: Your Nest Egg: SS14 Cdn
Hit create server.
Head to your domain registar, create a new A record, fill it like before but with the CDN, and wait a few minutes.

In your terminal run
sudo nano /etc/nginx/sites-available/containers/cdn.confEnter the following config, make sure to edit server_name and proxy_pass
server {
listen 80;
server_name cdn.yourdomain.com;
location / {
proxy_pass http://your_ip:port;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
include /etc/nginx/proxy_params;
client_max_body_size 512m;
}
}
then run
sudo ln -s /etc/nginx/sites-available/containers/cdn.conf /etc/nginx/sites-enabled/
sudo certbot --nginx -d cdn.yourdomain.com
sudo systemctl reload nginxHead to your normal ptero panel, hit the CDN server, go to files, and open the appsettings.json
Here is a basic config, make sure to modify values to match your server. UpdateToken is like a password, make it unique and complex and do NOT give it out.
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning",
"Robust": "Information"
}
},
"Manifest": {
"FileDiskPath": "/home/container/builds",
"DatabaseFileName": "/home/container/manifest.db",
"Forks": {
"MyCoolFork": {
"UpdateToken": "*************",
"PruneBuildsDays": 90,
"DisplayName": "My Cool Fork",
"BuildsPageLink": "https://myforkswebsite.com",
"BuildsPageLinkText": "My Fork's Cool Website"
}
}
},
"Cdn": {
"DatabaseFileName": "/home/container/content.db",
"StreamCompressLevel": 5,
"DefaultFork": "MyCoolFork"
},
"BaseUrl": "https://cdn.yourdomain.com/",
"PathBase": "/",
"AllowedHosts": "*",
"Urls": "http://0.0.0.0:your_port/",
}
From here you'll have to headover to your forks github, go to /Tools/publish_multi_request.py and modify the following values:
#
# CONFIGURATION PARAMETERS
# Forks should change these to publish to their own infrastructure.
#
ROBUST_CDN_URL = "https://cdn.yourdomain.com/"
FORK_ID = "MyCoolFork"Now head to the settings of the repository, hit Secrets and variables, Actions, and New repository secret.
Enter PUBLISH_TOKEN for the Name, and the value you set for UpdateToken in the previous config for the Secret, and then hit Add secret.
Navigate to the Actions tab of your repo, hit Publish, and then and Run workflow. This will take around 10 minutes to complete.
Finally head over to your CDN's page for the fork, (ex: https://cdn.goobstation.com/fork/GoobLRP)
You should see your build now and your finished setting up the CDN!
Go to your nests tab in the admin panel and import the Postgres egg from https://github.com/pelican-eggs/database/blob/main/sql/postgres/egg-postgres16.json
Head to the Servers tab in the admin panel, click Create New enter the following information
Server Name: Postgres Database Server Owner: Enter the name for you admin account, it should autofill Start Server when Installed: True Default Allocation: Choose whatever port you'd like Memory: 0 (I recommend watching this overtime, figure out what it sticks around and set it a little above that) Disk Space: 0 (same as above) Nest: Your Nest Egg: Postgres Service Variables:
- Superuser Name: pterodactyl
- Superuser Password: You MUST modify this value. If you do not create a password anyone will be able to view and modify your databases with the default password. This is very bad.
Hit create server.
Head to your domain registar, create a new A record, fill it like before but with the CDN, and wait a few minutes.

In your terminal run
sudo nano /etc/nginx/sites-available/containers/postgres.confEnter the following config, make sure to edit server_name and proxy_pass
server {
listen 80;
server_name postgres.yourdomain.com;
location / {
proxy_pass http://your_ip:port;
include /etc/nginx/proxy_params;
}
}
then run
sudo ln -s /etc/nginx/sites-available/containers/postgres.conf /etc/nginx/sites-enabled/
sudo certbot --nginx -d postgres.yourdomain.com
sudo systemctl reload nginxGo back to the ptero panel, go into the Postgres insance, head to Files, postgres_db, pg_hba.conf.
At the bottom of the line there should be a line that appears like
# Custom rules
host all all 0.0.0.0/32 md5
modify it to look like
# Custom rules
host all all all md5
You're now finished with your Postgres setup!
Head to the Servers tab in the admin panel, click Create New enter the following information
Server Name: Game Server Server Owner: Enter the name for you admin account, it should autofill Start Server when Installed: True Default Allocation: Choose whatever port you'd like CPU Limit: 400% (100% is equal to one core) CPU Pinning: 0-3 (This locks the container to use only these cores, this sometimes help with servers fighting over the same thread, if you make multiple servers make sure you do not pin them to the same cores) Memory: 12000 MiB Disk Space: 0 Nest: Your Nest Egg: SS14 Server (CDN) Service Variables:
- Server Name:
Durk's Super Cool Awesome ServerName that will appear on the hub. - Server Tickrate:
30If you are a low playercount server with good hardware, you can bump this up to 60, otherwise leave it at 30. - Public Server:
TrueThis will make you show up on the hub/s. - Default Admin User:
HerobrineYou will need this to run commands ingame, make it your SS14 Username. - Server Description:
My awesome server!This is the description that will appear on the hub - Hub URLs:
https://hub.spacestation14.com/,https://web.networkgamez.com/,https://hub.singularity14.co.uk/ - Fork ID: This is the Fork ID you made in the CDN, its the last part of the URL.
- Build ID: Leave this blank for latest build
Hit create server.
Head to your domain registar, create a new A record, fill it like before but with the CDN, and wait a few minutes.

In your terminal run
sudo nano /etc/nginx/sites-available/containers/gameserver.confEnter the following config, make sure to edit server_name and proxy_pass
server {
listen 80;
server_name gameserver.yourdomain.com;
location / {
proxy_pass http://your_ip:port;
include /etc/nginx/proxy_params;
proxy_hide_header Access-Control-Allow-Origin;
add_header 'Access-Control-Allow-Origin' '*' always;
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS' always;
add_header 'Access-Control-Allow-Headers' 'Origin, Content-Type, Accept' always;
}
}
then run
sudo ln -s /etc/nginx/sites-available/containers/gameserver.conf /etc/nginx/sites-enabled/
sudo certbot --nginx -d server.yourdomain.com
sudo systemctl reload nginxHead back over to your game server in ptero, click Files, datadir, server_config.toml
It will probably be empty, here we will need to input some basic configs to get it up and running.
[net]
tickrate = 30
port = 00000 # Enter your game server's port
[status]
enabled = true
bind = "*:00000" # Enter your game server's port
connectaddress = "udp://0.0.0.0:00000" # Enter your game server's IP:Port
[game]
hostname = "Durk's Super Cool Awesome Server"
desc = "My awesome server!"
soft_max_players = 64
[hub]
advertise = 1
tags = "lang:en, rp:low, region:eu_w" # You can find a list of all tags @ https://docs.spacestation14.com/en/robust-toolbox/server-http-api.html#standard-tags
server_url = "ss14s://gameserver.yourdomain.com" # Enter your domain
hub_urls = "https://hub.spacestation14.com/,https://web.networkgamez.com/,https://hub.singularity14.co.uk/"
[database]
engine = "postgres"
pg_host = "postgres.yourdomain.com"
pg_port = 00000 # Enter the port for your database
pg_database = "mycoolserver" # This can be anything
pg_username = "pterodactyl" # Ideally you would create a seperate user in your postgres that only has access to the above database, but you can use the superuser
pg_password = "***********" # Password for your postgres, if you forgot it you can go back to the postgres instance and hit startup to view it.
[console]
login_host_user = "Herobrine"
loginlocal = true
[auth]
mode = 1
# Only enter the following if you intend to setup Prometheus and Grafana
[metrics]
enabled = 1
host = "*"
port = 00000 # Enter your game server's port
# Only enter the following if you intend to setup replays
[replay]
auto_record = true
auto_record_temp_dir = "/replays-recording"
auto_record_name = "durksawesomeserver_{year}_{month}_{day}-{hour}_{minute}-round_{round}.zip" # Modify the name at the start to whatever you want
directory = "/replays-complete/DurksAwesomeServer" # Here as wellStart your server and... boom! you have a server up and running! congrats!
go fuck yourself ig
sudo groupadd pteronginx
sudo usermod -aG pteronginx root
sudo usermod -aG pteronginx www-data
sudo usermod -aG pteronginx pterodactyl
sudo mkdir /var/lib/pterodactyl/mounts
sudo mkdir /var/lib/pterodactyl/mounts/replays-recording
sudo mkdir /var/lib/pterodactyl/mounts/replays-complete
sudo chown -R 999:pteronginx /var/lib/pterodactyl/mounts
sudo chown -R 999:pteronginx /var/lib/pterodactyl/mounts/replays-recording
sudo chown -R 999:pteronginx /var/lib/pterodactyl/mounts/replays-complete
sudo chmod -R 770 /var/lib/pterodactyl/mounts
sudo chmod -R 770 /var/lib/pterodactyl/mounts/replays-recording
sudo chmod -R 770 /var/lib/pterodactyl/mounts/replays-complete
sudo chmod g+s /var/lib/pterodactyl/mounts
sudo chmod g+s /var/lib/pterodactyl/mounts/replays-recording
sudo chmod g+s /var/lib/pterodactyl/mounts/replays-complete
sudo setfacl -d -m g::rwX /var/lib/pterodactyl/mounts
sudo setfacl -d -m g::rwX /var/lib/pterodactyl/mounts/replays-recording
sudo setfacl -d -m g::rwX /var/lib/pterodactyl/mounts/replays-completeill be honest i just tried 30 different commands until replays started working, you probably dont even need half of these but whatever.