Remote Desktop: Difference between revisions

Klinger (talk | contribs)
m Self hosting: link to RustDesk and CamelCase for RustDesk
Sandro (talk | contribs)
Fix syntax highlighting
 
(8 intermediate revisions by 4 users not shown)
Line 1: Line 1:
= Software =
== Software ==


Remote desktop software is split into two types: servers and clients.
Remote desktop software is split into two types: servers and clients.
Line 7: Line 7:


* VNC
* VNC
* XRDP
* RDP
 


== Self hosting ==
== Self hosting ==
* [[RustDesk]] (nixpkgs: rustdesk-server)
* [[RustDesk]] available in nixpkgs as rustdesk-server


== Clients ==
== Clients ==
Line 22: Line 21:
* GNOME Connections
* GNOME Connections
* [[RustDesk]]
* [[RustDesk]]
= Configuration =


== VNC ==
== VNC ==
Line 30: Line 27:
Various servers provide configuration options either by CLI or by configuration file.
Various servers provide configuration options either by CLI or by configuration file.


==== Desktop session ====
=== Desktop session ===


To start a desktop session or window manager, one currently has to do this manually because servers still have hard-coded paths to <code>/usr/share/xsessions</code> to look for <code>.desktop</code> files. That means one has to write a script that starts the desktop session, window manager, or any other X application.
To start a desktop session or window manager, one currently has to do this manually because servers still have hard-coded paths to <code>/usr/share/xsessions</code> to look for <code>.desktop</code> files. That means one has to write a script that starts the desktop session, window manager, or any other X application.
Line 67: Line 64:


A basic server setup service entry would look like this:  
A basic server setup service entry would look like this:  
    services.guacamole-server = {
 
        enable = true;
<syntaxhighlight lang="nix">
        host = "127.0.0.1";
services.guacamole-server = {
        port = 4822;
    enable = true;
        userMappingXml = ./user-mapping.xml;
    host = "127.0.0.1";
    };
    port = 4822;
    userMappingXml = ./user-mapping.xml;
};
</syntaxhighlight>
 
This creates the <code>guacamole-server.service</code> systemd unit.
This creates the <code>guacamole-server.service</code> systemd unit.


