Files
dev/docs/00 INBOX/ai/steamcmd servers.md
T

306 lines
6.3 KiB
Markdown

# SteamCMD servers
This note describes the workflow for adding a server that SteamCMD installs.
Start with the generic runner on a host.
Then move game behavior into a game module.
Move deployment behavior into a guest module after validation.
## Stage 1: Run the server with `steamcmd`
Prove the generic SteamCMD runner before adding game-specific modules.
Configure `modules.services.steamcmd` directly in the host file.
```nix
modules.services.steamcmd = {
enable = true;
steamDir = "/pikachu/data/steamcmd";
serviceName = "valheim";
appId = 896660;
installDir = "/pikachu/data/servers/valheim/main";
stateDir = "/pikachu/media/games/servers/valheim/main";
executable = "./valheim_server.x86_64";
arguments = [
"-nographics"
"-batchmode"
"-name"
"main"
"-port"
"2456"
"-world"
"main"
"-savedir"
config.modules.services.steamcmd.stateDir
"-password"
"foobarbaz"
"-public"
"0"
];
udpPorts = [
2456
2457
];
};
```
Use real values for the target game.
The example shows Valheim because it was the first server added.
This layer owns shared SteamCMD behavior:
- service user
- directory creation
- SteamCMD install and update command
- systemd service wrapper
- firewall ports
Do not pin the game server version in Nix.
SteamCMD mutates the installed server files.
## Stage 2: Add a game service module
Create a game module after direct SteamCMD deployment works.
Use `configs/nixos/modules/services/games/<game>.nix`.
The game module owns game-specific behavior:
- Steam app ID
- server executable
- command-line flags
- documented ports
- default listing policy
The host owns deployment-specific values:
- paths
- server name
- secret choice
- network placement
A host can run the game module directly during validation:
```nix
modules.services.games.valheim = {
enable = true;
steamDir = "/pikachu/data/steamcmd";
installDir = "/pikachu/data/servers/valheim/main";
stateDir = "/pikachu/media/games/servers/valheim/main";
serverName = "main";
passwordFile = "/run/secrets/services/game-servers/password";
};
```
The game module translates its options into `modules.services.steamcmd`.
It passes the app ID, executable, arguments, and ports to the runner.
## Stage 3: Add UDP ingress
Many game servers use UDP.
HTTP virtual hosts do not route raw UDP traffic.
Extend `registry.route` with UDP ports:
```nix
registry.route.pikachu.valheim = {
domain = "valheim.alexion.dev";
udp.ports = [
2456
2457
];
};
```
Keep `domain` mandatory.
Nix does not own public DNS today.
The route domain identifies the public route.
A future LAN DNS module can also consume it.
The reverse-proxy module joins `registry.route` with `registry.address`.
It renders nginx `stream` entries for UDP routes.
```nginx
server {
listen 2456 udp;
proxy_pass 10.23.20.197:2456;
}
```
Configure public DNS outside Nix:
```text
valheim.alexion.dev -> public IP
```
Configure LAN DNS outside Nix:
```text
valheim.alexion.dev -> reverse-proxy guest IP
```
Configure router forwarding outside Nix:
```text
2456/udp -> reverse-proxy guest:2456
2457/udp -> reverse-proxy guest:2457
```
Use the game documentation to choose the port list.
For Valheim, the official guide says it uses the configured port and port plus one.
## Stage 4: Move the server into a guest
Add a guest module after host-level validation succeeds.
Use `configs/nixos/guests/<game>.nix`.
The guest module wraps `modules.services.games.<game>`.
It maps host paths into guest paths.
It also connects guest address and route options to the registry.
The host config then owns deployment wiring:
```nix
guests.valheim = {
enable = true;
vlan = 20;
address = "10.23.20.197";
steamPath = "/pikachu/data/steamcmd";
installPath = "/pikachu/data/servers/valheim/main";
statePath = "/pikachu/media/games/servers/valheim/main";
serverName = "main";
reverseProxy = {
enable = true;
route = {
domain = "valheim.alexion.dev";
udp.ports = [
config.guests.valheim.port
(config.guests.valheim.port + 1)
];
};
};
};
```
The generic guest machinery publishes registry entries.
```nix
guests.valheim.address = "10.23.20.197";
```
becomes:
```nix
registry.address.pikachu.valheim = "10.23.20.197";
```
The guest route becomes:
```nix
registry.route.pikachu.valheim = config.guests.valheim.reverseProxy.route;
```
## Secrets
Use SOPS for game server passwords.
Use one shared secret when servers can share a password:
```yaml
services:
game-servers:
password: <password>
```
The Valheim guest defaults to:
```nix
passwordSecret = "services/game-servers/password";
```
The host decrypts the secret.
The guest module bind-mounts the decrypted file into the guest.
The game module reads the password file at runtime.
Edit shared secrets with the host key:
```sh
cd configs/nixos
sops-host secrets/shared.yaml
```
## Validation
Evaluate the host:
```sh
nix eval .#nixosConfigurations.pikachu.config.system.build.toplevel.drvPath --raw
```
Deploy the host:
```sh
deploy-to pikachu
```
Check the host secret:
```sh
sudo test -s /run/secrets/services/game-servers/password && echo secret-ok
```
Check the guest:
```sh
sudo systemctl status container@valheim.service --no-pager
```
Check the guest secret:
```sh
sudo nixos-container run valheim -- test -s /run/secrets/services/game-servers/password
```
Check the game service:
```sh
sudo nixos-container run valheim -- systemctl status valheim.service --no-pager
sudo nixos-container run valheim -- journalctl -u valheim.service -n 200 --no-pager
```
Wait for the game-specific ready log.
For Valheim, wait for these lines:
```text
Game server connected
Opened Steam server
```
Check game UDP listeners:
```sh
sudo nixos-container run valheim -- ss -lunp | grep -E '2456|2457|valheim'
```
Check reverse-proxy UDP listeners:
```sh
sudo nixos-container run reverse-proxy -- ss -lunp | grep -E '2456|2457|nginx'
```
Test the client through LAN DNS or public DNS:
```text
valheim.alexion.dev:2456
```
Test direct guest connectivity when ingress fails:
```text
10.23.20.197:2456
```
## Operational notes
A first server start can spend time preparing state.
For Valheim, first start can generate a world.
SteamCMD can leave old ownership on migrated server files.
The SteamCMD module uses recursive tmpfiles repair for its managed directories.