Sunshine self-hosted game stream

So I found why it refused to start, the module was not loaded

  boot.kernelModules = [ "uinput" ];

the service does not start, I can only do it in a terminal

remains to find how to do with my not compatible screen resolutions (pc screen 21:9, tablet 4:3) :sweat_smile:

1 Like

It’s an ‘extrarules’ option, which basically just creates ‘a symbolic link’ in /etc/blah/blah…

The nix code that setup up the extraRules could do a bit of parsing of the OPTIONS+= , and warn the users that they are going to need a related kernel module to get it to work.

However, there are very few OPTIONS that need a kernel module , then it’s probably not worth doing.

I checked the udev docs
static_node= SNIP SNIP SNIP The static nodes might not have a corresponding kernel device; they are used to trigger automatic kernel module loading when they are accessed.

So, normal udev, automatically loads this driver into the kernel, I bet nix isn’t doing that.

if you create a service for sunshine and i hope they you do … you just need get the service to add this kernel module by default.

https://github.com/NixOS/nixpkgs/issues/70471

and

https://github.com/NixOS/nixpkgs/pull/70499

has all the details (not gory at all) and something you can adapt your service to do.

Then you’ll probably have the perfect service, perfect package, and perfect PR.

Unfortunately, after many attempts I have errors with wayfire to create a fake screen

if i add WLR_BACKENDS=headless
Couldn't find matching mode 1600x2176@60 for output HEADLESS-1. Trying to use custom mode

or if i add WLR_BACKENDS=libinput,drm,headless
Could not add backend: multiple renderers at the same time aren't supported
failled to add backend 'headless'

Sounds like your close, I’m not familiar with wayfire, so can’t offer any idea there. Maybe the wayfire author can chime in with a solution?

or maybe not.

Hey! I’m trying to make this work. This is my current config:

file in repo

It spits two errors when I execute it:

[2023:04:22:01:04:34]: Error: avahi::entry_group_new() failed: Not permitted
(sunshine:73678): Gdk-CRITICAL **: 01:04:37.152: gdk_window_thaw_toplevel_updates: assertion 'window->update_and_descendants_freeze_count > 0' failed

I think the last one is regarding widgets/tray icons, etc. The other one I understand is for descovery in the WLAN. Anyways, I start Sunshine, open Moonlight on my phone, enter my IP and it says it can’t connect, that I might have to check the ports are open. I have this:

❯ ss -lptn
State      Recv-Q      Send-Q           Local Address:Port            Peer Address:Port     Process
LISTEN     0           128                    0.0.0.0:22                   0.0.0.0:*
LISTEN     0           4096                   0.0.0.0:48010                0.0.0.0:*
LISTEN     0           4096                   0.0.0.0:47984                0.0.0.0:*
LISTEN     0           4096                   0.0.0.0:47989                0.0.0.0:*
LISTEN     0           4096                   0.0.0.0:47990                0.0.0.0:*
LISTEN     0           128                       [::]:22                      [::]:*

These are the range for Sunshine, so it should be working. Any help/pointers?

Hey! Sorry I bother you. I saw that you are the one that wrote the PR for this pkg. Could you give me a hand on what could be going wrong?

For the first error, believe services.avahi.publish.userServices = true is needed since you are running Sunshine as a user unit.

As for your connectivity issue, are you sure the ports are open on your firewall? Check with iptables -L or equivalent and make sure you see them? Alternatively you can try Moonlight locally and just make sure it can see the Sunshine instance.

1 Like

Yep, I read through most of your config and saw the avahi config. I wasn’t using it before so I added it to mine.

About the ports, I was sure I had them open as I had the proper ports configured in the flake, but alas, I disabled the firewall and it worked!

I’m just two steps away from completely setting it up. First, it’s not opening apps! I’ll add a log in an hour or so of what’s happening, but if I execute the command to open Steam in Big Picture from the console, it works. When I do it from Moonlight, I get this:

