178 lines
4.8 KiB
Markdown
178 lines
4.8 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.
|
|
|
|
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:
|
|
|
|
```sh
|
|
cd configs/nixos
|
|
sops-host secrets/shared.yaml
|
|
```
|
|
|
|
## Validation
|
|
|
|
Evaluate the host before deployment:
|
|
|
|
```sh
|
|
nix eval .#nixosConfigurations.<host>.config.system.build.toplevel.drvPath --raw
|
|
```
|
|
|
|
Deploy the host:
|
|
|
|
```sh
|
|
deploy-to <host>
|
|
```
|
|
|
|
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@<guest>.service --no-pager
|
|
```
|
|
|
|
Check the guest secret:
|
|
|
|
```sh
|
|
sudo nixos-container run <guest> -- test -s /run/secrets/services/game-servers/password
|
|
```
|
|
|
|
Check the game service:
|
|
|
|
```sh
|
|
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:
|
|
|
|
```text
|
|
Game server connected
|
|
Opened Steam server
|
|
```
|
|
|
|
Check game UDP listeners:
|
|
|
|
```sh
|
|
sudo nixos-container run <guest> -- ss -lunp | grep -E '<ports>|<game>'
|
|
```
|
|
|
|
Check reverse-proxy UDP listeners:
|
|
|
|
```sh
|
|
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.
|