4.8 KiB
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.
Use real values for the target game.
For the first Valheim deployment, the direct configuration set the Steam app ID, install path, state path, executable, command-line arguments, and UDP ports directly on modules.services.steamcmd.
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.
For Valheim, the host passed only deployment values to modules.services.games.valheim.
The game module translated those values into modules.services.steamcmd options.
Stage 3: Add UDP ingress
Many game servers use UDP. HTTP virtual hosts do not route raw UDP traffic.
Extend registry.route with the UDP ports for the public route.
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.
Configure public DNS outside Nix to point the route domain at the public IP. Configure LAN DNS outside Nix to point the same route domain at the reverse-proxy guest IP. Configure router forwarding outside Nix to forward the documented UDP ports to the reverse-proxy guest.
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:
- VLAN
- guest address
- host paths for SteamCMD files, server files, and server state
- server name
- reverse-proxy route
The generic guest machinery publishes guests.<name>.address as registry.address.<host>.<name>.
It also publishes guests.<name>.reverseProxy.route as registry.route.<host>.<name> when reverse proxying is enabled.
Secrets
Use SOPS for game server passwords.
Use one shared secret when servers can share a password.
The current shared key is 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:
cd configs/nixos
sops-host secrets/shared.yaml
Validation
Evaluate the host before deployment:
nix eval .#nixosConfigurations.<host>.config.system.build.toplevel.drvPath --raw
Deploy the host:
deploy-to <host>
Check the host secret:
sudo test -s /run/secrets/services/game-servers/password && echo secret-ok
Check the guest:
sudo systemctl status container@<guest>.service --no-pager
Check the guest secret:
sudo nixos-container run <guest> -- test -s /run/secrets/services/game-servers/password
Check the game service:
sudo nixos-container run <guest> -- systemctl status <game>.service --no-pager
sudo nixos-container run <guest> -- journalctl -u <game>.service -n 200 --no-pager
Wait for the game-specific ready log. For Valheim, wait for these lines:
Game server connected
Opened Steam server
Check game UDP listeners:
sudo nixos-container run <guest> -- ss -lunp | grep -E '<ports>|<game>'
Check reverse-proxy UDP listeners:
sudo nixos-container run reverse-proxy -- ss -lunp | grep -E '<ports>|nginx'
Test the client through LAN DNS or public DNS. Test direct guest connectivity when ingress fails.
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.