[2023:04:24:22:48:50]: Info: Spawning [setsid steam steam://open/bigpicture] in ["/run/current-system/sw/bin"]
[2023:04:24:22:48:50]: Warning: run_unprivileged() is not yet implemented for this platform. The new process will run with Sunshine's permissions.

On the other hand, I have to work on optimizing the gaming experience. It stutters and lags playing Star Wars Fallen Order with an 6800xt in 1080p at medium settings, so I think there is room to improve.

Anyways, thanks for the package and the help! I love this from this community

Were you able to discover why steam bigpiccture is not opening?

I even tried to nixify apps.json with no success…

{ config, lib, pkgs, ... }:

let
  apps = {
    env = "/run/current-system/sw/bin";
    apps = [
      {
         name = "Steam";
         output = "steam.txt";
         detached = ["setsid ${pkgs.steam}/bin/steam steam://open/bigpicture"];
         image-path = "steam.png";
      }
    ];
  };
in
{
  xdg.configFile = {
    "sunshine/sunshine.conf".source = ./sunshine.conf;
    "sunshine/apps.json".text = builtins.toJSON apps;
  };
}

Basically I have this error:

[2023:06:16:21:32:42]: Info: Spawning [setsid /nix/store/b7zgnxgzmmfmwixxb9gw3m86rj5brzwb-steam/bin/steam steam://open/bigpicture] in [""]
[2023:06:16:21:32:42]: Warning: run_unprivileged() is not yet implemented for this platform. The new process will run with Sunshine's permissions.
[2023:06:16:21:32:42]: Warning: Couldn't spawn [setsid /nix/store/b7zgnxgzmmfmwixxb9gw3m86rj5brzwb-steam/bin/steam steam://open/bigpicture]: System: No such file or directory
[2

Btw, thank for sharing the avahi tip. I was having trouble figuring out why I could not find the device. I have read more about what is avahi.

Edit: I find it odd it cant find setsid as I specified the env

Update:

Managed to run big picture with:

let
  apps = {
    env = "/run/current-system/sw/bin";
    apps = [
      {
         name = "Steam";
         output = "steam.txt";
         detached = ["${pkgs.util-linux}/bin/setsid ${pkgs.steam}/bin/steam steam://open/bigpicture"];
         image-path = "steam.png";
      }
    ];
  };
in
{
  xdg.configFile = {
    "sunshine/sunshine.conf".source = ./sunshine.conf;
    "sunshine/apps.json".text = builtins.toJSON apps;
  };
}

Still need to figure out why env does not work but this for now does the trick.

Btw, regarding big picture being slow: enable hardware acceleration under settings.

1 Like

How do I use this?

I’ve been trying to figure out how to get steam to load as an app without much luck. But I’m not sure where to put the above referenced code to be able to use it properly.

I’m running Sunshine as a user service using this nix config file and using the import function into the main nix config file:

Would I just be adding this to this existing file? Or do I need to create a new .nix config file. I’m fairly new to Nix in general and would appreciate any help.

Edit: This service file was mainly pulled from another one I found on github, so it may not be correct. Sunshine does start and I can connect. But I’m unable to edit the apps.json file without using a root account. I’m not using home-manager.

:wave:

You will need the generate the file using Nix, you can use for example home-manager, see my snippet here:

Sunshine self-hosted game stream - #15 by bphenriques (you can ignore the sunshine.conf)

My service setup is similar (followed some examples and official docs). Needs some cleanup though: https://github.com/bphenriques/dotfiles/blob/d04005dac57b00923e16252c84b34f57be1ae44c/nixos/modules/services/sunshine.nix. I was able to connect to sunshine and use my controller.

I have to manually introduce the IP but I prefer that over more complex configs (avahi works but I dont know enough about it to include it yet).

Edit: Answering your question specifically. There are many ways:

  1. (simpler IMHO) In the same file where you enable the service, you can:
{
    ...
    services.sunshine.enable = true; # Enable service
    home-manager.users.<username> = {
       xdg.configFile."sunshine/apps.json".text = builtins.toJSON
    {
      env = "/run/current-system/sw/bin";
      apps = [
        {
           name = "Steam";
           output = "steam.txt";
           detached = ["${pkgs.util-linux}/bin/setsid ${pkgs.steam}/bin/steam steam://open/bigpicture"];
           image-path = "steam.png";
        }
      ];
    };
    };    
}
  1. Create a separate file just to manage home and then import it under the right key.
  2. (harder), use nixos to create the file but you will need to change the service to pass file_app=<generated_file> (docs) when running sunshine. Would require changing how the service runs to support additional arguments.
1 Like

That helped some, I got a bit closer. Steam won’t start, but I am generating the configs via home-manager.

I got resolution switching working, but it seems steam won’t open due to a permissions error most likely…

Error from steam.txt

bwrap: Unexpected capabilities but not setuid, old file caps config?

Sunshine log:

[2023:06:21:16:07:33]: Info: Spawning [/nix/store/87mfa22rgff50l6fafclzkhy9b9s0b0a-util-linux-2.38.1-bin/bin/setsid /nix/store/jx6aiqgwvxp6kmxhwrl4ipg9971m8q8w-steam/bin/steam steam://open/bigpicture] in ["/nix/store/87mfa22rgff50l6fafclzkhy9b9s0b0a-util-linux-2.38.1-bin/bin"]
[2023:06:21:16:07:33]: Warning: run_unprivileged() is not yet implemented for this platform. The new process will run with Sunshine's permissions.

Edit: Here is the home-manager config:

home-manager.users.<username> = { pkgs, ... }: {  
    home.stateVersion = "23.05";  
    home.packages = [pkgs.libreoffice];
    xdg.configFile."sunshine/apps.json".text = builtins.toJSON
    {
      env = "/run/current-system/sw/bin";
      apps = [
        {
           name = "Steam";
           output = "steam.txt";
           detached = ["${pkgs.util-linux}/bin/setsid ${pkgs.steam}/bin/steam steam://open/bigpicture"];
           image-path = "steam.png";
        }
      ];
    };
    xdg.configFile."sunshine/sunshine.conf".text = ''
      global_prep_cmd = [{"do":"${pkgs.libsForQt5.libkscreen}/bin/kscreen-doctor output.1.mode.12","undo":"${pkgs.libsForQt5.libkscreen}/bin/kscreen-doctor output.1.mode.0"}]
      output_name = 1
    '';

    nixpkgs.config = {
      allowUnfree = true;
    };
  };

The run_unprivileged() log I also have (dont know exactly… but is not bothering me yet). Let me know if you find out how to fix it.

Regarding the bwrap: Unexpected capabilities but not setuid, old file caps config?, I am not sure but it might be related with some settings required and documented.

I am also fairly new to the scene, but can you try including the remaining setup parts ?

{
   ...
       # Make it work for KMS.
    # TODO: Should I migrate cap_sys_admin+p to CapabilityBoundingSet within the systemd?
    security.wrappers.sunshine = {
      owner = "root";
      group = "root";
      capabilities = "cap_sys_admin+p";
      source = "${pkgs.sunshine}/bin/sunshine";
    };

    # Requires to simulate input
    boot.kernelModules = [ "uinput" ];
    services.udev.extraRules = ''
      KERNEL=="uinput", SUBSYSTEM=="misc", OPTIONS+="static_node=uinput", TAG+="uaccess"
    '';
}

I am under the impression that that the KMS setup is not required for X11 but does not hurt (much) having it as far as I can tell.

Updated configs:
Home-Manager: https://github.com/RandomNinjaAtk/nixos/blob/2ea96ee86254d4b0728e538c7e75f3d7754cb51e/home-manager.nix
Sunshine Service: https://github.com/RandomNinjaAtk/nixos/blob/2ea96ee86254d4b0728e538c7e75f3d7754cb51e/services.sunshine.nix

Still the same error:

[2023:06:22:08:25:59]: Info: Avahi service Sunshine successfully established.
[2023:06:22:08:26:59]: Info: Executing Do Cmd: [/nix/store/v9k2l6g2hl7kb2f5dw5zl5vxbiyrw43w-libkscreen-5.27.5/bin/kscreen-doctor output.1.mode.12]
[2023:06:22:08:26:59]: Warning: run_unprivileged() is not yet implemented for this platform. The new process will run with Sunshine's permissions.
[2023:06:22:08:26:59]: Info: Spawning [/nix/store/87mfa22rgff50l6fafclzkhy9b9s0b0a-util-linux-2.38.1-bin/bin/setsid /nix/store/jx6aiqgwvxp6kmxhwrl4ipg9971m8q8w-steam/bin/steam steam://open/bigpicture] in ["/nix/store/87mfa22rgff50l6fafclzkhy9b9s0b0a-util-linux-2.38.1-bin/bin"]
[2023:06:22:08:26:59]: Warning: run_unprivileged() is not yet implemented for this platform. The new process will run with Sunshine's permissions.
[2023:06:22:08:26:59]: Info: Executing [Desktop]
[2023:06:22:08:26:59]: Info: CLIENT CONNECTED

kscreen-doctor works, but steam does not. If I run the listed command:

/nix/store/87mfa22rgff50l6fafclzkhy9b9s0b0a-util-linux-2.38.1-bin/bin/setsid /nix/store/jx6aiqgwvxp6kmxhwrl4ipg9971m8q8w-steam/bin/steam steam://open/bigpicture

From the terminal, it works as expected. But if I attempt to run the same command from the root user, it does not work and outputs:

[root@workstation-01:/etc/nixos]# /nix/store/87mfa22rgff50l6fafclzkhy9b9s0b0a-util-linux-2.38.1-bin/bin/setsid /nix/store/jx6aiqgwvxp6kmxhwrl4ipg9971m8q8w-steam/bin/steam steam://open/bigpicture
[root@workstation-01:/etc/nixos]# bwrap: Can't chdir to /etc/nixos: No such file or directory

Edit:
From some additional experimentation, the problem is caused by the security wrapper. If I remove the wrapper, the application loads normally as you’d expect but then you get the cap_sys_admin+p error in sunshine and cannot connect…

I have no idea :\ I use KDE as well but do not use kscreen-doctor (I use the default conf). I am using (mostly) the latest version of nixpkgs-unstable.

Hi! Did you ever find a solution to this? You are correct that this is caused by the security wrapper, but is there any way around it?

I’m facing the same issue. Have you managed to solve it?

I’ve worked around the security wrapper issue by creating a separate service for launching Steam games, one that is not encumbered by a security wrapper.

First, the service:

  systemd.user.services.steam-run-url-service = {
    enable = true;
    description = "Listen and starts steam games by id";
    wantedBy = ["graphical-session.target"];
    partOf = [ "graphical-session.target" ];
    wants = [ "graphical-session.target" ];
    after = [ "graphical-session.target" ];
    serviceConfig.Restart = "on-failure";
    script = toString (pkgs.writers.writePython3 "steam-run-url-service" {} ''
      import os
      from pathlib import Path
      import subprocess

      pipe_path = Path(f'/run/user/{os.getuid()}/steam-run-url.fifo')
      try:
          pipe_path.parent.mkdir(parents=True, exist_ok=True)
          pipe_path.unlink(missing_ok=True)
          os.mkfifo(pipe_path, 0o600)
          while True:
              with pipe_path.open(encoding='utf-8') as pipe:
                  subprocess.Popen(['steam', pipe.read().strip()])
      finally:
          pipe_path.unlink(missing_ok=True)
    '');
    path = [
      pkgs.steam
    ];

The service waits for a client to pipe Steam URL (e.g. steam://rungameid/1086940) to a file at /run/user/1000/steam-run-url.fifo (where 1000 is your user id). Upon reading an URL from the file the service launches Steam, passing the received URL to it.

Once you have the service running you can start a game with command:

# Launch Baldur's Gate 3
echo "steam://rungameid/1086940" > "/run/user/$(id --user)/steam-run-url.fifo"

Any terminal output from the game goes to steam-run-url-service’s journal, which you can see with:

journalctl --user -u steam-run-url-service.service

To make it easier to launch games the launch command can be wrapped into a script:

  steam-run-url = pkgs.writeShellApplication {
    name = "steam-run-url";
    text = ''
      echo "$1" > "/run/user/$(id --user)/steam-run-url.fifo"
    '';
    runtimeInputs = [
      pkgs.coreutils  # For `id` command
    ];
  };

Then add it to your environment so that it can be called from shell:

environment.systemPackages = [ steam-run-url ];

Examples:

steam-run-url steam://rungameid/1086940  # Start Baldur's Gate 3
steam-run-url steam://open/bigpicture    # Start Steam in Big Picture mode

And finally, put it to Sunshine service’s PATH. This way you can use it in Sunshine’s app settings as a detached command:

systemd.user.services.sunshine.path = [ steam-run-url ];

In Sunshine’s app settings replace e.g. call:

setsid steam steam://rungameid/1086940

With:

steam-run-url steam://rungameid/1086940

See my Sunshine config for full example.

1 Like

Thank you! it will surely be useful to me :wink:

Someone managed to turn on the screen with sunshine the hyprctl dispatch dpms command we work in the terminal but sunshine can’t do it.

Since headless is broken immediately, I stream the screen directly, but I have to turn on the screen first.