Multi-Game Server Hosting on Single VPS

Hosting multiple game servers on a single VPS requires careful resource planning, port management, and containerization strategies. This guide covers resource allocation, Docker container deployment, systemd service management for multiple servers, port forwarding configuration, and comprehensive monitoring. Proper implementation allows cost-effective hosting of 5-20+ game servers on a single powerful machine.

Table of Contents

Planning and Resources

Capacity Analysis

Calculate VPS capacity:

# Example calculation for various servers
TOTAL_CORES=16
TOTAL_RAM=64GB
TOTAL_BANDWIDTH=1Gbps

# Per-server estimates
declare -A SERVER_REQS=(
    ["valheim_50"]="2:4:200"      # CPU: 2 cores, RAM: 4GB, Bandwidth: 200 Mbps
    ["rust_100"]="4:16:500"       # CPU: 4 cores, RAM: 16GB, Bandwidth: 500 Mbps
    ["factorio_20"]="1:2:100"     # CPU: 1 core, RAM: 2GB, Bandwidth: 100 Mbps
    ["terraria_50"]="1:1:50"      # CPU: 1 core, RAM: 1GB, Bandwidth: 50 Mbps
    ["7dtd_50"]="2:8:300"         # CPU: 2 cores, RAM: 8GB, Bandwidth: 300 Mbps
)

# Validate capacity
echo "Server Configuration:"
CPU_TOTAL=0
RAM_TOTAL=0

for SERVER in "${!SERVER_REQS[@]}"; do
    IFS=':' read -r CPU RAM BW <<< "${SERVER_REQS[$SERVER]}"
    CPU_TOTAL=$((CPU_TOTAL + CPU))
    RAM_TOTAL=$((RAM_TOTAL + RAM))
    echo "$SERVER -> CPU: ${CPU} cores, RAM: ${RAM}GB, BW: ${BW}Mbps"
done

echo ""
echo "Total Resources:"
echo "  CPU: $CPU_TOTAL / $TOTAL_CORES cores"
echo "  RAM: ${RAM_TOTAL}GB / 64GB"

if [ $CPU_TOTAL -le $TOTAL_CORES ] && [ $RAM_TOTAL -le 64 ]; then
    echo "✓ Configuration fits within VPS capacity"
else
    echo "✗ Configuration exceeds VPS capacity"
fi

System Architecture

Recommended multi-server architecture:

                    ┌─────────────┐
                    │   VPS Host  │
                    │  (16 cores) │
                    │  (64GB RAM) │
                    └──────┬──────┘
                           │
        ┌──────────────────┼──────────────────┐
        │                  │                  │
    ┌───▼───┐          ┌───▼───┐         ┌───▼───┐
    │Valheim│          │ Rust  │         │  7DTD │
    │ (ctr1)│          │ (ctr2)│         │ (ctr3)│
    └───────┘          └───────┘         └───────┘
    │ :2456-2458       │ :28015-28016    │ :26900-26901
    │ :4GB RAM         │ :16GB RAM       │ :8GB RAM
    │ 2 cores          │ 4 cores         │ 2 cores
    └──────────────────┴──────────────────┴──────────

    Network: Custom bridge (172.20.0.0/16)
    Storage: /home/gameservers/
    Monitoring: Prometheus + Grafana

Resource Allocation

Create resource allocation plan:

# Create resource tracking file
sudo tee /home/gameservers/RESOURCE_ALLOCATION.txt > /dev/null <<'EOF'
# Multi-Game Server Resource Allocation

# System Baseline (required)
System_Cores: 2
System_RAM_GB: 4
System_Disk_GB: 20

# Available for servers
Available_Cores: 14
Available_RAM_GB: 60
Available_Bandwidth_Mbps: 900

# Server Allocations
# Name          | Cores | RAM_GB | Port_Range    | Player_Count | Status
valheim_01      | 2     | 4      | 2456-2458     | 50           | Active
rust_01         | 4     | 16     | 28015-28016   | 100          | Active
factorio_01     | 1     | 2      | 34197         | 255          | Active
terraria_01     | 1     | 1      | 7777          | 50           | Standby
7dtd_01         | 2     | 8      | 26900-26901   | 50           | Active
csgo_01         | 2     | 2      | 27015         | 64           | Standby
minecraft_01    | 2     | 8      | 25565         | 20           | Standby

# Totals
Allocated_Cores: 14 / 14
Allocated_RAM: 41 / 60 GB
Spare_Capacity: 19GB RAM, 0 cores
EOF

