parent
ce94e6fe48
commit
4a11f0ab9c
1 changed files with 122 additions and 0 deletions
122
content/posts/sunshine-autostart.md
Normal file
122
content/posts/sunshine-autostart.md
Normal file
|
@ -0,0 +1,122 @@
|
|||
+++
|
||||
date = '2025-03-27T01:02:50+01:00'
|
||||
draft = false
|
||||
title = 'Simple Sunshine Autostart on Headless Linux'
|
||||
+++
|
||||
## Motivation
|
||||
The combination of [Sunshine](https://app.lizardbyte.dev/Sunshine) and [Moonlight](https://moonlight-stream.org/) provides means to remotely connect to a PC hosting the Sunshine server. This set of tools has been specifically engineered and optimized for the sake of low-latency and high-performance game streaming.
|
||||
|
||||
While a regular setup allows for streaming of one's PC to devices in the home network, the addition of [Tailscale](https://tailscale.com/) (and if desired [Headscale](https://headscale.net)) facilitates streaming from any arbitrary internet-connected location in the world. This is especially useful, if one has a powerful PC at home, but is currently limited to a comparatively less powerful notebook.
|
||||
|
||||
However, a problem arises if the PC at home is powered off and no one is present to turn it on and log in with the user's credentials. In the optimal case it should be possible to achieve this from any remote location.
|
||||
|
||||
Unfortunately this idea is hindered by the fact, that on Linux the Sunshine server only starts after entering the user's credentials. Therefore a methodology must be devised to sign in a user and start the Sunshine server before using it for its inteded game streaming purposes.
|
||||
|
||||
## Existing Approaches
|
||||
Since the aforementioned problem is not unique, a plethora of users have faced a similar issue before. The following discusses some approaches and why they are not suitable for my likings.
|
||||
|
||||
### Autologin
|
||||
The easiest way to achieve automatic startup of Sunshine after a headless Linux boot is to skip the password authentication and automatically log into the desktop environment.
|
||||
|
||||
{{< alert icon="fire" cardColor="#e63946" iconColor="#1d3557" textColor="#f1faee" >}}
|
||||
**Warning!** This is insecure and not recommended!
|
||||
{{< /alert >}}
|
||||
|
||||
To achieve this, an additional file `/etc/systemd/system/getty@tty1.service.d/override.conf` with the following content has to be created.
|
||||
|
||||
{{< highlight systemd >}}
|
||||
[Service]
|
||||
ExecStart=
|
||||
ExecStart=-/sbin/agetty --autologin <USERNAME HERE> --noclear %I $TERM
|
||||
Type=idle
|
||||
{{< / highlight >}}
|
||||
|
||||
The biggest drawback of this method lies in its inherent security flaws. Removing password authentication allows unauthorized parties on-premise to access sensitive data and should therefore be avoided.
|
||||
|
||||
### Separate Sunshine Login Session
|
||||
The article I initially encountered ([Autostart Sunshine on Boot without Auto-Login](https://app.lizardbyte.dev/2024-10-16-autostart-sunshine-on-boot-without-auto-login)) proposes a solution with two separate consecutive Sunshine sessions.
|
||||
The first Sunshine session is initiated by an external SSH connection and is solely aimed at allowing the user to log in. The second Sunshine session then represents the regular game streaming session.
|
||||
|
||||
Multiple Sunshine sessions introduces complexity which I did not want to tackle. This involves creating custom Systemd units which replace the original Sunshine autostart unit. Additional polkit rules and the added systemd complexity led me to a search for more simplistic alternatives.
|
||||
|
||||
## Concept
|
||||
As in the "[Autostart Sunshine on Boot without Auto-Login](https://app.lizardbyte.dev/2024-10-16-autostart-sunshine-on-boot-without-auto-login)" article I initially considered, Wake-on-LAN is the easiest method to trigger the boot process of the Sunshine host system.
|
||||
|
||||
{{< alert icon="triangle-exclamation" >}}
|
||||
**Attention**: Make sure to enable the Wake-on-LAN capabilities in the host system BIOS
|
||||
{{< /alert >}}
|
||||
|
||||
Then either Moonlight's builtin Wake-on-LAN feature or an external tool can be used to power on the Sunshine host.
|
||||
|
||||
Subsequently, an SSH connection should be utilized to trigger the system login or directly trigger the desktop environment. This might either be achieved by remotely typing the password on the local TTY hosting the login manager or by directly spawning the desktop environment from the authenticated SSH session.
|
||||
|
||||
## Realization
|
||||
The following requires a working SSH server running on the Sunshine host system. In order to prevent unauthorized SSH access of this host machine, prefer SSH-key authentication and make sure the system is not exposed to the public internet.
|
||||
|
||||
To begin with, I explored the option to directly spawn the desktop environment from the SSH session. The Linux tool `chvt` allows to directly manipulate the host system's TTY and might be used to exec the desktop manager.
|
||||
|
||||
{{< highlight bash >}}
|
||||
sudo chvt -l -s -- bash -c "XDG_RUNTIME_DIR='/run/user/1000' exec Hyprland"
|
||||
{{< / highlight >}}
|
||||
|
||||
In the case of my current desktop environment --- Hyprland, a wayland compositor --- I was not able to establish a usable Hyprland session via SSH. The former command leads to a Hyprland crash which needs to be investigated in the future.
|
||||
|
||||
A simpler method is to emulate physical keyboard interaction and start the desktop environment using the login manager generally used to start a desktop environment in presence.
|
||||
|
||||
{{< github repo="ReimuNotMoe/ydotool" >}}
|
||||
|
||||
The Linux application `ydotool`, an alternative to the Xorg-specific `xdotool`, provides an easy means of remotely controlling keyboard input.
|
||||
|
||||
|
||||
<div style="background-color:white; padding: 20px">
|
||||
{{< mermaid >}}
|
||||
sequenceDiagram
|
||||
autonumber
|
||||
Client ->> Server: Wake-on-LAN request
|
||||
Note right of Server: Server boots to <br/> login manager
|
||||
Client ->> Server: SSH Connection: Login using ydotool
|
||||
Note right of Server: Desktop environment <br/> running
|
||||
Client ->>+ Server: Moonlight: Initialize Stream
|
||||
Server -->>- Client: Sunshine: Stream Desktop
|
||||
{{< /mermaid >}}
|
||||
</div>
|
||||
|
||||
In the case of my login manager, GNOME Display Manager (GDM), the following sequence of interactions is required to complete the login screen:
|
||||
|
||||
1. Press the `ENTER` key
|
||||
2. Type the password
|
||||
3. Press the `ENTER` key once again to submit the password
|
||||
|
||||
This sequence is relatively easy to replicate with `ydotool`, after starting the required `ydotoold` daemon. After some experiments, additional time delays between keybord interactions with `sleep` seemed to be required to allow the keypresses to fully take effect.
|
||||
|
||||
{{< highlight bash "linenos=table" >}}
|
||||
#! /usr/bin/env bash
|
||||
ydotoold& # start daemon
|
||||
sleep 1
|
||||
ydotool key 28:1 28:0 # press enter key
|
||||
sleep 1
|
||||
ydotool type -f password.txt # type out
|
||||
sleep 1
|
||||
pkill ydotoold # kill daemon
|
||||
{{< / highlight >}}
|
||||
|
||||
Keycodes such as for the `ENTER` key can be relatively easily generated by the [ydotool composer](https://vdegenne.github.io/ydotool-composer/).
|
||||
|
||||
The content of a text file, for instance `password.txt` is fully typed out with a minor caveat. `ydotool type` currently does not respect keyboard layouts, which means one must either utilize `ydtool key` instead or already transform the to-be-typed text into the representation one would type on an English keyboard. For example `Foo-Bar` on a German keyboard requires `Foo/Bar` as the input to `ydotool`.
|
||||
|
||||
This leaves the problem of plain-text passwords on the system hard-drive. While there are many keystores and secrets managers, I use sops to keep secrets safe while exposing them to the system using secrets files.
|
||||
|
||||
{{< github repo="getsops/sops" >}}
|
||||
|
||||
Using this application allows `ydotool` to access the system password in a file on a temporary RAM file system, such as `/run/secrets/sunshine/login_pw_seq`. This secret file then can be utilized in plase of the aforementioned `passwords.txt`.
|
||||
|
||||
## Discussion
|
||||
Using the here proposed shell script it is possible to directly start the Sunshine server after a single additional SSH interaction without any additional modification to the system. Its simplicity and speed are the biggest advantages compared to the presented alternative approaches.
|
||||
|
||||
However there are still many problems to this method, which may or may not be solvable in the future.
|
||||
|
||||
The biggest flaw lies in its high speed caused by automation. The keyboard interactions via `ydotool` are not login manager agnostic and need to be customized. This might also cause future breakage in case the overall interaction procedure changes.
|
||||
|
||||
The lack of keyboard layout support by `ydotool` will most likely be fixed in the future and currently does not represent a dramatic issue. Yet the general usage of the here proposed approach is affected slightly detrimental in its usability.
|
||||
|
||||
Lastly there exists the risk of plain-text passwords being stored on the hard-drive, caused by the convenience for the user. Nevertheless a security-minded user should be able to address this issue by applying key-vaults, such as SOPS.
|
Loading…
Add table
Add a link
Reference in a new issue