Sunshine/docs/guides.md
A Literal Midwestern Rodent d80fe79f81
Some checks failed
CI / GitHub Env Debug (push) Has been cancelled
CI / Setup Release (push) Has been cancelled
CI / Setup Flatpak Matrix (push) Has been cancelled
CI Docker / Check Dockerfiles (push) Has been cancelled
CodeQL / Get language matrix (push) Has been cancelled
Build GH-Pages / update_pages (push) Has been cancelled
CI / Linux Flatpak (push) Has been cancelled
CI / Linux ${{ matrix.type }} (--appimage-build, 22.04, AppImage) (push) Has been cancelled
CI / Homebrew (${{ matrix.os_name }}-${{ matrix.os_version }}${{ matrix.release == true && ' (Release)' || '' }}) (macos, 13) (push) Has been cancelled
CI / Homebrew (${{ matrix.os_name }}-${{ matrix.os_version }}${{ matrix.release == true && ' (Release)' || '' }}) (macos, 14) (push) Has been cancelled
CI / Homebrew (${{ matrix.os_name }}-${{ matrix.os_version }}${{ matrix.release == true && ' (Release)' || '' }}) (ubuntu, latest) (push) Has been cancelled
CI / Homebrew (${{ matrix.os_name }}-${{ matrix.os_version }}${{ matrix.release == true && ' (Release)' || '' }}) (ubuntu, latest, true) (push) Has been cancelled
CI / Macports (macOS-${{ matrix.os_version }}) (13, true) (push) Has been cancelled
CI / Macports (macOS-${{ matrix.os_version }}) (14) (push) Has been cancelled
CI / Windows (push) Has been cancelled
CI Docker / Setup Release (push) Has been cancelled
CI Docker / Docker${{ matrix.tag }} (push) Has been cancelled
CodeQL / Analyze (${{ matrix.name }}) (push) Has been cancelled
docs(guides): add autostart guide (#3287)
Co-authored-by: ReenigneArcher <42013603+ReenigneArcher@users.noreply.github.com>
2024-10-16 20:57:23 +00:00

43 KiB

Guides

@admonition{Community | This collection of guides is written by the community! Feel free to contribute your own tips and trips by making a PR.}

Linux

Discord call cancellation

Author RickAndTired
Difficulty Easy
  • Set your normal Sound Output volume to 100%

  • Start Sunshine

  • Set Sound Output to sink-sunshine-stereo (if it isn't automatic)

  • In Discord, right click Deafen and select your normal Output Device. This is also where you will need to adjust output volume for Discord calls

  • Open qpwgraph

  • Connect sunshine [sunshine-record] to your normal Output Device

    • Drag monitor_FL to playback_FL
    • Drag monitor_FR to playback_FR

Remote SSH Headless Setup

Author Eric Dong
Difficulty Intermediate

This is a guide to setup remote SSH into host to startup X server and Sunshine without physical login and dummy plug. The virtual display is accelerated by the NVidia GPU using the TwinView configuration.

@attention{This guide is specific for Xorg and NVidia GPUs. I start the X server using the startx command. I also only tested this on an Artix runit init system on LAN. I didn't have to do anything special with pulseaudio (pipewire untested).

Pipewire does not seem to work when Sunshine is started over an SSH session. A workaround to this problem is to kill the Sunshine instance started via SSH, and start a new one with the permissions of the desktop session. See Autostart on boot without auto-login

Keep your monitors plugged in until the Checkpoint step.}

@tip{Prior to editing any system configurations, you should make a copy of the original file. This will allow you to use it for reference or revert your changes easily.}

The Big Picture

Once you are done, you will need to perform these 3 steps:

  1. Turn on the host machine

  2. Start Sunshine on remote host with a script that:

    • Edits permissions of /dev/uinput (added sudo config to execute script with no password prompt)
    • Starts X server with startx on virtual display
    • Starts Sunshine
  3. Startup Moonlight on the client of interest and connect to host

@hint{As an alternative to SSH...

Step 2 can be replaced with autologin and starting Sunshine as a service or putting sunshine & in your .xinitrc file if you start your X server with startx. In this case, the workaround for /dev/uinput permissions is not needed because the udev rule would be triggered for "physical" login. See Linux Setup. I personally think autologin compromises the security of the PC, so I went with the remote SSH route. I use the PC more than for gaming, so I don't need a virtual display everytime I turn on the PC (E.g running updates, config changes, file/media server).}

First we will setup the host and then the SSH Client (Which may not be the same as the machine running the moonlight client).

Host Setup

We will be setting up:

  1. Static IP Setup
  2. SSH Server Setup
  3. Virtual Display Setup
  4. Uinput Permissions Workaround
  5. Stream Launcher Script

Static IP Setup

Setup static IP Address for host. For LAN connections you can use DHCP reservation within your assigned range. e.g. 192.168.x.x. This will allow you to ssh to the host consistently, so the assigned IP address does not change. It is preferred to set this through your router config.

SSH Server Setup

@note{Most distros have OpenSSH already installed. If it is not present, install OpenSSH using your package manager.}

@tabs{ @tab{Debian based | bash sudo apt update sudo apt install openssh-server } @tab{Arch based | bash sudo pacman -S openssh # Install openssh-<other_init> if you are not using SystemD # e.g. sudo pacman -S openssh-runit } @tab{Alpine based | bash sudo apk update sudo apk add openssh } @tab{Fedora based (dnf) | bash sudo dnf install openssh-server } @tab{Fedora based (yum) | bash sudo yum install openssh-server } }

Next make sure the OpenSSH daemon is enabled to run when the system starts.

@tabs{ @tab{SystemD | bash sudo systemctl enable sshd.service sudo systemctl start sshd.service # Starts the service now sudo systemctl status sshd.service # See if the service is running } @tab{Runit | bash sudo ln -s /etc/runit/sv/sshd /run/runit/service # Enables the OpenSSH daemon to run when system starts sudo sv start sshd # Starts the service now sudo sv status sshd # See if the service is running } @tab{OpenRC | bash rc-update add sshd # Enables service rc-status # List services to verify sshd is enabled rc-service sshd start # Starts the service now } }

Disabling PAM in sshd

I noticed when the ssh session is disconnected for any reason, pulseaudio would disconnect. This is due to PAM handling sessions. When running dmesg, I noticed elogind would say removed user session. In this Gentoo Forums post, someone had a similar issue. Starting the X server in the background and exiting out of the console would cause your session to be removed.

@caution{According to this article disabling PAM increases security, but reduces certain functionality in terms of session handling. Do so at your own risk!}

Edit the sshd_config file with the following to disable PAM.

usePAM no

After making changes to the sshd_config, restart the sshd service for changes to take effect.

@tip{Run the command to check the ssh configuration prior to restarting the sshd service.

sudo sshd -t -f /etc/ssh/sshd_config

An incorrect configuration will prevent the sshd service from starting, which might mean losing SSH access to the server.}

@tabs{ @tab{SystemD | bash sudo systemctl restart sshd.service } @tab{Runit | bash sudo sv restart sshd } @tab{OpenRC | bash sudo rc-service sshd restart } }

Virtual Display Setup

As an alternative to a dummy dongle, you can use this config to create a virtual display.

@important{This is only available for NVidia GPUs using Xorg.}

@hint{Use xrandr to see name of your active display output. Usually it starts with DP or HDMI. For me, it is DP-0. Put this name for the ConnectedMonitor option under the Device section.

xrandr | grep " connected" | awk '{ print $1 }'

}

Section "ServerLayout"
   Identifier "TwinLayout"
   Screen 0 "metaScreen" 0 0
EndSection

Section "Monitor"
   Identifier "Monitor0"
   Option "Enable" "true"
EndSection

Section "Device"
   Identifier "Card0"
   Driver "nvidia"
   VendorName "NVIDIA Corporation"
   Option "MetaModes" "1920x1080"
   Option "ConnectedMonitor" "DP-0"
   Option "ModeValidation" "NoDFPNativeResolutionCheck,NoVirtualSizeCheck,NoMaxPClkCheck,NoHorizSyncCheck,NoVertRefreshCheck,NoWidthAlignmentCheck"
EndSection

Section "Screen"
   Identifier "metaScreen"
   Device "Card0"
   Monitor "Monitor0"
   DefaultDepth 24
   Option "TwinView" "True"
   SubSectionSub "Display"
       Modes "1920x1080"
   EndSubSection
EndSection

@note{The ConnectedMonitor tricks the GPU into thinking a monitor is connected, even if there is none actually connected! This allows a virtual display to be created that is accelerated with your GPU! The ModeValidation option disables valid resolution checks, so you can choose any resolution on the host!

References

Uinput Permissions Workaround

Steps

We can use chown to change the permissions from a script. Since this requires sudo, we will need to update the sudo configuration to execute this without being prompted for a password.

  1. Create a sunshine-setup.sh script to update permissions on /dev/uinput. Since we aren't logged into the host, the udev rule doesn't apply.
  2. Update user sudo configuration /etc/sudoers.d/<user> to allow the sunshine-setup.sh script to be executed with sudo.

@note{After I setup the :ref:udev rule <about/setup:install> to get access to /dev/uinput, I noticed when I sshed into the host without physical login, the ACL permissions on /dev/uinput were not changed. So I asked reddit. I discovered that SSH sessions are not the same as a physical login. I suppose it's not possible for SSH to trigger a udev rule or create a physical login session.}

Setup Script

This script will take care of any preconditions prior to starting up Sunshine.

Run the following to create a script named something like sunshine-setup.sh:

echo "chown $(id -un):$(id -gn) /dev/uinput" > sunshine-setup.sh && \
  chmod +x sunshine-setup.sh

(Optional) To Ensure ethernet is being used for streaming, you can block Wi-Fi with rfkill.

Run this command to append the rfkill block command to the script:

echo "rfkill block $(rfkill list | grep "Wireless LAN" \
  | sed 's/^\([[:digit:]]\).*/\1/')" >> sunshine-setup.sh
Sudo Configuration

We will manually change the permissions of /dev/uinput using chown. You need to use sudo to make this change, so add/update the entry in /etc/sudoers.d/${USER}.

@danger{Do so at your own risk! It is more secure to give sudo and no password prompt to a single script, than a generic executable like chown.}

@warning{Be very careful of messing this config up. If you make a typo, YOU LOSE THE ABILITY TO USE SUDO. Fortunately, your system is not borked, you will need to login as root to fix the config. You may want to setup a backup user / SSH into the host as root to fix the config if this happens. Otherwise, you will need to plug your machine back into a monitor and login as root to fix this. To enable root login over SSH edit your SSHD config, and add PermitRootLogin yes, and restart the SSH server.}

  1. First make a backup of your /etc/sudoers.d/${USER} file.

    sudo cp /etc/sudoers.d/${USER} /etc/sudoers.d/${USER}.backup
    
  2. cd to the parent dir of the sunshine-setup.sh script and take note of the full filepath.

  3. Execute the following to edit your sudoer config file.

@danger{NEVER modify a file in sudoers.d directly. Always use the visudo command. This command checks your changes before saving the file, and if the resulting changes would break sudo on your system, it will prompt you to fix them. Modifying the file with nano or vim directly does not give you this sanity check and introduces the possibility of losing sudo access to your machine. Tread carefully, and make a backup.}

sudo visudo /etc/sudoers.d/${USER}

Copy the below configuration into the text editor. Change ${USER} wherever it occurs to your username (e.g. if your username is sunshineisaawesome you should change ${USER} to sunshineisawesome) or modify the path if you placed sunshine-setup.sh in a different area.

${USER} ALL=(ALL:ALL) ALL, NOPASSWD: /home/${USER}/scripts/sunshine-setup.sh

These changes allow the script to use sudo without being prompted with a password.

e.g. sudo $(pwd)/sunshine-setup.sh

Stream Launcher Script

This is the main entrypoint script that will run the sunshine-setup.sh script, start up X server, and Sunshine. The client will call this script that runs on the host via ssh.

Sunshine Startup Script

This guide will refer to this script as ~/scripts/sunshine.sh. The setup script will be referred as ~/scripts/sunshine-setup.sh.

#!/bin/bash
set -e

export DISPLAY=:0

# Check existing X server
ps -e | grep X >/dev/null
[[ ${?} -ne 0 ]] && {
 echo "Starting X server"
 startx &>/dev/null &
 [[ ${?} -eq 0 ]] && {
   echo "X server started successfully"
 } || echo "X server failed to start"
} || echo "X server already running"

# Check if sunshine is already running
ps -e | grep -e .*sunshine$ >/dev/null
[[ ${?} -ne 0 ]] && {
 sudo ~/scripts/sunshine-setup.sh
 echo "Starting Sunshine!"
 sunshine > /dev/null &
 [[ ${?} -eq 0 ]] && {
   echo "Sunshine started successfully"
 } || echo "Sunshine failed to start"
} || echo "Sunshine is already running"

# Add any other Programs that you want to startup automatically
# e.g.
# steam &> /dev/null &
# firefox &> /dev/null &
# kdeconnect-app &> /dev/null &

SSH Client Setup

We will be setting up:

  1. SSH Key Authentication Setup
  2. SSH Client Script (Optional)
SSH Key Authentication Setup
  1. Setup your SSH keys with ssh-keygen and use ssh-copy-id to authorize remote login to your host. Run ssh <user>@<ip_address> to login to your host. SSH keys automate login so you don't need to input your password!

  2. Optionally setup a ~/.ssh/config file to simplify the ssh command

    Host <some_alias>
        Hostname <ip_address>
        User <username>
        IdentityFile ~/.ssh/<your_private_key>
    

    Now you can use ssh <some_alias>. ssh <some_alias> <commands/script> will execute the command or script on the remote host.

Checkpoint

As a sanity check, let's make sure your setup is working so far!

Test Steps

With your monitor still plugged into your Sunshine host PC:

  1. ssh <alias>

  2. ~/scripts/sunshine.sh

  3. nvidia-smi

    You should see the Sunshine and Xorg processing running:

    nvidia-smi
    

    Output:

    +---------------------------------------------------------------------------------------+
    | NVIDIA-SMI 535.104.05             Driver Version: 535.104.05   CUDA Version: 12.2     |
    |-----------------------------------------+----------------------+----------------------+
    | GPU  Name                 Persistence-M | Bus-Id        Disp.A | Volatile Uncorr. ECC |
    | Fan  Temp   Perf          Pwr:Usage/Cap |         Memory-Usage | GPU-Util  Compute M. |
    |                                         |                      |               MIG M. |
    |=========================================+======================+======================|
    |   0  NVIDIA GeForce RTX 3070        Off | 00000000:01:00.0  On |                  N/A |
    | 30%   46C    P2              45W / 220W |    549MiB /  8192MiB |      2%      Default |
    |                                         |                      |                  N/A |
    +-----------------------------------------+----------------------+----------------------+
    
    +---------------------------------------------------------------------------------------+
    | Processes:                                                                            |
    |  GPU   GI   CI        PID   Type   Process name                            GPU Memory |
    |        ID   ID                                                             Usage      |
    |=======================================================================================|
    |    0   N/A  N/A      1393      G   /usr/lib/Xorg                                86MiB |
    |    0   N/A  N/A      1440    C+G   sunshine                                    293MiB |
    +---------------------------------------------------------------------------------------+
    
  4. Check /dev/uinput permissions

    ls -l /dev/uinput
    

    Output:

    crw------- 1 <user> <primary_group> 10, 223 Aug 29 17:31 /dev/uinput
    
  5. Connect to Sunshine host from a moonlight client

Now kill X and Sunshine by running pkill X on the host, unplug your monitors from your GPU, and repeat steps 1 - 5. You should get the same result. With this setup you don't need to modify the Xorg config regardless if monitors are plugged in or not.

pkill X
SSH Client Script (Optional)

At this point you have a working setup! For convenience, I created this bash script to automate the startup of the X server and Sunshine on the host. This can be run on Unix systems, or on Windows using the git-bash or any bash shell.

For Android/iOS you can install Linux emulators, e.g. Userland for Android and ISH for iOS. The neat part is that you can execute one script to launch Sunshine from your phone or tablet!

#!/bin/bash
set -e

ssh_args="<user>@192.168.X.X" # Or use alias set in ~/.ssh/config

check_ssh(){
  result=1
  # Note this checks infinitely, you could update this to have a max # of retries
  while [[ $result -ne 0 ]]
  do
    echo "checking host..."
    ssh $ssh_args "exit 0" 2>/dev/null
    result=$?
    [[ $result -ne 0 ]] && {
      echo "Failed to ssh to $ssh_args, with exit code $result"
    }
    sleep 3
  done
  echo "Host is ready for streaming!"
}

start_stream(){
  echo "Starting sunshine server on host..."
  echo "Start moonlight on your client of choice"
  # -f runs ssh in the background
  ssh -f $ssh_args "~/scripts/sunshine.sh &"
}

check_ssh
start_stream
exit_code=${?}

sleep 3
exit ${exit_code}

Next Steps

Congratulations, you can now stream your desktop headless! When trying this the first time, keep your monitors close by incase something isn't working right.

@seealso{Now that you have a virtual display, you may want to automate changing the resolution and refresh rate prior to connecting to an app. See Changing Resolution and Refresh Rate for more information.}

Autostart on boot without auto-login

Author MidwesternRodent
Difficulty Intermediate

After following this guide you will be able to:

  1. Turn on the Sunshine host via Moonlight's Wake on LAN (WoL) feature.
  2. Have Sunshine initialize to the login screen ready for you to enter your credentials.
  3. Login to your desktop session remotely, and have your pipewire audio and Sunshine tray icon work appropriately.

Specifications

This guide was created with the following software on the host:

  1. OpenSSH server and client (both on the host machine)
  2. Sunshine v2024.1003.1754422
  3. Debian 12 w/ KDE Plasma, SDDM, Wayland (also tested through xorg), and pipewire for audio.

The host hardware that was used in developing this guide:

  1. AMD 7900XTX
  2. AMD Ryzen 7 7800X3D
  3. 128GB DDR5 RAM
  4. 4 displays in total. 2 1080p displays, 1 3440x1440 display, and 1 4k Roku TV which is used as the always-on display for streaming. (could be subbed with a dummy plug).

If you have used this guide on any alternative hardware or software (including non-debian based distros) please, feel free to modify this guide and keep it growing!

Caveats

  1. When you login the machine will close your connection and you will have to reconnect. This is necessary due to an issue similar to why the Uinput Permissions Workaround is needed since SSH connections are not treated the same as graphical logins. This causes weirdness like sound not working through pipewire, and the tray icon for Sunshine not appearing. To get around this, we need to close the SSH initiated Sunshine service, and start a new Sunshine service with the permissions of the graphical desktop. Unfortunately, this closes the connection and forces you to reconnect through Moonlight. There is no way around this to the best of my knowledge without enabling auto-login.
  2. This guide does not cover using virtual displays. If you are using Nvidia graphics, see Remote SSH Headless Setup. If you are using AMD hardware, let me know if you find something or feel free to add it to this guide.
  3. I haven't (yet) found a way to disable sleep on the login screen, so if you wait too long after starting your PC, the display may go to sleep and Moonlight will have trouble connecting. Shutting down and using WoL works great though.

@attention{This is definitely safer than enabling auto-login directly, especially for a dual-use PC that is not only streamed via Moonlight, but is also used as a standard desktop. However I do not know the implications of having an always running SSH client to the localhost on the same machine. It may be possible for someone with significant knowledge and physical access to the machine to compromise your user account due to this always-running SSH session. However, that's better than just having the desktop always available, or opening up SSH even just your LAN since this guide specifically disables non-localhost connections, so I believe this is safer to use than auto-login for general users. As always, your threat model may vary.}

Prerequisites

In Remote SSH Headless Setup complete the following sections.

  1. Static IP Setup
  2. SSH Server Setup
  3. Virtual Display Setup
  4. Uinput Permissions Workaround
  5. Stream Launcher Script

@note{On a default Debian 12 install using KDE Plasma, you are using the Simple Desktop Display Manager (SDDM). Even if you are logging in to a Wayland session, SDDM by default starts with an xorg session, so this script does not need to be modified if you primarily use a Wayland session (the default) when you login.}

Instructions

Enable Wake on LAN

Wake on LAN (WoL) will allow you to send a magic packet to turn your PC on remotely. This is handled automatically by Moonlight's "send wake on lan" option in the app but you do need to enable it on your host machine first. The instructions on the debian.org site are a little hard to parse, so I've simplified them below.

@note{This may not work on all deb based distributions. If you know of a better way for POP OS, Ubuntu, or another debian based distro please feel free to edit the guide yourself, or let me know.}

First, find the name of your ethernet interface.

ip link show

When I run this command, these are the results I receive

1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000  
   link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00  
2: enp117s0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP mode DEFAULT group default qlen 1000  
   link/ether 9c:6b:00:59:33:c1 brd ff:ff:ff:ff:ff:ff

We can ignore the loopback interface, and I can see my ethernet interface is called enp117s0. You might see wireless interfaces here as well but they can also be ignored.

@note{If your PC is only connected via Wi-Fi, it is still technically possible to get this working, but it is outside the scope of this guide and requires more networking knowledge and a Wi-Fi chip that supports WoL. If this is your first foray into linux, I'd recommend just getting a cable.}

Now I can install ethtool and modify my interface to allow Wake on LAN. For your use, replace enp117s0 with whatever the name of your ethernet interface is from the command ip link show

sudo apt update
sudo apt install ethtool
sudo ethtool -s enp117s0 wol g
SSH Client Setup

To start, we need to install an SSH client (which is different from the server in Remote SSH Headless Setup) on our machine if this not already done. Open a terminal and enter the following commands.

sudo apt update
sudo apt install openssh-client

Next we need to generate the keys we will use to connect to our SSH session. This is as simple as running the following in a terminal:

ssh-keygen

and simply pressing enter through the default options. This will place a file called id_rsa and id_rsa.pub in the hidden folder ~/.ssh/. This is the default key used when this user initiates an SSH session.

Next, we'll copy that public key to the ~/.ssh/authorized_users file. These are the public keys allowed to access this machine over SSH, and will allow us to establish an SSH connection with this user to the SSH server running on the localhost.

cat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized_keys 

@tip{If you also want any other machines (e.g. a laptop or Steam Deck) to connect to your machine remotely over ssh, be sure to generate a pubkey on that machine and append it to the authorized_keys file like we did above.}

SSH Server Modifications

We'll want to make a few modification to the SSH server on the Sunshine host, both for convenience and security.

Modify /etc/ssh/sshd_config with the following changes:

@tabs{ @tab{nano | bash sudo nano /etc/ssh/sshd_config } @tab{vim | bash sudo vi /etc/ssh/sshd_config } }

Find the line with PasswordAuthentication and make sure it is set to no (removed the # if present. Then find the line PubkeyAuthentication and make sure it is set to yes and remove the # from the beginning if present. When you're done you should have these two lines in your config somewhere.

PubkeyAuthentication yes
PasswordAuthentication no

@tip{Using publickey encryption for SSH connections significantly increases your protection against brute force attacks, and protects you against a rogue machine pretending to be your SSH server and stealing your password.}

The next step is optional, but if you do not plan on connecting to your computer remotely via ssh and only have installed SSH for the purposes of using Sunshine, it's a good idea to disable listening for remote SSH connections. Do this by changing the following lines near the top of your sshd_config:

#ListenAddress 0.0.0.0  
#ListenAddress ::

To the following:

ListenAddress 127.0.0.1
ListenAddress ::1

This will only allow SSH connections coming from your computer itself.

@tip{on some distributions, the maintainers have added some files in /etc/ssh/sshd_config.d/ which are pulled into your sshd_config. These modifications can conflict with what we've just done. If you have any files in /etc/ssh/sshd_config.d/, make sure they do not include any of the changes we've just made or you will experience problems. If they do, you can comment out those lines by placing a # at their beginning, or delete the files safely if you don't plan to use SSH for anything other than Sunshine.}

Quick Test and Accept Host Authenticity.

Next, let's reboot the machine and try to connect! Accept any warnings about the unidentified host at this time, you'll never see those appear again unless something changes with your setup.

ssh $(whoami)@localhost

You should see a new login prompt for the machine you're already on, and when you type exit you should just see

logout
Connection to localhost closed.
Run sunshine-setup on boot over SSH

Thanks to this comment from Gavin Haynes on Unix Stack exchange, we can establish an SSH connection on boot to run the sunshine-setup script via a systemd service.

Disable default Sunshine services

These service files are sometimes overwritten when updating Sunshine with the .deb. So we'll be making new ones and disabling the included service files for our purposes.

sudo sytstemctl disable sunshine
systemctl --user disable sunshine

@note{In order to disable the user service, you must be logged in to the graphical desktop environment and run the command from a GUI terminal. You'll also likely need to approve a polkit request (a graphical popup that asks for your password). Trying to disable the user service without being signed in to the graphical environment is a recipe for pain, and is why sudo is not invoked on the second line in the command above.}

Create the autossh-sunshine-start script

@tabs{ @tab{nano | bash sudo nano /usr/local/bin/autossh-sunshine-start } @tab{vim | bash sudo vi /usr/local/bin/autossh-sunshine-start } }

Copy the below script to that location and replace {USERNAME} wherever it occurs with the username you created the SSH public key for in the previous section.

#!/bin/bash
ssh -i /home/{USERNAME}/.ssh/id_rsa {USERNAME}@localhost
"/home/{USERNAME}/scripts/sunshine.sh"

@attention{This script uses the location of the script in Stream Launcher Script. Please complete that section before continuing.}

Once you've created the script, be sure to make it executable by running:

sudo chmod +x /usr/local/bin/autossh-sunshine-start
Create the autossh systemd service file

@tabs{ @tab{nano | bash sudo nano /etc/systemd/system/autossh-sunshine.service } @tab{vim | bash sudo vi /etc/systemd/system/autossh-sunshine.service } }

Copy and paste the below systemd file and save it to the location in the commands above.

[Unit]  
Description=Start sunshine over an localhost SSH connection on boot
Requires=sshd.service
After=sshd.service

[Service]
ExecStartPre=/bin/sleep 5
ExecStart=/usr/local/bin/autossh-sunshine-start
Restart=on-failure
RestartSec=5s

[Install]
WantedBy=multi-user.target

Make it executable, and enable the service when you're done.

sudo chmod +x /etc/systemd/system/autossh-sunshine.service
sudo systemctl start autossh-sunshine
sudo systemctl enable autossh-sunshine

This point is a good time for a sanity check, so restart your PC and try to sign in to your desktop via Moonlight. You should be able to access the login screen, enter your credentials, and control the user session. At this point you'll notice the reason for the next section as your audio will be non-functional and you won't see any tray icon for Sunshine. If you don't care about audio (and maybe a couple other bugs you might encounter from time to time due to the permissions difference between an SSH session and the desktop session), you can consider yourself finished at this point!

@note{You might also notice some issues if you have multiple monitors setup (including the dummy plug), like the mouse cursor not being on the right screen for you to login. We will address this in the last step of this guide. It requires messing with some configs for SDDM.}

Getting the audio working

To get the audio (and tray icon, etc...) working we will create a systemd user service, that will start on a graphical login, kill the autossh-sunshine system service, and start Sunshine just like the standard Sunshine service. This service will also need to call the autossh-sunshine system service before it is stopped as the user service will be killed when we log out of the graphical session, so we want to make sure we restart that SSH service so we don't lose the ability to log back in if we need to.

@tabs{ @tab{nano | bash sudo nano /usr/lib/systemd/user/sunshine-after-login.service } @tab{vim | bash sudo vi /usr/lib/systemd/user/sunshine-after-login.service } }

Once again, copy the below service file into your text editor at the location above.

[Unit]  
Description=Start Sunshine with the permissions of the graphical desktop session
StartLimitIntervalSec=500
StartLimitBurst=5

[Service]  
# Avoid starting Sunshine before the desktop is fully initialized.
ExecStartPre=/usr/bin/pkill sunshine
ExecStartPre=/bin/sleep 5
ExecStart=/usr/bin/sunshine
ExecStopPost=/usr/bin/systemctl start autossh-sunshine

Restart=on-failure
RestartSec=5s

[Install]
WantedBy=xdg-desktop-autostart.target

Make it executable, and enable it.

sudo chmod +x /usr/lib/systemd/user/sunshine-after-login.service
systemctl --user enable sunshine-after-login
Polkit Rules for Sunshine User Service

Since this is being run with the permissions of the graphical session, we need to make a polkit modification to allow it to call the system service autossh-sunshine when this user service is stopped, without prompting us for a password.

@tabs{ @tab{nano | bash sudo nano /etc/polkit-1/rules.d/sunshine.rules } @tab{vim | bash sudo vi /etc/polkit-1/rules.d/sunshine.rules } }

Once again, copy the below to the .rules file in your text editor.

polkit.addRule(function(action, subject) {  
   if (action.id == "org.freedesktop.systemd1.manage-units" &&  
       action.lookup("unit") == "autossh-sunshine.service")  
   {  
       return polkit.Result.YES;  
   }  
})
Modifications to sudoers.d files

Lastly, we need to make a few modifications to the sudoers file for our users. Replace {USERNAME} below with your username. You will be prompted to select either vi or nano for your editor if you've not used this command before, choose whichever you prefer.

sudo visudo /etc/sudoers.d/{USERNAME}

@danger{NEVER modify a file in sudoers.d directly. Always use the visudo command. This command checks your changes before saving the file, and if the resulting changes would break sudo on your system, it will prompt you to fix them. Modifying the file with nano or vim directly does not give you this sanity check and introduces the possibility of losing sudo access to your machine. Tread carefully, and make a backup.}

As always, copy and paste the below into your user's sudoers.d configuration. Replace {USERNAME} with your username, and {HOSTNAME} with the name of your computer.

{USERNAME} {HOSTNAME} = (root) NOPASSWD: /home/{USERNAME}/scripts/sunshine-setup.sh
{USERNAME} {HOSTNAME} = (root) NOPASSWD: /bin/sunshine
{USERNAME} {HOSTNAME} = (root) NOPASSWD: /usr/bin/systemctl start autossh-sunshine
{USERNAME} {HOSTNAME} = (root) NOPASSWD: /usr/bin/systemctl --user start sunshine-after-login
# The below is optional, but will allow us to send trigger a shutdown with a sunshine prep command, if desired.
{USERNAME} {HOSTNAME} = (root) NOPASSWD: /usr/sbin/shutdown

Once again, restart your computer and do a quick test. Make sure you can connect to the PC to login and enter your credentials. You should be booted out of the system, and then can reconnect a few seconds later to the logged-in desktop session. You should see a tray icon for Sunshine, and the sound should be working (or you may need to manually select the sunshine-sink at least the first time).

If you don't have multiple monitors, at this point you can consider yourself done!

Configuring the login screen layout for multiple monitors

This is not Sunshine specific, but is a frequent problem I had setting up Sunshine and thought it pertinent to add to the guide. If you are using multiple monitors (even a single monitor with a dummy plug may have this problem) you might notice the streamed login screen has one or more of the following problems:

  1. The text is way too small to see (caused by a too-high resolution)
  2. The mouse cursor is off on some other screen (caused by not mirroring the displays)
  3. There are multiple login screens overlapping each other (caused by differing resolutions, and trying to mirror the display).
Log in to an X11 Session

This can be fixed, by modifying some scripts called by SDDM on boot. To start though, we need to make sure we're logged into an x11 session, not Wayland or the terminal. As the Wayland session will give us incorrect information, and the terminal will give us no information since no graphical environment exists. SDDM initially starts an x11 session to display the login screen so we need to use xorg commands to change the display configuration.

To do this, log out of your desktop session on the Sunshine host, and somewhere on the lower left of your screen (depending on your SDDM theme) there will be some text that on Debian 12 KDE Plasma defaults to saying Session: Plasma (Wayland). Select this and choose Plasma (X11) from the drop down menu and sign in.

Find your monitor identifiers.

Open a terminal and run:

xrandr | grep -w connected

This will require some more sleuthing on your part. Different PC hardware, and different monitors / connectors, display the names differently. Some start at 0, some start 1. Some spell out "DisplayPort" some, say "DP". You will need to modify all of the commands from here on out based on the output of the above command. I will use the output I receive below as the example for the rest of this guide.

DisplayPort-0 connected (normal left inverted right x axis y axis)  
DisplayPort-1 connected (normal left inverted right x axis y axis)
DisplayPort-2 connected (normal left inverted right x axis y axis)
HDMI-A-0 connected primary 1920x1080+0+0 (normal left inverted right x axis y axis) 800mm x 450mm

@note{If I instead run this command on Wayland, I get the following useless output. Hence the need to sign in to an x11 session.

XWAYLAND0 connected 2592x1458+6031+0 (normal left inverted right x axis y axis) 600mm x 340mm
XWAYLAND1 connected 2592x1458+0+0 (normal left inverted right x axis y axis) 480mm x 270mm
XWAYLAND2 connected primary 3440x1440+2592+0 (normal left inverted right x axis y axis) 800mm x 330mm
XWAYLAND3 connected 2592x1458+0+0 (normal left inverted right x axis y axis) 1440mm x 810mm

}

From this, you can see that my monitors are named the following under an x11 session.

DisplayPort-0 DisplayPort-1 DisplayPort-2 HDMI-A-0

@tip{If you have a label maker, now would be a good time to unplug some cables, determine where they are on your system, and label the outputs on your graphics card to ease changing your setup in the future.}

In my setup, after moving some inputs I changed my system so that these cables correspond to the below monitors

Display Name Monitor
DisplayPort-0 rightmost 1080p display
DisplayPort-1 leftmost 1080p display
DisplayPort-2 middle 3440x1440 display
HDMI-A-0 4k Roku TV (and dummy plug)
Modify the SDDM startup script

For my purposes, I would prefer to have the Roku TV (which doubles as my always-on dummy plug) to always display a 1080p screen on login (this can be changed automatically after login). And I would like to retain the ability to use my leftmost monitor to login to my physical desktop, but I'd like to disable my primary and rightmost displays.

To do this, we need to modify the SDDM startup script to shut off DisplayPort-1 and DisplayPort-2, set HDMI-A-0 to 1080p and mirror it with DisplayPort-1.

@tabs{ @tab{nano | bash sudo nano /usr/share/sddm/scripts/Xsetup } @tab{vim | bash sudo vi /usr/share/sddm/scripts/Xsetup } }

Which will open a script that looks like this. We will not be removing these lines.

#!/bin/sh  
# Xsetup - run as root before the login dialog appears  
  
if [ -e /sbin/prime-offload ]; then  
   echo running NVIDIA Prime setup /sbin/prime-offload  
   /sbin/prime-offload  
fi

At the bottom of this Xsetup script though, we can add some xrandr commands

To shut a display off, we can use: xrandr --output {DISPLAYNAME} --off.

To set a display as the primary and accept it's automatic (usually the maximum, but not always especially on TVs where the default refresh rate may be lower) resolution and refresh rate we can use: xrandr --output {DISPLAYNAME} --auto --primary.

To set a display to a specific resolution we can use: xrandr --output {DISPLAYNAME} --mode {PIXELWIDTH}x{PIXELLENGTH}.

And lastly, to mirror a display we can use: xrandr --output {DISPLAYNAME} --same-as {ANOTHER-DISPLAY}

So with my desire to mirror my TV and left displays, my Xsetup script now looks like this:

#!/bin/sh  
# Xsetup - run as root before the login dialog appears  
  
if [ -e /sbin/prime-offload ]; then  
   echo running NVIDIA Prime setup /sbin/prime-offload  
   /sbin/prime-offload  
fi  
  
xrandr --output DisplayPort-0 --off  
xrandr --output DisplayPort-2 --off  
xrandr --output DisplayPort-1 --auto --primary  
xrandr --output HDMI-A-0 --mode 1920x1080  
xrandr --output HDMI-A-0 --same-as DisplayPort-1

Save this file, reboot, and you should see your login screen now respects these settings. Make sure when you log back in, you select a Wayland session (if that is your preferred session manager).

Next Steps

Congratulations! You now have Sunshine starting on boot, you can login to your session remotely, you get all the benefits of the graphical session permissions, and you can safely shut down your PC with the confidence you can turn it back on when needed.

@seealso{As Eric Dong recommended, I'll also send you to automate changing your displays. You can add multiple commands, to turn off, or configure as many displays as you'd like with the sunshine prep commands. See Changing Resolution and Refresh Rate for more information and remember that the display names for your prep commands, may be different than what you found for SDDM.}

macOS

@todo{It's looking lonely here.}

Windows

Author BeeLeDev
Difficulty Intermediate

Discord call cancellation

Cancel Discord call audio with Voicemeeter (Standard)

Voicemeeter Configuration

  1. Click "Hardware Out"
  2. Set the physical device you receive audio to as your Hardware Out with MME
  3. Turn on BUS A for the Virtual Input

Windows Configuration

  1. Open the sound settings
  2. Set your default Playback as Voicemeeter Input

@tip{Run audio in the background to find the device that your Virtual Input is using (Voicemeeter In #), you will see the bar to the right of the device have green bars going up and down. This device will be referred to as Voicemeeter Input.}

Discord Configuration

  1. Open the settings
  2. Go to Voice & Video
  3. Set your Output Device as the physical device you receive audio to

@tip{It is usually the same device you set for Hardware Out in Voicemeeter.}

Sunshine Configuration

  1. Go to Configuration
  2. Go to the Audio/Video tab
  3. Set Virtual Sink as Voicemeeter Input

@note{This should be the device you set as default previously in Playback.}

[TOC]