2026-08-17

Make the Steam Machine a Server

how to enable ssh, ftp, caldav, nix on the steam machine

Picture of my steam machine taken using a 3rd generation iPhone SE

Hello Readers,

I’ve recently come into the possession of a steam machine. The steam machine is Valve’s attempt at developing a gaming console. However it is more than just a gaming console. Instead of the normal closed ecosystem which Microsoft and Sony both follow, Valve has instead left the doors wide open for people to use the machine however they want. It is purpose built to play games from the steam catalogue but without the unforced lobotomy. It can handle non-steam games as well as act as a normal linux workstation.

My main priority isn’t to play games unfortunately. Since moving countries I haven’t had a local server available to me. Having to make do with virtual private servers (VPS) for my many small syncing services between my multiple devices. The allure of replacing my use of a VPS with the steam machine has lead me to embark on a quest. A quest to see whether the steam machine can be a competent local server for my needs (spoiler it can!).

Over the past week I have successfully transformed my steam machine with trial and error into a capable local server. The rest of this article documents the steps I took and what footguns may trip another person attempting this project.

For the sake of comprehension, I have chosen to include user prompts throughout the large code snippets in this article, where deck$is the regular user on the machine, root# is the root user (after sudo -i), and client$ is a regular user from a client machine, i.e a laptop.

Author’s Note (AN): The technical difficulty of this tutorial is quite unassuming. I would advise against anyone without a couple years of experience with linux to attempt this process. Not due to any particular step but because of the relative newness of the product and the possible fallout of bricking this machine. This isn’t a strictly intended use of the steam machine and I would not think Valve would be amused with providing customer support. Likewise I do not expect to field support questions. Please if you are reading this and are a teenager; congradulations on the steam machine! I highly recommend learning linux skills on a more friendly, cheaper platform like a Raspberry PI, an embedded system, or an old laptop. I would hate for you to brick your new console.

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

I have to give it to Valve, the packaging of the steam machine was gorgeous. Kudos to the product design team. I have to also give kudos to the UX team as well as the initial boot wizard was intuitive and non-frustrating, unfortunately a uncommon trait for consoles. The most inconvient part of the process was the initial firmware updates, but I can hardly hold that against Valve.

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 convient 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