A solid server monitoring setup is the insurance policy of running a game server: you see the CPU maxing out, RAM filling up, or a process crashing before players ever feel the lag. In this guide I'll walk you through making a Linux game server (Metin2, Minecraft, CS, a Discord bot host — it doesn't matter) fully observable using the Prometheus + node_exporter + Grafana trio. It's all open source and it all runs on a single VPS.
Why Prometheus + Grafana?
The roles of this duo are cleanly separated:
- Prometheus — the time-series database and collector. It "scrapes" the targets (exporters) you define at regular intervals, stores the metrics and makes them queryable.
- node_exporter — Prometheus's official exporter; it publishes OS-level CPU, RAM, disk, network and load metrics on an HTTP endpoint.
- Grafana — the visualization layer. You connect Prometheus as a data source and build dashboards and alerts.
The data flows in one direction: node_exporter → Prometheus → Grafana. This architecture stays the same as you scale: you install an exporter on each new machine and add it as a target in Prometheus.
Installing node_exporter
node_exporter is a single static binary with no dependencies. Let's download the official release and run it as a systemd service:
cd /tmp
wget https://github.com/prometheus/node_exporter/releases/download/v1.8.2/node_exporter-1.8.2.linux-amd64.tar.gz
tar xzf node_exporter-1.8.2.linux-amd64.tar.gz
sudo cp node_exporter-1.8.2.linux-amd64/node_exporter /usr/local/bin/
sudo useradd --no-create-home --shell /usr/sbin/nologin node_exporter
Then create a systemd unit file:
sudo tee /etc/systemd/system/node_exporter.service >/dev/null <<'EOF'
[Unit]
Description=Prometheus Node Exporter
After=network.target
[Service]
User=node_exporter
Group=node_exporter
ExecStart=/usr/local/bin/node_exporter
Restart=on-failure
[Install]
WantedBy=multi-user.target
EOF
sudo systemctl daemon-reload
sudo systemctl enable --now node_exporter
Verify it: curl http://localhost:9100/metrics should return a long list of metrics. node_exporter listens on port 9100 by default.
Setting up Prometheus and defining targets
You can download Prometheus as a binary the same way or run it with Docker. Its heart is the prometheus.yml config file, where you define your scrape targets:
global:
scrape_interval: 15s
scrape_configs:
- job_name: 'node'
static_configs:
- targets: ['localhost:9100']
labels:
instance: 'metin2-vps-1'
scrape_interval sets how often data is collected; 15 seconds is enough resolution for most game servers. If you have several machines, add new ip:9100 lines under targets. Spinning up Prometheus with Docker is the most practical route:
docker run -d --name prometheus -p 9090:9090 \
-v /etc/prometheus/prometheus.yml:/etc/prometheus/prometheus.yml \
prom/prometheus
Check that your target shows up as UP at http://server-ip:9090/targets.
Player counts and custom game metrics
node_exporter gives you system metrics but can't answer "how many players are online?" There are two practical approaches:
- process metrics — with
process-exporteryou can track the CPU and memory usage of game server processes (e.g. Metin2 channel/game processes) individually. If one channel suddenly eats RAM, you see it immediately. - custom exporter — the player count usually lives in a database or in the server's own API. A small script can push values to Prometheus's Pushgateway or you can use the
textfile collector.
The textfile collector method is the simplest: start node_exporter with --collector.textfile.directory=/var/lib/node_exporter, then a cron script writes the metric to a .prom file:
#!/bin/bash
# read the online player count from MySQL
COUNT=$(mysql -N -e "SELECT COUNT(*) FROM player_online;" game_db)
echo "game_players_online ${COUNT}" > /var/lib/node_exporter/players.prom.$$
mv /var/lib/node_exporter/players.prom.$$ /var/lib/node_exporter/players.prom
Using an atomic mv prevents node_exporter from reading a half-written file. Now you can graph the game_players_online metric in Grafana.
Grafana dashboard and alerts
After installing Grafana (Docker: grafana/grafana, port 3000), the first step is adding Prometheus as a data source under Connections → Data sources; set the URL to http://prometheus:9090 or your server IP. Instead of building a dashboard from scratch, importing a ready-made one is fastest: for node_exporter the community dashboard ID 1860 (Node Exporter Full) brings dozens of panels for CPU, RAM, disk and network.
The real value is in alerts. A few practical PromQL expressions:
- CPU usage:
100 - (avg by(instance)(rate(node_cpu_seconds_total{mode="idle"}[5m])) * 100)— warn when it exceeds 90%. - Free RAM ratio:
node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes— warn when it drops below 10%. - Disk fill:
node_filesystem_avail_byteson the root partition falling below a critical threshold.
In Grafana you create an Alert rule from a panel, define the threshold, and route the notification to a Discord webhook, email or Telegram. That way your phone buzzes at 3 a.m. when the server goes down — instead of waking up to player complaints.
A security note
Never expose the exporter and Prometheus ports (9100, 9090) to the public internet. They carry no authentication and leak information about your system. The right approach: restrict these ports in the firewall (e.g. ufw) to your internal network or trusted IPs only, and for machine-to-machine traffic put them behind a VPN (WireGuard) or a reverse proxy with basic auth. Put Grafana's port 3000 behind a TLS reverse proxy (Nginx/Caddy) too — that's the cleanest setup.
Frequently Asked Questions
Can Prometheus and the game server run on the same VPS?
Yes, at small to medium scale it's fine. Prometheus and node_exporter are very lightweight. Just keep the retention period (say 15 days) and scrape interval reasonable; storing months of per-second data wastes disk for no reason.
How do I monitor multiple game servers?
Install node_exporter on each machine, gather them all under targets in a single Prometheus prometheus.yml, and give each a meaningful instance label. In Grafana you watch them all from one dashboard by selecting the instance.
Should I use something other than Grafana alerting?
Grafana alerts are enough for most use cases. If you want more complex silencing/grouping rules, add Prometheus's own Alertmanager component; the two also work together.
Stop flying your game server blind. Want me to make your server properly observable with a Prometheus + Grafana monitoring setup, process tracking and alerts dropped into Discord? Get in touch — I'll handle everything from install to dashboards.