Remote Desktop: Difference between revisions
Remove default setting for gnome |
Add fuse information for Hyper-V drive redirection to work correctly. |
||
| (9 intermediate revisions by 5 users not shown) | |||
| Line 6: | Line 6: | ||
== Server Protocols == | == Server Protocols == | ||
* VNC | * [[Wikipedia:VNC|VNC]] | ||
* RDP | * [[Wikipedia:Remote Desktop Protocol|RDP]] | ||
== Self hosting == | == Self hosting == | ||
* [[RustDesk]] | * [[RustDesk]] available in nixpkgs as [https://search.nixos.org/packages?query=rustdesk-server rustdesk-server] | ||
== Clients == | == Clients == | ||
* Apache Guacamole | * Apache Guacamole | ||
* | * FreeRDP | ||
* KRDC (KDE) | * KRDC (KDE) | ||
* | * Remmina | ||
* | * TightVNC and its forks [[TigerVNC]] and TurboVNC | ||
* x2goclient | * x2goclient | ||
* GNOME Connections | * GNOME Connections | ||
| Line 31: | Line 31: | ||
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. | ||
Some servers will automatically run <code>$HOME/.vnc/xstartup</code> but the more secure option is to write an executable script and run <code>vncserver -xstartup $pathToScript</code> | Some servers will automatically run <code>$HOME/.vnc/xstartup</code> but the more secure option is to write an executable script and run <code>vncserver -xstartup $pathToScript</code>. | ||
An example script: | An example script: | ||
| Line 42: | Line 42: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
<code>pathToScript</code> can also be a path to an executable like <code>${pkgs.icewm}/bin/icewm</code> | <code>pathToScript</code> can also be a path to an executable like <code>${pkgs.icewm}/bin/icewm</code>. | ||
=== | === TigerVNC === | ||
Nixpkgs has a package but no service. | Nixpkgs has a package but no service. | ||
The server component can be started using the <code>vncserver</code> command. | The server component can be started using the <code>vncserver</code> command. | ||
To connect, use the <code>vncviewer</code> command. | To connect, use the <code>vncviewer</code> command. | ||
For an automated nixos config see [[TigerVNC]]. | |||
However, you'll more likely have success running [https://search.nixos.org/packages?channel=unstable&query=x11vnc&show=x11vnc x11vnc] on the remote/far-away server, while only using <code>vncviewer</code> from the TigerVNC package from where you're sitting. Quality documentation for x11vnc usage is at its [https://github.com/LibVNC/x11vnc/?tab=readme-ov-file#readme official repository]. | |||
=== x2go === | === x2go === | ||
| Line 56: | Line 60: | ||
The server is installed by adding the following line:<br/> | The server is installed by adding the following line:<br/> | ||
<code>services.x2goserver.enable = true;</code><br/> | <code>services.x2goserver.enable = true;</code><br/> | ||
to /etc/nixos/configuration.nix. | to <code>/etc/nixos/configuration.nix</code>. | ||
=== Guacamole === | === Guacamole === | ||
==== Guacamole Server ==== | ==== Guacamole Server ==== | ||
In nixos the guacamole server component is provided by [https://github.com/NixOS/nixpkgs/blob/nixos-24.05/nixos/modules/services/web-apps/guacamole-server.nix guacamole-server] | In nixos the guacamole server component is provided by [https://github.com/NixOS/nixpkgs/blob/nixos-24.05/nixos/modules/services/web-apps/guacamole-server.nix guacamole-server]. | ||
A basic server setup service entry would look like this: | A basic server setup service entry would look like this: | ||
<syntaxhighlight lang="nix"> | |||
services.guacamole-server = { | |||
enable = true; | |||
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?type=packages&query=services.guacamole-server search | See the [https://search.nixos.org/options?type=packages&query=services.guacamole-server NixOS Options search] 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 82: | Line 90: | ||
The file content should look something like this: | The file content should look something like this: | ||
{{file|user-mapping.xml|xml|3= | |||
<user-mapping> | |||
<authorize username="USERNAME_HERE" password="ENCRYPTED_PASSWORD_HERE" encoding="sha256"> | |||
<connection name="NAME_OF_THE_CONNECTION"> | |||
<protocol>rdp</protocol> | |||
<param name="hostname">XXX.XXX.XXX.XXX</param> | |||
<param name="port">3389</param> | |||
<param name="ignore-cert">true</param> | |||
</connection> | |||
<connection name="NAME_OF_THE_CONNECTION"> | |||
<protocol>ssh</protocol> | |||
<param name="hostname">XXX.XXX.XXX.XXX</param> | |||
<param name="port">22</param> | |||
</connection> | |||
</authorize> | |||
</user-mapping> | |||
}} | |||
The <code>password=""</code> can be a plain text password, but it is not recommended. An easy way to encrypt a password would be something like: | The <code>password=""</code> can be a plain text password, but it is not recommended. An easy way to encrypt a password would be something like: | ||
<syntaxhighlight lang="console"> | |||
$ echo -n 'SUPERsecretPASSWORD' | openssl dgst -sha256 | |||
SHA2-256(stdin)= 491cf91d586fb9442db7efe92b7839190206a653971573c23fed0435ceb596e8 | |||
</syntaxhighlight> | |||
The [https://guacamole.apache.org/doc/gug/configuring-guacamole.html#configuring-connections upstream documentation] has complete configuration options avaiable. | The [https://guacamole.apache.org/doc/gug/configuring-guacamole.html#configuring-connections upstream documentation] has complete configuration options avaiable. | ||
| Line 110: | Line 121: | ||
In nixos the guacamole client component is provided by the [https://github.com/NixOS/nixpkgs/blob/nixos-24.05/nixos/modules/services/web-apps/guacamole-client.nix guacamole-client] component. | In nixos the guacamole client component is provided by the [https://github.com/NixOS/nixpkgs/blob/nixos-24.05/nixos/modules/services/web-apps/guacamole-client.nix guacamole-client] component. | ||
This is the part of the service that provides the webportal for end users. | This is the part of the service that provides the webportal for end users. | ||
A basic client setup service entry would look like this: | A basic client setup service entry would look like this: | ||
<syntaxhighlight lang="nix"> | |||
services.guacamole-client = { | |||
enable = true; | |||
enableWebserver = true; | |||
settings = { | |||
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. | ||
| Line 127: | Line 140: | ||
See the [https://search.nixos.org/options?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. | ||
The [https://guacamole.apache.org/doc/gug/configuring-guacamole.html#guacamole-properties upstream documentation] has the list of <code>guacamole.properties</code> options that can be provided for this setting. | The [https://guacamole.apache.org/doc/gug/configuring-guacamole.html#guacamole-properties upstream documentation] has the list of <code>guacamole.properties</code> options that can be provided for this setting. | ||
At this point if you are intending to serve the webportal directly, then the service can be reached at the url <code>http://<your-computer-ip:8080/guacamole</code>. | At this point if you are intending to serve the webportal directly, then the service can be reached at the url <code>http://<your-computer-ip:8080/guacamole</code>. | ||
==== Reverse Proxy ==== | ==== Reverse Proxy ==== | ||
| Line 139: | Line 152: | ||
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. | 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. | ||
<syntaxhighlight lang="nix"> | |||
services.nginx = { | |||
enable = true; | |||
upstreams."guacamole_server" = { | |||
extraConfig = '' | |||
keepalive 4; | |||
''; | |||
servers = { | |||
"127.0.0.1:8080" = { }; | |||
}; | |||
}; | |||
virtualHosts."remote.mydomain.net" = { | |||
forceSSL = true; # redirect http to https | |||
enableACME = true; | |||
locations."/" = { | |||
extraConfig = '' | |||
proxy_buffering off; | |||
proxy_set_header Upgrade $http_upgrade; | |||
proxy_set_header Connection $http_connection; | |||
proxy_set_header X-Real-IP $remote_addr; | |||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; | |||
proxy_set_header Host $host; | |||
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 = { | |||
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 187: | Line 202: | ||
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. | ||
<syntaxhighlight lang="nix"> | |||
networking.firewall = { | |||
enable = true; | |||
allowedTCPPorts = [ | |||
80 # http | |||
443 # https | |||
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>. | ||
<syntaxhighlight lang="nix"> | |||
networking.firewall = { | |||
enable = true; | |||
allowedTCPPorts = [ | |||
3389 # rdp | |||
]; | |||
}; | |||
</syntaxhighlight> | |||
==== References ==== | ==== References ==== | ||
| Line 216: | Line 233: | ||
=== XRDP === | === XRDP === | ||
[[File:Screenshot from 2024-03-02 03-15-05.png|thumb|right|GNOME running in an XRDP shell in Remmina.]] | [[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 | NixOS has first-class support for XRDP. Client-wise, RDP can be accessed in many ways, but <code>remmina</code> and <code>freerdp</code> support it natively. | ||
All of the options for the <code>xrdp</code> service can be viewed | All of the options for the <code>xrdp</code> service can be viewed through the [https://search.nixos.org/options?query=xrdp NixOS Options search], though an example setup inside of <code>configuration.nix</code> is provided below: | ||
<syntaxhighlight lang="nix"> | <syntaxhighlight lang="nix"> | ||
services.xserver = { | |||
enable = true; | |||
displayManager.sddm.enable = true; | |||
desktopManager.plasma5.enable = true; | |||
}; | |||
services. | services.xrdp = { | ||
enable = true; | |||
defaultWindowManager = "startplasma-x11"; | |||
openFirewall = true; | |||
}; | |||
</syntaxhighlight> | </syntaxhighlight> | ||
| Line 247: | Line 267: | ||
networking.firewall.allowedTCPPorts = [ 3389 ]; | networking.firewall.allowedTCPPorts = [ 3389 ]; | ||
</syntaxhighlight> | </syntaxhighlight> | ||
==== XRDP under Hyper-V with enhanced session mode ==== | |||
If you want to use enhanced session mode in VMConnect while using Hyper-V for a NixOS VM, you need to specify some additional options: | |||
<syntaxhighlight lang="nix"> | |||
programs.fuse.enable = true; | |||
services = { | |||
xrdp = { | |||
defaultWindowManager = "${pkgs.i3}/bin/i3"; | |||
enable = true; | |||
extraConfDirCommands = '' | |||
substituteInPlace $out/xrdp.ini \ | |||
--replace-fail 'port=3389' 'port=vsock://-1:3389' \ | |||
--replace-fail '#vmconnect=true' 'vmconnect=true' \ | |||
--replace-fail 'security_layer=negotiate' 'security_layer=rdp' \ | |||
--replace-fail 'crypt_level=high' 'crypt_level=none' \ | |||
--replace-fail 'bitmap_compression=true' 'bitmap_compression=false' | |||
''; | |||
}; | |||
}; | |||
systemd.services.xrdp.serviceConfig.ExecStart = lib.mkForce "${pkgs.xrdp}/bin/xrdp --nodaemon --config /etc/xrdp/xrdp.ini"; | |||
virtualisation.hypervGuest.enable = true; | |||
</syntaxhighlight> | |||
As documented in [https://github.com/nixos/nixpkgs/issues/304855 this issue], the current behavior of the XRDP module in NixOS is to provide the <code>--port</code> parameter on the CLI in the systemD unit file. It does print a message indicating it's ignoring anything provided in the configuration saying <code>--port parameter found, ini override</code> in journalctl. | |||
If in doubt, you can always run <code>ss --vsock -l</code>. If nothing shows up, then XRDP isn't listening where it should be and something about the above has changed. | |||
Enabling fuse allows you to configure drive redirection in VMConnect and any drives selected will appear under <code>~/thinclient_drives</code> by default. Without enabling this programs option, you will receive a command not found error in <code>~/.local/share/xrdp/xrdp-chansrv.*.log</code> related to fusermount3. | |||
=== GNOME RDP === | === GNOME RDP === | ||
| Line 267: | Line 319: | ||
<code>services.meshcentral.enable = true;</code> | <code>services.meshcentral.enable = true;</code> | ||
[[Category:Applications]] | [[Category:Applications]] | ||
[[Category:Desktop]] | [[Category:Desktop]] | ||
[[Category:Server]] | [[Category:Server]] | ||