cat /home/gameservers/RESOURCE_ALLOCATION.txt

Docker Setup for Game Servers

Install Docker:

sudo apt-get update
sudo apt-get install -y docker.io docker-compose

# Enable and start Docker
sudo systemctl enable docker
sudo systemctl start docker

# Add user to docker group
sudo usermod -aG docker steam
sudo usermod -aG docker gameserver

Create docker-compose for multi-server deployment:

sudo tee /home/gameservers/docker-compose.yml > /dev/null <<'EOF'
version: '3.8'

services:
  # Valheim Server
  valheim_01:
    image: ghcr.io/pterodactyl/yolks:debian
    container_name: valheim_01
    environment:
      SERVER_NAME: "My Valheim Server"
      WORLD_NAME: "Dedicated"
      SERVER_PASSWORD: "secure_password"
    volumes:
      - /home/gameservers/valheim_01:/mnt/server
      - /home/gameservers/valheim_01/data:/root/.config/unity3d/IronGate/Valheim
    ports:
      - "2456:2456/udp"
      - "2457:2457/udp"
      - "2458:2458/udp"
    networks:
      - game_network
    restart: unless-stopped
    cpus: "2"
    mem_limit: 4g
    mem_reservation: 3g

  # Rust Server
  rust_01:
    image: ghcr.io/pterodactyl/yolks:rust
    container_name: rust_01
    environment:
      RUST_SERVER_NAME: "My Rust Server"
      RUST_MAX_PLAYERS: "100"
      RUST_WORLD_SIZE: "4000"
    volumes:
      - /home/gameservers/rust_01:/mnt/server
    ports:
      - "28015:28015/udp"
      - "28016:28016/udp"
    networks:
      - game_network
    restart: unless-stopped
    cpus: "4"
    mem_limit: 16g
    mem_reservation: 14g

  # Factorio Server
  factorio_01:
    image: ghcr.io/pterodactyl/yolks:factorio
    container_name: factorio_01
    environment:
      SERVER_NAME: "My Factorio Server"
      MAX_PLAYERS: "255"
    volumes:
      - /home/gameservers/factorio_01:/mnt/server
    ports:
      - "34197:34197/tcp"
    networks:
      - game_network
    restart: unless-stopped
    cpus: "1"
    mem_limit: 2g
    mem_reservation: 1.5g

networks:
  game_network:
    driver: bridge
    ipam:
      config:
        - subnet: 172.20.0.0/16

volumes:
  valheim_data:
  rust_data:
  factorio_data:
EOF

sudo chown gameserver:gameserver /home/gameservers/docker-compose.yml

Start containers:

cd /home/gameservers
sudo docker-compose up -d

# Verify running containers
sudo docker-compose ps

# Check logs
sudo docker-compose logs -f valheim_01
sudo docker-compose logs -f rust_01

Systemd Multi-Server Management

Create individual systemd services:

# Service for Valheim server
sudo tee /etc/systemd/system/gameserver-valheim01.service > /dev/null <<'EOF'
[Unit]
Description=Game Server: Valheim 01
After=docker.service network-online.target
Requires=docker.service
PartOf=gameservers.target

[Service]
Type=simple
WorkingDirectory=/home/gameservers
ExecStart=/usr/bin/docker-compose up valheim_01
ExecStop=/usr/bin/docker-compose stop valheim_01
Restart=always
RestartSec=10

User=gameserver
Group=gameserver

[Install]
WantedBy=multi-user.target
EOF

sudo systemctl daemon-reload
sudo systemctl enable gameserver-valheim01.service

Create master target for all game servers:

sudo tee /etc/systemd/system/gameservers.target > /dev/null <<'EOF'
[Unit]
Description=Game Servers Target
Wants=gameserver-valheim01.service gameserver-rust01.service gameserver-factorio01.service

[Install]
WantedBy=multi-user.target
EOF

sudo systemctl daemon-reload

Control all servers:

# Start all servers
sudo systemctl start gameservers.target

# Stop all servers
sudo systemctl stop gameservers.target

# Restart specific server
sudo systemctl restart gameserver-valheim01.service

# Check status
sudo systemctl status gameservers.target
systemctl list-unit-files gameserver-*.service

Port Configuration

Create port mapping documentation:

sudo tee /home/gameservers/PORT_MAPPING.txt > /dev/null <<'EOF'
# Game Server Port Mapping

