Angus Forrest

How to make the Steam Machine a Server

Updated 827 words 4 min read

Picture of Valve Steam Machine

The Valve Steam Machine is a gaming console that can be retro-fitted to be a personal mini-server. The machine has a custom x86_64 CPU with 6 cores and a TDP of 30W. For memory it has 16GB DDR5 system memory and 8GB DDR6 video memory. The retail prices for a Valve Steam Machine do not make a compelling offer currently11 See DRAM prices. This is not to say that the platform and the engineering don’t have merits.The form-factor being an approximately 6 inch cube makes it one of the smallest personal computers or gaming console you can purchase on the market today. Another more important fact for making the Steam Machine a personal mini-server, is Valve choosing to build it’s operating system and software stack on top of Arch Linux. Valve made the conscious choice as well to make the Steam Machine architecture open.

When I purchased the Steam Machine, I intended to use it as a mini-server primarily and a gaming console second22 I swear!. This would allow me to move my services off virtual private servers and onto hardware I own. Below I detail the steps I took to set up the Valve Steam Machine to be a mini-server.

1. First boot: firmware, CEC, and getting a terminal

For the process of turning the steam machine into a server, this is the only part that requires a display out! The first setting to change from the default configuration is to turn off the HDMI-CEC poweroff feature, where the steam machine turns off with a display turn off. Good for power saving, bad for always on display. We then need to switch into Desktop Mode from Big Picture to access a terminal Emulator Konsole. Once in Desktop Mode we can open the Konsole application to input commands (you can use the app launcher in the bottom left and search for the app in the search bar).

2. Get SSH access to the machine

To start the process of making the steam machine a server, we should let it be interacted with in a headless mode. To do this we can enable sshd. Initially SteamOS’s user deck has no password so we must set that ourselves.

passwd
sudo systemctl enable --now sshd
ip addr | grep inet

3. Install Tailscale

To access the steam machine while not on the local network and make it more convenient to access, we can use Tailscale; a Wireguard manager. To install Tailscale we use a community script that installs the binaries into writable locations as the steam machine has a read-only root filesystem. The community script is available from a github repo. If Tailscale is installed correctly and has been connected to your Tailscale account, you should now have a ip address, this ip address is then usable from any of your other devices that has Tailscale installed and is on the same VPN.

curl -fsSL https://tailscale.com/install.sh | sh
git clone https://github.com/tailscale-dev/deck-tailscale.git ~/deck-tailscale
sudo -i

export TERM=xterm
cd ~deck/deck-tailscale
bash tailscale.sh
source /etc/profile.d/tailscale.sh
tailscale update
exit

tailscale ip -4
  # e.g. 100.64.0.10 — note it down

4. Harden SSH: keys only, no passwords

To add an additional layer of security, and make it easier to access the steam machine, we will create a ssh config and keys. Most of the steps in this section occur on the client machine client$. The steps in order are to create a SSH key that can be copied to the steam machine, requiring the last use of the passwd that we previously set for sudo as a method to connect to the machine. Then we add the steam machine to the ssh config so that we can alias the machine and use the correct SSH key every time. Finally we turn off PasswordAuthentication on the steam machine and restart sshd.

tailscale status
  # find the machine's <tailscale-ip> address

ssh-keygen -t ed25519 -f ~/.ssh/<sshkey-name>
  # skip if you already have a key

ssh-copy-id deck@<tailscale-ip>
  # uses the password one last time

cat >> ~/.ssh/config << 'EOF'
Host steam-machine
    # machine's Tailscale IP (from `tailscale status`)
    IdentityFile ~/.ssh/<sshkey-name>
    HostName <tailscale-ip>
    User deck
EOF
ssh steam-machine
  # prove it works before proceeding

sudo vim /etc/ssh/sshd_config
  # PasswordAuthentication no
  # KbdInteractiveAuthentication no

sudo systemctl restart sshd

5. Make sure the machine won’t sleep

To make sure that steam machine doesn’t suspend when we are idle, I’ve taken the liberty to disable most of the the systemd services that relate to power mode sleep actions.

systemctl status sleep.target
loginctl show-logind | grep -E 'IdleAction|IdleActionUSec|HandleLid'
systemd-analyze cat-config systemd/logind.conf | grep -E '^(IdleAction|IdleActionSec|HandleLid)'
systemd-inhibit --list
exit

6. Install Nix, then SFTPGo

To add software to the steam machine, I’ve decided to use the Nix package management system. A benefit of this approach is that packages install in /nix and the user’s home rather than in the read-only sections of the device. There are a few flags that matter to how I want to install Nix but aren’t strictly necessary for getting things working like nix-command and flakes. We will need to allow unfree packages to install sftpgo into the user profile.

findmnt /nix
sudo chown -R $USER:$USER /nix
sh <(curl -L https://nixos.org/nix/install) --no-daemon
. ~/.nix-profile/etc/profile.d/nix.sh
echo '. ~/.nix-profile/etc/profile.d/nix.sh' >> ~/.bashrc
nix-channel --update nixpkgs
mkdir -p ~/.config/nix
echo "experimental-features = nix-command flakes" >> ~/.config/nix/nix.conf
mkdir -p ~/.config/nixpkgs
vim ~/.config/nixpkgs/config.nix
  # allowUnfree = true

export NIXPKGS_ALLOW_UNFREE=1
nix profile add nixpkgs#sftpgo --impure

7. Configure SFTPGo and test-run it

Once sftpgo is installed we should make the associated folders for its operation. Then generate the configuration files for the service, and test it out and set up the admin user account through connecting to the HTTP server over tailscale.

mkdir -p ~/.local/share/sftpgo/{data,backups} ~/.config/sftpgo
tailscale ip -4
  # needed again for §8's unit file

sftpgo gen config ~/.config/sftpgo
STORE_SHARE=$(dirname $(dirname $(readlink -f $(which sftpgo))))/share/sftpgo
cp -r "$STORE_SHARE/templates" "$STORE_SHARE/static" ~/.config/sftpgo/
sftpgo serve -c ~/.config/sftpgo
tail -30 ~/.config/sftpgo/sftpgo.log

sudo reboot

8. Make SFTPGo survive reboots

To get SFTPGo working nicely on the steam machine requires a bit of finagling. SteamOS requires us to create the data folder in the user’s home directory. So we will need to run as a systemd user service and bind to sftpd on port 2022 and the web admin port on 8080 of the tailscale IP. We also should turn on enable-linger so the user services start at boot.

mkdir -p /home/deck/.local/share/sftpgo/data
exit

tailscale ip -4                        # for <tailscale ip>
mkdir -p ~/.config/systemd/user
cat > ~/.config/systemd/user/sftpgo.service << 'EOF'
[Unit]
Description=SFTPGo
After=network-online.target tailscaled.service
Wants=network-online.target

[Service]
Environment=SFTPGO_SFTPD__BINDINGS__0__ADDRESS=<tailscale ip>
Environment=SFTPGO_SFTPD__BINDINGS__0__PORT=2022
Environment=SFTPGO_HTTPD__BINDINGS__0__ADDRESS=<tailscale ip>
Environment=SFTPGO_HTTPD__BINDINGS__0__PORT=8080
ExecStart=%h/.nix-profile/bin/sftpgo serve -c %h/.config/sftpgo
Restart=on-failure
RestartSec=5

[Install]
WantedBy=default.target
EOF
systemctl --user daemon-reload
systemctl --user enable --now sftpgo
sudo loginctl enable-linger deck

Footnotes

  1. See DRAM prices ↩

  2. I swear! ↩

.md