docs: generalize SteamCMD server workflow
This commit is contained in:
@@ -1,12 +1,13 @@
|
|||||||
# SteamCMD servers
|
# SteamCMD servers
|
||||||
|
|
||||||
This note records the workflow used to add the Valheim server.
|
This note describes the workflow for adding a server that SteamCMD installs.
|
||||||
The workflow starts with the lowest useful layer.
|
Start with the generic runner on a host.
|
||||||
Each later step moves game knowledge into a narrower module.
|
Then move game behavior into a game module.
|
||||||
|
Move deployment behavior into a guest module after validation.
|
||||||
|
|
||||||
## Stage 1: Run one server with `steamcmd`
|
## Stage 1: Run the server with `steamcmd`
|
||||||
|
|
||||||
Start by proving the generic SteamCMD runner works on a host.
|
Prove the generic SteamCMD runner before adding game-specific modules.
|
||||||
Configure `modules.services.steamcmd` directly in the host file.
|
Configure `modules.services.steamcmd` directly in the host file.
|
||||||
|
|
||||||
```nix
|
```nix
|
||||||
@@ -41,33 +42,41 @@ modules.services.steamcmd = {
|
|||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
This layer owns SteamCMD update behavior and systemd wiring.
|
Use real values for the target game.
|
||||||
It also owns directory setup for SteamCMD metadata, server files, and state.
|
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.
|
Do not pin the game server version in Nix.
|
||||||
SteamCMD mutates the installed server files.
|
SteamCMD mutates the installed server files.
|
||||||
|
|
||||||
## Stage 2: Add a game service module
|
## Stage 2: Add a game service module
|
||||||
|
|
||||||
After direct SteamCMD deployment works, create a game module.
|
Create a game module after direct SteamCMD deployment works.
|
||||||
Use `configs/nixos/modules/services/games/<game>.nix`.
|
Use `configs/nixos/modules/services/games/<game>.nix`.
|
||||||
|
|
||||||
The game module owns game-specific details:
|
The game module owns game-specific behavior:
|
||||||
|
|
||||||
- Steam app ID
|
- Steam app ID
|
||||||
- server executable
|
- server executable
|
||||||
- required command-line flags
|
- command-line flags
|
||||||
- documented UDP ports
|
- documented ports
|
||||||
- private or public listing policy
|
- default listing policy
|
||||||
|
|
||||||
The host keeps deployment-specific values:
|
The host owns deployment-specific values:
|
||||||
|
|
||||||
- host paths
|
- paths
|
||||||
- server name
|
- server name
|
||||||
- secret choice
|
- secret choice
|
||||||
- guest placement, when a guest exists
|
- network placement
|
||||||
|
|
||||||
For Valheim, the host config became:
|
A host can run the game module directly during validation:
|
||||||
|
|
||||||
```nix
|
```nix
|
||||||
modules.services.games.valheim = {
|
modules.services.games.valheim = {
|
||||||
@@ -76,17 +85,17 @@ modules.services.games.valheim = {
|
|||||||
installDir = "/pikachu/data/servers/valheim/main";
|
installDir = "/pikachu/data/servers/valheim/main";
|
||||||
stateDir = "/pikachu/media/games/servers/valheim/main";
|
stateDir = "/pikachu/media/games/servers/valheim/main";
|
||||||
serverName = "main";
|
serverName = "main";
|
||||||
password = "foobarbaz";
|
passwordFile = "/run/secrets/services/game-servers/password";
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
The Valheim module translated that into `modules.services.steamcmd`.
|
The game module translates its options into `modules.services.steamcmd`.
|
||||||
It generated the Valheim argument list and UDP ports.
|
It passes the app ID, executable, arguments, and ports to the runner.
|
||||||
|
|
||||||
## Stage 3: Add UDP ingress
|
## Stage 3: Add UDP ingress
|
||||||
|
|
||||||
Valheim uses UDP.
|
Many game servers use UDP.
|
||||||
HTTP virtual hosts do not route Valheim traffic.
|
HTTP virtual hosts do not route raw UDP traffic.
|
||||||
|
|
||||||
Extend `registry.route` with UDP ports:
|
Extend `registry.route` with UDP ports:
|
||||||
|
|
||||||
@@ -102,11 +111,11 @@ registry.route.pikachu.valheim = {
|
|||||||
|
|
||||||
Keep `domain` mandatory.
|
Keep `domain` mandatory.
|
||||||
Nix does not own public DNS today.
|
Nix does not own public DNS today.
|
||||||
The route domain still identifies the public route.
|
The route domain identifies the public route.
|
||||||
A future LAN DNS module can also consume it.
|
A future LAN DNS module can also consume it.
|
||||||
|
|
||||||
The reverse-proxy module joins `registry.route` with `registry.address`.
|
The reverse-proxy module joins `registry.route` with `registry.address`.
|
||||||
It renders nginx `stream` entries for UDP ports.
|
It renders nginx `stream` entries for UDP routes.
|
||||||
|
|
||||||
```nginx
|
```nginx
|
||||||
server {
|
server {
|
||||||
@@ -134,15 +143,19 @@ Configure router forwarding outside Nix:
|
|||||||
2457/udp -> reverse-proxy guest:2457
|
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
|
## Stage 4: Move the server into a guest
|
||||||
|
|
||||||
After the host-level game module works, add a guest module.
|
Add a guest module after host-level validation succeeds.
|
||||||
Use `configs/nixos/guests/<game>.nix`.
|
Use `configs/nixos/guests/<game>.nix`.
|
||||||
|
|
||||||
The guest module wraps `modules.services.games.<game>`.
|
The guest module wraps `modules.services.games.<game>`.
|
||||||
It also maps host paths into guest paths.
|
It maps host paths into guest paths.
|
||||||
|
It also connects guest address and route options to the registry.
|
||||||
|
|
||||||
For Valheim, the host config became:
|
The host config then owns deployment wiring:
|
||||||
|
|
||||||
```nix
|
```nix
|
||||||
guests.valheim = {
|
guests.valheim = {
|
||||||
@@ -186,8 +199,8 @@ registry.route.pikachu.valheim = config.guests.valheim.reverseProxy.route;
|
|||||||
|
|
||||||
## Secrets
|
## Secrets
|
||||||
|
|
||||||
Use SOPS for the game server password.
|
Use SOPS for game server passwords.
|
||||||
Use one shared secret for game servers:
|
Use one shared secret when servers can share a password:
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
services:
|
services:
|
||||||
@@ -203,7 +216,7 @@ passwordSecret = "services/game-servers/password";
|
|||||||
|
|
||||||
The host decrypts the secret.
|
The host decrypts the secret.
|
||||||
The guest module bind-mounts the decrypted file into the guest.
|
The guest module bind-mounts the decrypted file into the guest.
|
||||||
The Valheim module reads the password file at runtime.
|
The game module reads the password file at runtime.
|
||||||
|
|
||||||
Edit shared secrets with the host key:
|
Edit shared secrets with the host key:
|
||||||
|
|
||||||
@@ -232,7 +245,7 @@ Check the host secret:
|
|||||||
sudo test -s /run/secrets/services/game-servers/password && echo secret-ok
|
sudo test -s /run/secrets/services/game-servers/password && echo secret-ok
|
||||||
```
|
```
|
||||||
|
|
||||||
Check the Valheim guest:
|
Check the guest:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
sudo systemctl status container@valheim.service --no-pager
|
sudo systemctl status container@valheim.service --no-pager
|
||||||
@@ -244,21 +257,22 @@ Check the guest secret:
|
|||||||
sudo nixos-container run valheim -- test -s /run/secrets/services/game-servers/password
|
sudo nixos-container run valheim -- test -s /run/secrets/services/game-servers/password
|
||||||
```
|
```
|
||||||
|
|
||||||
Check the Valheim service:
|
Check the game service:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
sudo nixos-container run valheim -- systemctl status valheim.service --no-pager
|
sudo nixos-container run valheim -- systemctl status valheim.service --no-pager
|
||||||
sudo nixos-container run valheim -- journalctl -u valheim.service -n 200 --no-pager
|
sudo nixos-container run valheim -- journalctl -u valheim.service -n 200 --no-pager
|
||||||
```
|
```
|
||||||
|
|
||||||
Wait for these log lines:
|
Wait for the game-specific ready log.
|
||||||
|
For Valheim, wait for these lines:
|
||||||
|
|
||||||
```text
|
```text
|
||||||
Game server connected
|
Game server connected
|
||||||
Opened Steam server
|
Opened Steam server
|
||||||
```
|
```
|
||||||
|
|
||||||
Check Valheim UDP listeners:
|
Check game UDP listeners:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
sudo nixos-container run valheim -- ss -lunp | grep -E '2456|2457|valheim'
|
sudo nixos-container run valheim -- ss -lunp | grep -E '2456|2457|valheim'
|
||||||
@@ -284,8 +298,8 @@ Test direct guest connectivity when ingress fails:
|
|||||||
|
|
||||||
## Operational notes
|
## Operational notes
|
||||||
|
|
||||||
A first Valheim start can spend time generating a world.
|
A first server start can spend time preparing state.
|
||||||
The service accepts connections after `Opened Steam server` appears.
|
For Valheim, first start can generate a world.
|
||||||
|
|
||||||
SteamCMD can leave old ownership on migrated server files.
|
SteamCMD can leave old ownership on migrated server files.
|
||||||
The SteamCMD module uses recursive tmpfiles repair for its managed directories.
|
The SteamCMD module uses recursive tmpfiles repair for its managed directories.
|
||||||
|
|||||||
Reference in New Issue
Block a user