# SteamCMD server notes These notes describe the emerging pattern for SteamCMD-based game servers in this monorepo. They come from the Valheim prototype on Pikachu. ## Goal Use NixOS to manage server operations, not game content. Nix owns service wiring, launch flags, ports, timers, users, and mounts. SteamCMD owns downloaded server files. The game owns world data, generated config, saves, and modded files. ## Layering Use three layers for SteamCMD-based servers. ```text configs/nixos/modules/services/steamcmd.nix configs/nixos/modules/services/.nix configs/nixos/guests/.nix ``` ### `modules.services.steamcmd` This module provides the generic SteamCMD machinery. It runs on any NixOS system. That system can be a physical host or a guest. It owns: - the `steamcmd` service user, - the shared SteamCMD data directory, - per-instance Steam app updates, - per-instance game service units, - optional hard restart timers, - firewall openings for declared ports. It does not know Valheim, PalWorld, or Project Zomboid semantics. Game modules translate game-specific settings into SteamCMD instances. ### `modules.services.` A game service module wraps `modules.services.steamcmd`. For Valheim, this layer owns: - Steam app id `896660`, - the Valheim runtime app id, - launch flags such as `-name`, `-world`, and `-port`, - the expected UDP port range, - the mapping from instance options to a SteamCMD instance. This layer exposes operational config only. It avoids owning mutable gameplay files unless the game exposes stable launch flags. ### `guests.` A guest module turns a game service into a deployable guest. It owns host-facing concerns: - VLAN placement, - guest address registry entry, - host paths and bind mounts, - resource limits, - secret file mounts, - game-family instance declarations. Do not add a reusable `guests.steamcmd` base guest. The guest auto-loader turns `configs/nixos/guests/steamcmd.nix` into a concrete guest. A specialized guest cannot use it as a base without creating another container. ## Instance model Use one guest per game family. Use named instances inside that guest. For example, `guests.palworld` can contain `instances.current` and `instances.old`. Each instance has its own ports and paths. The host config must avoid clashes. For Valheim, the prototype uses `instances.foo`. The instance name is the operational identity. The world name defaults to the instance name. Keep these names separate in the module interface: ```text instance name -> unit names and paths worldName -> game launch flag ``` This permits a test instance to load a copied world later. ## Storage layout Use three storage roots. ```text /data/steamcmd /data/servers// /media/games/servers// ``` ### `/data/steamcmd` Store SteamCMD data and cache here. This directory contains mutable Steam metadata and download state. Do not treat it as durable game state. ### `/data/servers//` Store the installed dedicated server files here. SteamCMD writes these files. Mods can also mutate this tree. For that reason, use per-instance app installs. Do not share one app install between modded or historical instances. ### `/media/games/servers//` Store world data, saves, generated config, and durable game state here. Backups are out of scope for the first prototype. This path gives a stable backup boundary later. ## Updates Do not pin game server versions in Nix. Steam controls the server build. Nix controls when updates run. The prototype updates on service start. A daily hard restart timer can pull updates during a maintenance window. The generic SteamCMD layer supports a restart timer. The default timer command restarts the instance service. Game modules or host config can override that command later. Avoid generic player-warning or player-count logic in the SteamCMD layer. Those flows are game-specific. ## Secrets Use sops-backed environment files for durable configuration. Mount them read-only into the guest. The Valheim prototype temporarily supports a hardcoded password. That password leaks into the Nix store and process arguments. Use it only for throwaway tests. The target model is: ```text host sops secret -> read-only guest mount -> systemd EnvironmentFile ``` For Valheim, the environment file contains: ```sh SERVER_PASSWORD=example-password ``` ## Networking Open ports in the guest firewall from the game module. Valheim uses the base UDP port through `basePort + 2`. The default base port is `2456`, so open UDP `2456-2458`. For public access, forward those UDP ports to the guest address. DNS is optional for the first deployment. Use `machinectl status ` to confirm the current DHCP address. Do not trust a guessed address. Add a DHCP reservation before depending on a committed address. ## Valheim prototype The prototype proved these facts: - Valheim runs inside a NixOS guest on Pikachu. - SteamCMD installs the dedicated server files at service start. - `steam-run` runs the mutable Valheim server binary. - LAN clients can connect to the guest address and UDP port. - The storage split works for SteamCMD data, server files, and world data. The prototype used: ```text guest: valheim instance: foo password: foobarbaz actual DHCP address during test: 10.23.20.197 ``` The hardcoded password and test instance name need cleanup before a final PR. ## Bring-up checklist 1. Add or update `modules.services.`. 2. Map game-specific options to `modules.services.steamcmd.instances`. 3. Add or update `guests.`. 4. Mount `/data/steamcmd` into the guest. 5. Mount `/data/servers//` into the guest. 6. Mount `/media/games/servers//` into the guest. 7. Add a sops environment file for secrets. 8. Open the required game ports in the guest firewall. 9. Enable the guest on the target host. 10. Deploy with `deploy-to `. 11. Check `container@.service` on the host. 12. Enter the guest with `nixos-container root-login `. 13. Check the game service with `systemctl status`. 14. Follow logs with `journalctl -u -f`. 15. Connect from LAN before adding public forwarding. ## Open cleanup items - Replace hardcoded prototype passwords with sops environment files. - Choose durable instance names before long-term use. - Add DHCP reservations for game guests. - Add backup policy for world and modded server data. - Decide whether server install trees need backup for modded servers.