diff --git a/modules/darwin/apps.nix b/modules/darwin/apps.nix index 5f8c561b..b217c8f2 100644 --- a/modules/darwin/apps.nix +++ b/modules/darwin/apps.nix @@ -158,6 +158,8 @@ in { "telegram" "discord" "microsoft-remote-desktop" + "moonlight" # remote desktop client + "rustdesk" # "anki" "shadowsocksx-ng" # proxy tool diff --git a/modules/nixos/desktop/game/steam.nix b/modules/nixos/desktop/game/steam.nix index d16274ca..cf58a24e 100644 --- a/modules/nixos/desktop/game/steam.nix +++ b/modules/nixos/desktop/game/steam.nix @@ -1,6 +1,7 @@ # https://github.com/fufexan/dotfiles/blob/483680e/system/programs/steam.nix {pkgs, ...}: { # https://wiki.archlinux.org/title/steam + # Games installed by Steam works fine on NixOS, no other configuration needed. programs.steam = { # Some location that should be persistent: # ~/.local/share/Steam - The default Steam install location diff --git a/modules/nixos/desktop/remote-desktop/README.md b/modules/nixos/desktop/remote-desktop/README.md new file mode 100644 index 00000000..2eef9997 --- /dev/null +++ b/modules/nixos/desktop/remote-desktop/README.md @@ -0,0 +1,10 @@ +# Remote Desktop + +1. **X11**: We have `xrdp` & `ssh -x` for remote desktop access, which works well for most use cases. +2. **Wayland**: (not tested) + 1. `waypipe`: similar to `ssh -X`, transfer wayland data over a ssh connection. + 2. [rustdesk](https://github.com/rustdesk/rustdesk): a remote desktop client/server written in rust. + 1. confirmed broken currently: + 3. [sunshine server](https://github.com/LizardByte/Sunshine) + [moonlight client](https://github.com/moonlight-stream): It's designed for game streaming, but it can be used for remote desktop as well. + 1. broken currently: + diff --git a/modules/nixos/desktop/remote-desktop/default.nix b/modules/nixos/desktop/remote-desktop/default.nix new file mode 100644 index 00000000..3ab750cd --- /dev/null +++ b/modules/nixos/desktop/remote-desktop/default.nix @@ -0,0 +1,13 @@ +{ + pkgs, + mylib, + ... +}: { + imports = mylib.scanPaths ./.; + + environment.systemPackages = with pkgs; [ + waypipe + moonlight-qt # moonlight client, for streaming games/desktop from a PC + rustdesk # p2p remote desktop + ]; +} diff --git a/modules/nixos/desktop/remote-desktop/sunshine.nix b/modules/nixos/desktop/remote-desktop/sunshine.nix new file mode 100644 index 00000000..b8e9bdcc --- /dev/null +++ b/modules/nixos/desktop/remote-desktop/sunshine.nix @@ -0,0 +1,70 @@ +{ + config, + lib, + pkgs, + ... +}: +# =============================================================================== +# +# Sunshine: A self-hosted game stream server for Moonlight(Client). +# It's designed for game streaming, but it can be used for remote desktop as well. +# +# TODO: currently broken, fixed but not released yet: https://github.com/LizardByte/Sunshine/pull/1977 +# +# How to use(Web Console: ): +# https://docs.lizardbyte.dev/projects/sunshine/en/latest/about/usage.html +# +# Check Service Status +# systemctl --user status sunshine +# Check logs +# journalctl --user -u sunshine --since "2 minutes ago" +# +# References: +# https://github.com/LongerHV/nixos-configuration/blob/c7a06a2125673c472946cda68b918f68c635c41f/modules/nixos/sunshine.nix +# https://github.com/RandomNinjaAtk/nixos/blob/fc7d6e8734e6de175e0a18a43460c48003108540/services.sunshine.nix +# +# =============================================================================== +{ + 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" + ''; + + # systemd.user.services.sunshine = { + # description = "A self-hosted game stream server for Moonlight(Client)"; + # after = ["graphical-session-pre.target"]; + # wants = ["graphical-session-pre.target"]; + # wantedBy = ["graphical-session.target"]; + # startLimitIntervalSec = 500; + # startLimitBurst = 5; + # + # serviceConfig = { + # ExecStart = "${config.security.wrapperDir}/sunshine"; + # Restart = "on-failure"; + # RestartSec = "5s"; + # }; + # }; + + networking.firewall = { + allowedTCPPortRanges = [ + { + from = 47984; + to = 48010; + } + ]; + allowedUDPPortRanges = [ + { + from = 47998; + to = 48010; + } + ]; + }; +} diff --git a/modules/nixos/desktop/remote-desktop/tailscale.nix b/modules/nixos/desktop/remote-desktop/tailscale.nix new file mode 100644 index 00000000..f493c3d2 --- /dev/null +++ b/modules/nixos/desktop/remote-desktop/tailscale.nix @@ -0,0 +1,76 @@ +{ + config, + pkgs, + ... +}: +# ============================================================= +# +# Tailscale - your own private network(VPN) that uses WireGuard +# +# It's open souce and free for personal use, +# and it's really easy to setup and use. +# Tailscale has great client coverage for Linux, windows, Mac, android, and iOS. +# Tailscale is more mature and stable compared to other alternatives such as netbird/netmaker. +# Maybe I'll give netbird/netmaker a try when they are more mature, but for now, I'm sticking with Tailscale. +# +# How to use: +# 1. Create a Tailscale account at https://login.tailscale.com +# 2. Login via `tailscale login` +# 3. join into your Tailscale network via `tailscale up` +# 4. If you prefer automatic connection to Tailscale, then generate a authkey, and uncomment the systemd service below. +# +# Status Data: +# `journalctl -u tailscaled` shows tailscaled's logs +# logs indicate that tailscale store its data in /var/lib/tailscale +# which is already persistent across reboots(via impermanence.nix) +# +# References: +# https://tailscale.com/blog/nixos-minecraft +# +# ============================================================= +{ + # make the tailscale command usable to users + environment.systemPackages = [pkgs.tailscale]; + + # enable the tailscale service + services.tailscale.enable = true; + + # create a oneshot job to authenticate to Tailscale + # systemd.services.tailscale-autoconnect = { + # description = "Automatic connection to Tailscale"; + # + # # make sure tailscale is running before trying to connect to tailscale + # after = ["network-pre.target" "tailscale.service"]; + # wants = ["network-pre.target" "tailscale.service"]; + # wantedBy = ["multi-user.target"]; + # + # # set this service as a oneshot job + # serviceConfig.Type = "oneshot"; + # + # # have the job run this shell script + # script = with pkgs; '' + # # wait for tailscaled to settle + # sleep 2 + # + # # check if we are already authenticated to tailscale + # status="$(${tailscale}/bin/tailscale status -json | ${jq}/bin/jq -r .BackendState)" + # if [ $status = "Running" ]; then # if so, then do nothing + # exit 0 + # fi + # + # # otherwise authenticate with tailscale + # ${tailscale}/bin/tailscale up -authkey file:${config.age.secrets.tailscale-authkey.path} + # ''; + # }; + + networking.firewall = { + # always allow traffic from your Tailscale network + trustedInterfaces = ["tailscale0"]; + + # allow the Tailscale UDP port through the firewall + allowedUDPPorts = [config.services.tailscale.port]; + + # allow you to SSH in over the public internet + allowedTCPPorts = [22]; + }; +}