See the [https://search.nixos.org/options?channel=24.05&from=0&size=50&sort=relevance&type=packages&query=services.guacamole-server search.nixos options] for other configuration options.
See the [https://search.nixos.org/options?type=packages&query=services.guacamole-server search.nixos options] for other configuration options.


The <code>host</code> entry indicates on which IP the server component listens. The <code>port</code> entry here is the default port of <code>4822</code>.
The <code>host</code> entry indicates on which IP the server component listens. The <code>port</code> entry here is the default port of <code>4822</code>.
Line 117: Line 118:
A basic client setup service entry would look like this:
A basic client setup service entry would look like this:


    services.guacamole-client = {
<syntaxhighlight lang="nix">
        enable = true;
services.guacamole-client = {
        enableWebserver = true;
    enable = true;
        settings = {
    enableWebserver = true;
            guacd-port = 4822;
    settings = {
            guacd-hostname = "localhost";
        guacd-port = 4822;
        };
        guacd-hostname = "localhost";
     };
     };
};
</syntaxhighlight>


This creates a <code>tomcat.service</code> systemd unit.
This creates a <code>tomcat.service</code> systemd unit.


See the [https://search.nixos.org/options?channel=24.05&from=0&size=50&sort=relevance&type=packages&query=services.guacamole-client search.nixos options] for other configuration options.
See the [https://search.nixos.org/options?type=packages&query=services.guacamole-client search.nixos options] for other configuration options.


The webportal this provides is served by the tomcat server, and listens on port <code>8080</code> by default. The <code>settings.guacd-port</code> tells the client software how to communicate with the guacamole-server component.  
The webportal this provides is served by the tomcat server, and listens on port <code>8080</code> by default. The <code>settings.guacd-port</code> tells the client software how to communicate with the guacamole-server component.  
Line 140: Line 143:
If you want to use <code>nginx</code> as a reverse proxy in front of the webportal, then the below options can serve as an example setup.
If you want to use <code>nginx</code> as a reverse proxy in front of the webportal, then the below options can serve as an example setup.


This example has a virtual host available as <code>https://remote.mydomain.net</code>. It uses the [https://search.nixos.org/options?channel=24.05&from=0&size=50&sort=relevance&type=packages&query=services.nginx nginx] service, and [https://letsencrypt.org/ LetsEncrypt] for SSL. Configuration of a DNS domain and records is outside the scope of this document.
This example has a virtual host available as <code>https://remote.mydomain.net</code>. It uses the [https://search.nixos.org/options?type=packages&query=services.nginx nginx] service, and [https://letsencrypt.org/ LetsEncrypt] for SSL. Configuration of a DNS domain and records is outside the scope of this document.


    services.nginx = {
<syntaxhighlight lang="nix">
        enable = true;
services.nginx = {
        upstreams."guacamole_server" = {
  enable = true;
            extraConfig = ''
  upstreams."guacamole_server" = {
                keepalive 4;
    extraConfig = ''
            '';
      keepalive 4;
            servers = {
    '';
                "127.0.0.1:8080" = {};
    servers = {
            };
      "127.0.0.1:8080" = { };
        };
    };
        virtualHosts."remote.mydomain.net" = {
};
            forceSSL = true; # redirect http to https
 
            enableACME = true;
virtualHosts."remote.mydomain.net" = {
            locations."/" = {
  forceSSL = true; # redirect http to https
                extraConfig = ''
  enableACME = true;
                    proxy_buffering off;
  locations."/" = {
                    proxy_set_header Upgrade $http_upgrade;
    extraConfig = ''
                    proxy_set_header Connection $http_connection;
      proxy_buffering off;
                    proxy_set_header X-Real-IP $remote_addr;
      proxy_set_header Upgrade $http_upgrade;
                    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
      proxy_set_header Connection $http_connection;
                    proxy_set_header Host $host;
      proxy_set_header X-Real-IP $remote_addr;
                    proxy_set_header X-NginX-Proxy true;
      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
                    proxy_pass http://guacamole_server/guacamole$request_uri;
      proxy_set_header Host $host;
                    proxy_redirect http://guacamole_server/ https://$server_name/;
      proxy_set_header X-NginX-Proxy true;
                '';
      proxy_pass http://guacamole_server/guacamole$request_uri;
            };
      proxy_redirect http://guacamole_server/ https://$server_name/;
        };
    '';
    };       
  };
    # this sets up the letsencrypt service to get ssl certs for the above
     
    security.acme = {
# this sets up the letsencrypt service to get ssl certs for the above
        acceptTerms = true;
security.acme = {
        defaults.email = "your.email@server.name";
  acceptTerms = true;
    };     
  defaults.email = "your.email@server.name";
};     
</syntaxhighlight>


The <code>upstreams."guacamole_server".servers</code> setting points the to IP:port where the <code>guacamole-client</code> webportal is hosted. In this example <code>nginx</code> and <code>guacamole</code> are on the same host.
The <code>upstreams."guacamole_server".servers</code> setting points the to IP:port where the <code>guacamole-client</code> webportal is hosted. In this example <code>nginx</code> and <code>guacamole</code> are on the same host.
Line 190: Line 195:
In the case of the above reverse proxy example, the correct firewall ports will also need to be opened on the server hosting the <code>nginx</code> proxy.
In the case of the above reverse proxy example, the correct firewall ports will also need to be opened on the server hosting the <code>nginx</code> proxy.


    networking.firewall = {
<syntaxhighlight lang="nix">
        enable = true;
networking.firewall = {
        allowedTCPPorts = [
  enable = true;
            80 # http
  allowedTCPPorts = [
            443 # https
    80 # http
            8080 # guacamole
    443 # https
            4822 # guacamole
    8080 # guacamole
        ];
    4822 # guacamole
    };                                         
  ];
 
};                                         
</syntaxhighlight>


For any systems that will be reached from the guacamole service, the corresponding ports will need to be opened. The below example opens ports that match the connection settings in the above <code>user-mapping.xml</code>.
For any systems that will be reached from the guacamole service, the corresponding ports will need to be opened. The below example opens ports that match the connection settings in the above <code>user-mapping.xml</code>.


    networking.firewall = {
<syntaxhighlight lang="nix">
        enable = true;
networking.firewall = {
        allowedTCPPorts = [
  enable = true;
            22 # ssh
  allowedTCPPorts = [
            3389 # rdp
    3389 # rdp
        ];
  ];
    };                                         
};                                         
</syntaxhighlight>


==== References ====
==== References ====
Line 217: Line 224:
== RDP ==
== RDP ==


=== XRDP ===
[[File:Screenshot from 2024-03-02 03-15-05.png|thumb|right|GNOME running in an XRDP shell in Remmina.]]
NixOS has first-class support for XRDP. Client-wise, RDP can be accessed in many ways, but `remmina` and `freerdp` support it natively.
NixOS has first-class support for XRDP. Client-wise, RDP can be accessed in many ways, but `remmina` and `freerdp` support it natively.


All of the options for the <code>xrdp</code> service can be viewed on the [https://search.nixos.org/options?channel=23.11&from=0&size=50&sort=relevance&type=packages&query=xrdp NixOS Options wiki], though an example setup inside of <code>configuration.nix</code> is provided below:
All of the options for the <code>xrdp</code> service can be viewed on the [https://search.nixos.org/options?type=packages&query=xrdp NixOS Options wiki], though an example setup inside of <code>configuration.nix</code> is provided below:


<syntaxhighlight lang="nix">
<syntaxhighlight lang="nix">


services.xserver.enable = true;
services.xserver = {
services.xserver.displayManager.sddm.enable = true;
  enable = true;
services.xserver.desktopManager.plasma5.enable = true;
  displayManager.sddm.enable = true;
  desktopManager.plasma5.enable = true;
};


services.xrdp.enable = true;
services.xrdp = {
services.xrdp.defaultWindowManager = "startplasma-x11";
  enable = true;
services.xrdp.openFirewall = true;
  defaultWindowManager = "startplasma-x11";
  openFirewall = true;
};
</syntaxhighlight>
</syntaxhighlight>


(Source: [https://discourse.nixos.org/t/please-post-working-xrdp-setting-in-configuration-nix/7404/10 Discourse Link], [https://github.com/NixOS/nixpkgs/blob/86a80807d8d7051c63ab2b9d7f630abe066468b1/nixos/modules/services/networking/xrdp.nix nixpkgs code])
(Source: [https://discourse.nixos.org/t/please-post-working-xrdp-setting-in-configuration-nix/7404/10 Discourse Link], [https://github.com/NixOS/nixpkgs/blob/86a80807d8d7051c63ab2b9d7f630abe066468b1/nixos/modules/services/networking/xrdp.nix nixpkgs code])


A different window manager can be used for XRDP than a machine user, provided it has been enabled (through NixOS <code>services</code> or <code>nixpkgs</code>.
A different window manager can be used for XRDP than a machine user, provided it has been enabled (through NixOS <code>services</code> or <code>nixpkgs</code>.  


Make sure you log out the visual user first on the remote machine, otherwise you'll get a black screen. (Source: [https://www.reddit.com/r/Proxmox/comments/hxp28j/black_screen_in_microsoft_remote_desktop_noob/fzm7zbo/ Reddit]). You may be able to work around this by enabling and configuring [[Polkit]], as demonstrated on that page.
Make sure you log out the visual user first on the remote machine, otherwise you'll get a black screen. (Source: [https://www.reddit.com/r/Proxmox/comments/hxp28j/black_screen_in_microsoft_remote_desktop_noob/fzm7zbo/ Reddit]). You may be able to work around this by enabling and configuring [[Polkit]], as demonstrated on that page.


=== GNOME ===
==== XRDP with Gnome 48 and higher ====
[[File:Screenshot from 2024-03-02 03-15-05.png|thumb|right|GNOME running in an XRDP shell in Remmina.]]
<syntaxhighlight lang="nix">
 
services.xrdp.enable = true;
services.xrdp.defaultWindowManager = "${pkgs.gnome-session}/bin/gnome-session"; # gnome wayland session
services.gnome.gnome-remote-desktop.enable = true; # needs gnome-remote-desktop backend to work!!
services.displayManager.autoLogin.enable = false;
services.getty.autologinUser = null;
networking.firewall.allowedTCPPorts = [ 3389 ];
</syntaxhighlight>
 
=== GNOME RDP ===
 
To enable the built in gnome-rdp, setting <code>services.gnome.gnome-remote-desktop.enable = true;</code> is not enough by itself. This installs the systemd unit but the unit does not start automatically at boot. As a consequence the 'Remote Desktop' configuration option is also not available in 'System' tab of the 'Settings' app.
 
To fix this we need to enable and start the systemd unit at boot using <code>wantedBy = [ "graphical.target" ];</code> as shown below:


The XRDP <code>defaultWindowManager</code> setting to access a remote GNOME shell should be set to <code>gnome-remote-desktop</code>. Also ensure you include the package <code>pkgs.gnome.gnome-remote-desktop</code> in your configuration files and that you have a firewall port open for XRDP to communicate on (for the GNOME connections app, this is usually <code>3389</code>).
<syntaxhighlight lang="nix">services.gnome.gnome-remote-desktop.enable = true;
systemd.services.gnome-remote-desktop = {
  wantedBy = [ "graphical.target" ]; # for starting the unit automatically at boot
};
services.displayManager.autoLogin.enable = false;
networking.firewall.allowedTCPPorts = [ 3389 ];</syntaxhighlight>


=== Meshcentral ===
=== Meshcentral ===
Line 249: Line 281:


<code>services.meshcentral.enable = true;</code>
<code>services.meshcentral.enable = true;</code>
However, the agent (client) is not available. ([https://github.com/NixOS/nixpkgs/issues/167527 Request])


[[Category:Applications]]
[[Category:Applications]]
[[Category:Desktop]]
[[Category:Desktop]]
[[Category:Server]]
[[Category:Server]]