{ config, pkgs, lib, ...}: let xpra-html5 = pkgs.fetchFromGitHub { owner = "Xpra-org"; repo = "xpra-html5"; rev = "e5fb000a9d4042c54e55c5e30c0936125ec3a045"; hash = "sha256-nfPePTvOVBgx/aMx380vu4Kn9sxmo1QNb050N95ENPk="; }; xpra-web = pkgs.writeScript "xpra-web" '' #!${pkgs.bash}/bin/bash ${pkgs.xpra}/bin/xpra $@ --html=${xpra-html5}/html5 ''; in { nixpkgs.overlays = [ (final: prev: { xpra = prev.xpra.overrideAttrs (old: { postPatch = old.postPatch or "" + '' sed -e 's#"%s/share/xsessions" % sys.prefix#"${config.services.xserver.displayManager.sessionData.desktops}/share/xsessions"#g' -i xpra/platform/xposix/menu_helper.py ''; }); }) ]; # To use instead of Plasma services.xserver.windowManager.fluxbox.enable = true; environment.systemPackages = [ pkgs.xpra ]; security.pam.services = { xpra = { text = '' # Account management. account required pam_unix.so # Authentication management. auth sufficient pam_unix.so likeauth try_first_pass auth required pam_deny.so # Password management. password sufficient pam_unix.so nullok yescrypt session required pam_unix.so #account required pam_nologin.so # account include system-auth # password include system-auth # pam_selinux.so close should be the first session rule #session required pam_selinux.so close session required pam_loginuid.so #to require a local user account, uncomment this line: #session required pam_localuser.so # session sufficient pam_systemd.so class=background type=x11 # pam_selinux.so open should only be followed by sessions to be executed in the user context # session required pam_selinux.so open # session required pam_namespace.so # session optional pam_keyinit.so force revoke # session include system-auth # session include postlogin -session optional pam_ck_connector.so ''; }; }; systemd.sockets.xpra-web = { description = "Xpra Web Socket"; partOf = [ "xpra-web.service" ]; wantedBy = [ "sockets.target" ]; socketConfig = { # ListenStream = 14500; ListenStream = "/run/xpra/system"; SocketUser = "root"; SocketGroup = "users"; PassCredentials = "true"; }; }; systemd.services.xpra-web = { description = "xpra-web"; after = [ "network.target" "xpra-web.socket" ]; requires = [ "xpra-web.socket" ]; wantedBy = [ "multi-user.target" ]; serviceConfig = { Type = "simple"; ExecStart = ''${xpra-web} proxy :14500 --daemon=no \ --tcp-auth=pam --auth=pam --bind=none \ --log-dir=/var/log --pidfile=/run/xpra/proxy.pid --bind-tcp=:10000''; Restart = "always"; # Security NoNewPrivileges = true; ReadWritePaths = [ "/run/xpra" "/tmp" ]; # Sandboxing ProtectSystem = "strict"; ProtectKernelTunables = true; ProtectControlGroups = true; }; }; services.caddy.virtualHosts = { "remote.ws.kcnhub.com" = { extraConfig = '' reverse_proxy 127.0.0.1:${toString 10000} ''; }; }; }