# UDP Ports (Game Traffic)
2456-2458   : Valheim (3 ports)
28015-28016 : Rust Query (2 ports)
34197       : Factorio (1 port TCP)
7777        : Terraria (1 port)
26900-26901 : 7 Days to Die (2 ports)
27015-27017 : Counter-Strike 2 (3 ports)
25565-25575 : Minecraft (11 ports for instances)
16261-16271 : Project Zomboid (11 ports)
8211        : Palworld (1 port)

# Management/RCON Ports (Internal)
32330-32339 : RCON services
8080-8089   : Web panels
27005-27014 : Query ports

# Security: Firewall Rules
sudo ufw allow 2456:2458/udp
sudo ufw allow 28015:28016/udp
sudo ufw allow 34197/tcp
sudo ufw allow 7777/tcp
sudo ufw allow 26900:26901/udp
sudo ufw allow 27015:27017/tcp
EOF

cat /home/gameservers/PORT_MAPPING.txt

Configure firewall efficiently:

# UFW configuration for multiple game servers
sudo tee /etc/ufw/before.rules.d/gameservers > /dev/null <<'EOF'
# Game Server Port Rules

# Valheim
-A ufw-before-input -p udp --dport 2456:2458 -j ACCEPT

# Rust
-A ufw-before-input -p udp --dport 28015:28016 -j ACCEPT

# Factorio
-A ufw-before-input -p tcp --dport 34197 -j ACCEPT

# Terraria
-A ufw-before-input -p tcp --dport 7777 -j ACCEPT

# 7 Days to Die
-A ufw-before-input -p udp --dport 26900:26901 -j ACCEPT

# Counter-Strike 2
-A ufw-before-input -p tcp --dport 27015:27017 -j ACCEPT
-A ufw-before-input -p udp --dport 27015:27017 -j ACCEPT
EOF

sudo ufw reload

Memory and CPU Limits

Set resource limits per server:

# Docker CPU/Memory limits (via docker-compose shown above)
# Or via command line:

# Limit Valheim to 2 cores and 4GB RAM
docker update --cpus="2" --memory="4g" valheim_01

# Limit Rust to 4 cores and 16GB RAM
docker update --cpus="4" --memory="16g" rust_01

# Monitor resource usage
docker stats --no-stream
docker stats --no-stream --all

Create resource monitoring alert:

sudo tee /home/gameservers/check_resources.sh > /dev/null <<'EOF'
#!/bin/bash

echo "=== Game Server Resource Usage ==="

# Check CPU usage per container
docker stats --no-stream --format "table {{.Container}}\t{{.CPUPerc}}\t{{.MemUsage}}"

# Check if any container exceeds limits
MAX_MEM_PERCENT=85

docker stats --no-stream --format "{{json . }}" | while read line; do
    CONTAINER=$(echo $line | jq -r '.Container')
    MEM=$(echo $line | jq -r '.MemPerc' | sed 's/%//')
    
    if (( $(echo "$MEM > $MAX_MEM_PERCENT" | bc -l) )); then
        echo "WARNING: $CONTAINER exceeds ${MAX_MEM_PERCENT}% memory usage ($MEM%)"
    fi
done
EOF

sudo chmod +x /home/gameservers/check_resources.sh

Storage Organization

Organize server data efficiently:

# Directory structure
mkdir -p /home/gameservers/{
    valheim_01/data,
    rust_01/data,
    factorio_01/data,
    terraria_01/data,
    7dtd_01/data,
    backups/{valheim,rust,factorio,terraria,7dtd},
    logs,
    configs
}

# Create symbolic links for easy access
ln -s /home/gameservers/valheim_01/data /home/gameservers/valheim_world
ln -s /home/gameservers/rust_01/data /home/gameservers/rust_world
ln -s /home/gameservers/factorio_01/data /home/gameservers/factorio_world

