From 523655a9ec0cf94891990afe38651fac47809ac6 Mon Sep 17 00:00:00 2001 From: alexion Date: Thu, 10 Sep 2026 11:57:31 -0400 Subject: [PATCH] docs: make SteamCMD guide procedural --- docs/00 INBOX/ai/steamcmd servers.md | 187 +++++++++++++-------------- 1 file changed, 91 insertions(+), 96 deletions(-) diff --git a/docs/00 INBOX/ai/steamcmd servers.md b/docs/00 INBOX/ai/steamcmd servers.md index 514f5b6..7cae7c1 100644 --- a/docs/00 INBOX/ai/steamcmd servers.md +++ b/docs/00 INBOX/ai/steamcmd servers.md @@ -1,103 +1,107 @@ # 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. +Use this workflow to add a server that SteamCMD installs. +Complete each stage before you start the next stage. -## Stage 1: Run the server with `steamcmd` +## Stage 1: Prove the SteamCMD runner -Prove the generic SteamCMD runner before adding game-specific modules. -Configure `modules.services.steamcmd` directly in the host file. +1. Add the server to the host with `modules.services.steamcmd`. +2. Set the Steam app ID. +3. Set the SteamCMD directory. +4. Set the server install directory. +5. Set the server state directory. +6. Set the server executable path. +7. Set the game arguments. +8. Set the documented game ports. +9. Evaluate the host configuration. +10. Deploy the host. +11. Start the service on the host. +12. Read the service logs. +13. Wait for the game-specific ready log. +14. Connect from the game client. -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 +Keep this stage small. +Use it only to validate SteamCMD, game arguments, ports, and state paths. Do not pin the game server version in Nix. SteamCMD mutates the installed server files. -## Stage 2: Add a game service module +## Stage 2: Create the game module -Create a game module after direct SteamCMD deployment works. -Use `configs/nixos/modules/services/games/.nix`. +1. Create `configs/nixos/modules/services/games/.nix`. +2. Add the module to `configs/nixos/modules/default.nix`. +3. Define options under `modules.services.games.`. +4. Expose only deployment-specific values. +5. Keep host paths in the host configuration. +6. Keep secret selection in the host configuration. +7. Keep network placement outside the game module. +8. Move the Steam app ID into the game module. +9. Move the executable path into the game module. +10. Move game arguments into the game module. +11. Move documented ports into the game module. +12. Wire the game module to `modules.services.steamcmd`. +13. Replace the direct host `modules.services.steamcmd` config. +14. Enable `modules.services.games.` on the host. +15. Evaluate the host configuration. +16. Deploy the host. +17. Validate the service again on the host. -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. +The game module owns game behavior. +The host owns deployment values. ## Stage 3: Add UDP ingress -Many game servers use UDP. -HTTP virtual hosts do not route raw UDP traffic. +1. Read the game's official server port documentation. +2. Add the UDP ports to `registry.route...udp.ports`. +3. Keep `registry.route...domain` set. +4. Point `registry.address..` at the backend address. +5. Evaluate the reverse-proxy host configuration. +6. Deploy the reverse-proxy host. +7. Verify nginx listens on the UDP ports. +8. Configure public DNS outside Nix. +9. Configure LAN DNS outside Nix. +10. Configure router forwarding outside Nix. +11. Test the public route from the game client. +12. Test the backend address directly when ingress fails. -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. +Use the route domain for identity only. +Nginx stream routing uses destination ports for UDP traffic. +It does not route UDP by hostname. ## Stage 4: Move the server into a guest -Add a guest module after host-level validation succeeds. -Use `configs/nixos/guests/.nix`. +1. Create `configs/nixos/guests/.nix`. +2. Add the guest module to `src/dotfiles/guests.nix`. +3. Wrap `modules.services.games.` inside the guest. +4. Bind-mount the host SteamCMD directory into the guest. +5. Bind-mount the host install directory into the guest. +6. Bind-mount the host state directory into the guest. +7. Use guest-local paths for the game module. +8. Add `guests.` to the host configuration. +9. Set the guest VLAN. +10. Set the guest address. +11. Enable reverse proxying when the server needs ingress. +12. Put the UDP route under `guests..reverseProxy.route`. +13. Evaluate the host configuration. +14. Deploy the host. +15. Validate the container service. +16. Validate the game service inside the guest. +17. Validate reverse-proxy UDP listeners. +18. Connect from the game client. -The guest module wraps `modules.services.games.`. -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..address` as `registry.address..`. -It also publishes `guests..reverseProxy.route` as `registry.route..` when reverse proxying is enabled. +The guest machinery publishes `guests..address` to `registry.address..`. +It publishes `guests..reverseProxy.route` to `registry.route..`. ## 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. +1. Use SOPS for game server passwords. +2. Use `services/game-servers/password` for a shared game-server password. +3. Add a per-game key only when the game needs a different password. +4. Decrypt the secret on the host. +5. Bind-mount the decrypted secret into the guest. +6. Pass the password file to the game module. +7. Read the password file at service start. +8. Do not put plaintext passwords in host configuration. Edit shared secrets with the host key: @@ -106,9 +110,9 @@ cd configs/nixos sops-host secrets/shared.yaml ``` -## Validation +## Validation commands -Evaluate the host before deployment: +Evaluate the host: ```sh nix eval .#nixosConfigurations..config.system.build.toplevel.drvPath --raw @@ -145,14 +149,6 @@ sudo nixos-container run -- systemctl status .service --no-pager sudo nixos-container run -- journalctl -u .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 @@ -165,13 +161,12 @@ Check reverse-proxy UDP listeners: sudo nixos-container run reverse-proxy -- ss -lunp | grep -E '|nginx' ``` -Test the client through LAN DNS or public DNS. -Test direct guest connectivity when ingress fails. +## Operational checks -## Operational notes +1. Watch the first server start closely. +2. Expect some games to initialize state on first start. +3. Wait for the game-specific ready log before client testing. +4. Check SteamCMD logs when updates stall. +5. Check directory ownership when SteamCMD reports write failures. -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. +The SteamCMD module repairs ownership recursively for managed directories.