Monorepo for managing multiple dedicated game servers on Linux using Ansible for deployment and optionally Terraform for cloud infrastructure provisioning (DigitalOcean).
| Game | Port | Protocol | Service |
|---|---|---|---|
| Palworld | 8211 | UDP | palworld.service |
| Terraria | 7777 | TCP | terraria.service |
| Factorio Co-op | 34197 | UDP | factorio-coop.service |
| Factorio PvP | 34198 | UDP | factorio-pvp.service |
- Node.js (v18+): Required for deployment scripts
- Ansible: Installing Ansible
- SSH access to your game server
- Terraform (optional, for cloud deployment): Install Terraform
game-servers-linux/
├── servers/ # Individual game server configurations
│ ├── palworld/
│ │ ├── ansible/ # Ansible playbook, roles, inventory
│ │ └── terraform/ # Terraform config for DigitalOcean
│ ├── terraria/
│ │ ├── ansible/
│ │ └── terraform/
│ └── factorio/
│ ├── ansible/
│ │ └── roles/factorio/files/saves/ # Seed save files
│ └── terraform/
├── status-app/ # Server status web application
│ ├── src/ # Preact SPA source
│ ├── server.ts # Fastify API server
│ └── ansible/ # Deployment for status app
├── scripts/
│ ├── deploy.ts # Deployment script
│ ├── backup-saves.ts # Backup saves from server
│ └── restore-save.ts # Restore saves to server
├── backups/ # Local save backups (gitignored)
├── servers.yml # Server definitions
├── host.yml # SSH connection details (gitignored)
├── host.dist.yml # Example host configuration
├── terraform.tfvars # Shared Terraform variables (gitignored)
├── terraform.tfvars.dist # Example Terraform variables
└── package.json
-
Clone the repository:
git clone <repository-url> cd game-servers-linux
-
Install dependencies:
npm install
-
Copy
host.dist.ymltohost.ymland configure your server details:ansible_host: "192.168.0.49" ansible_user: "your_username" ansible_ssh_private_key_file: "/home/you/.ssh/id_rsa" ansible_become_password: "your_sudo_password"
-
Install Ansible collections:
cd servers/<game>/ansible ansible-galaxy collection install -r roles/requirements.yml --force
-
Copy
terraform.tfvars.disttoterraform.tfvarsand configure:do_token = "your_digitalocean_api_token" ssh_key_name = "your-ssh-key-name"
-
Generate an SSH key pair (if needed):
ssh-keygen -b 4096 -t rsa -C "your_email@example.com" -
Import your SSH public key to DigitalOcean:
- Navigate to: Settings > Security > SSH Keys > Add SSH key
-
Generate a Personal Access Token on DigitalOcean:
- Navigate to: API > Tokens > Generate New Token (with read & write scopes)
-
Initialize and apply Terraform:
cd servers/<game>/terraform terraform init terraform apply -auto-approve
-
To destroy cloud infrastructure:
terraform destroy -auto-approve
Deploy all enabled servers:
npm run deploy:allDeploy specific servers:
npm run deploy:palworld
npm run deploy:terraria
npm run deploy:factorioBackup current saves from the server:
npm run backup-savesRestore a save to the server:
npm run restore-save -- --game factorio-coop --name MadMadWorld.zipStart/stop/restart a service:
ssh user@server "sudo systemctl start factorio-coop.service"
ssh user@server "sudo systemctl stop factorio-coop.service"
ssh user@server "sudo systemctl restart factorio-coop.service"View logs:
ssh user@server "journalctl -u factorio-coop.service -f"Defines all game servers with display names, ports, services, and connection instructions.
Located at servers/<game>/ansible/inventory.yml. Contains server-specific variables like world settings, max players, and admin lists.
Example (Factorio):
factorio_admins:
- username1
- username2
factorio_instances:
- name: "coop"
display_name: "My Co-op Server"
port: 34197
save_file: "MadMadWorld.zip"
max_players: 16Located at servers/<game>/ansible/roles/<game>/defaults/main.yml. Contains default values for all configuration options.
A web-based status page showing real-time server status, built with Preact and Fastify.
Run locally for development:
npm run devThis starts both:
- Vite dev server on port 5173 (frontend)
- Fastify API on port 3000 (backend)
Build and deploy to the game server:
npm run build
npm run deploy:statusThe status app runs as a systemd service behind nginx on the game server.
To wipe progress and restore original maps, set in inventory.yml:
factorio_reset_to_seed: trueThen run npm run deploy:factorio. Warning: This deletes all backups and overwrites current saves. Set back to false after running.
Enabled by default to prevent game stalls during autosaves.
| Component | Technology |
|---|---|
| Deployment Scripts | Node.js, TypeScript |
| Server Configuration | Ansible |
| Cloud Infrastructure | Terraform, DigitalOcean |
| Status App Frontend | Preact, Vite |
| Status App Backend | Fastify |
| Game Servers | Systemd services |
| Firewall | UFW |
pip3 install passlib- Edit the relevant
inventory.ymlordefaults/main.yml - Run
npm run backup-saves(recommended) - Run
npm run deploy:<game>
ssh user@server "systemctl status factorio-coop.service"Use the backup/restore scripts:
# On old setup
npm run backup-saves
# Copy backups/ directory to new setup, then:
npm run restore-save -- --game factorio-coop --name MadMadWorld.zipNote: This section only applies if you're running game servers on a local machine (e.g., a home server). If you deployed via Terraform to DigitalOcean, your server already has a public IP and these steps are not needed.
To allow friends to connect from the internet to your home server, you need to configure port forwarding on your router.
| Game | Port | Protocol |
|---|---|---|
| Palworld | 8211 | UDP |
| Terraria | 7777 | TCP |
| Factorio Co-op | 34197 | UDP |
| Factorio PvP | 34198 | UDP |
| Status App | 80 | TCP |
-
Find your server's local IP address:
hostname -I | awk '{print $1}'
-
Access your router's admin panel (typically
192.168.0.1or192.168.1.1) -
Navigate to Port Forwarding settings (may be under "NAT", "Virtual Servers", or "Gaming")
-
Create port forwarding rules for each game server:
- External Port: Game port (e.g., 34197)
- Internal IP: Your server's local IP
- Internal Port: Same as external port
- Protocol: UDP or TCP (see table above)
-
Find your public IP address:
curl -s ifconfig.me
-
Share your public IP with friends to connect
- Only forward ports for games you actively use
- Consider using a dynamic DNS service if your public IP changes frequently
- The game server firewall (UFW) already restricts access to only the necessary ports
- For additional security, some games support password protection (configured in
inventory.yml)