# Monitor storage
du -sh /home/gameservers/*/

# Set up automatic cleanup of old backups
find /home/gameservers/backups -name "*.tar.gz" -mtime +30 -delete

Network Configuration

Configure bridge network for containers:

# Create dedicated game server network
docker network create \
  --driver bridge \
  --subnet 172.20.0.0/16 \
  --ip-range 172.20.1.0/24 \
  game_network

# List networks
docker network ls

# Inspect network
docker network inspect game_network

# Connect running container to network
docker network connect game_network container_name

Port forwarding configuration:

# For servers behind NAT, configure port forwarding on router:
External Port -> Internal IP : Internal Port

Example:
2456/UDP -> 192.168.1.100 : 2456
28015/UDP -> 192.168.1.100 : 28015

Monitoring Multiple Servers

Create comprehensive monitoring dashboard:

sudo tee /home/gameservers/monitor_all.sh > /dev/null <<'EOF'
#!/bin/bash

clear
echo "=========================================="
echo "     Multi-Game Server Status Report"
echo "=========================================="
echo "Generated: $(date)"
echo ""

# System resources
echo "=== System Resources ==="
echo "CPU Cores: $(nproc)"
echo "Total RAM: $(free -h | grep Mem | awk '{print $2}')"
echo "Used RAM: $(free -h | grep Mem | awk '{print $3}')"
echo "Disk Space: $(df -h /home/gameservers | tail -1 | awk '{print $5}')"
echo ""

# Docker containers
echo "=== Container Status ==="
docker ps --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}" | column -t
echo ""

# Container resource usage
echo "=== Container Resource Usage ==="
docker stats --no-stream --format "table {{.Container}}\t{{.CPUPerc}}\t{{.MemPerc}}\t{{.MemUsage}}" | head -20
echo ""

# Network ports
echo "=== Active Ports ==="
netstat -tulnp | grep -E "2456|28015|34197|7777|26900|27015|25565|16261|8211" | awk '{print $4, $7}' | column -t
echo ""

# Game server processes
echo "=== Game Server Process Status ==="
for CONTAINER in $(docker ps --format "{{.Names}}"); do
    RUNNING=$(docker inspect -f '{{.State.Running}}' $CONTAINER)
    if [ "$RUNNING" = "true" ]; then
        echo "✓ $CONTAINER: Running"
    else
        echo "✗ $CONTAINER: Stopped"
    fi
done
echo ""

# Recent errors
echo "=== Recent Errors ==="
docker logs --tail 5 $(docker ps -a --format "{{.Names}}" | head -3) 2>&1 | grep -i "error\|fatal" || echo "No errors found"
EOF

sudo chmod +x /home/gameservers/monitor_all.sh

Run monitoring:

# One-time check
/home/gameservers/monitor_all.sh

# Continuous monitoring
watch -n 10 /home/gameservers/monitor_all.sh

# Background monitoring with logging
nohup /home/gameservers/monitor_all.sh > /home/gameservers/logs/monitor.log 2>&1 &

Install Prometheus for advanced monitoring:

# Install Prometheus
sudo apt-get install -y prometheus

# Configure for Docker metrics
sudo tee /etc/prometheus/prometheus.yml > /dev/null <<'EOF'
global:
  scrape_interval: 15s

scrape_configs:
  - job_name: 'docker'
    static_configs:
      - targets: ['localhost:9323']
  
  - job_name: 'node'
    static_configs:
      - targets: ['localhost:9100']
EOF

# Install cAdvisor for container monitoring
docker run --volume=/:/rootfs:ro \
  --volume=/var/run:/var/run:ro \
  --volume=/sys:/sys:ro \
  --volume=/var/lib/docker/:/var/lib/docker:ro \
  --publish=8080:8080 \
  --detach \
  --name=cadvisor \
  gcr.io/cadvisor/cadvisor:latest

Scaling Strategies

Add new server dynamically:

# Create new server entry in docker-compose.yml
# Example: Add Minecraft server

cat >> /home/gameservers/docker-compose.yml <<'EOF'

  minecraft_01:
    image: ghcr.io/pterodactyl/yolks:java_17
    container_name: minecraft_01
    environment:
      JAVA_MEMORY: "4G"
      SERVER_NAME: "My Minecraft Server"
      MOTD: "Welcome to my server!"
    volumes:
      - /home/gameservers/minecraft_01:/mnt/server
    ports:
      - "25565:25565/tcp"
    networks:
      - game_network
    restart: unless-stopped
    cpus: "2"
    mem_limit: 6g
EOF

# Create new system directories
mkdir -p /home/gameservers/minecraft_01/data

# Pull new container image
docker pull ghcr.io/pterodactyl/yolks:java_17

# Start new service
docker-compose up -d minecraft_01

# Verify
docker ps | grep minecraft_01

Conclusion

Hosting multiple game servers on a single VPS requires careful planning, resource allocation, and monitoring. This approach provides excellent cost efficiency while maintaining service quality.

Key takeaways:

  • Plan resource allocation carefully before deployment
  • Use Docker for container isolation and ease of management
  • Implement proper systemd service management
  • Monitor all servers continuously
  • Maintain clear documentation of configurations
  • Scale servers horizontally by adding more VPS nodes when needed
  • Implement automated backups for all servers
  • Use resource limits to prevent one server overwhelming others

A properly configured multi-game server VPS can efficiently host 10-20+ game servers with excellent player experience.