GNOME (Wayland) RDP

GNOME's own remote-desktop stack (GNOME Remote Desktop) is GNOME-only. lamco-rdp-server speaks standard RDP on GNOME/Mutter through the freedesktop RemoteDesktop portal and Mutter's Direct API, and the same server also runs on KDE, sway, Hyprland, and COSMIC. This guide is the concrete GNOME setup: install, grant permission once, connect, and fix the GNOME-specific things that trip people up.

Install

Community Edition (any distro): Lamco's own self-hosted Flatpak repository (recommended, auto-updates), the Flatpak bundle attached to the GitHub release, or the Snap Store.

# recommended: one-click install, updates automatically
flatpak install --from https://flatpak.lamco.ai/io.lamco.rdp-server.flatpakref

# equivalent, in two steps
flatpak remote-add --user --if-not-exists lamco https://flatpak.lamco.ai/lamco.flatpakrepo
flatpak install --user lamco io.lamco.rdp-server

# or: install the downloaded bundle once, no auto-updates
flatpak install <downloaded>.flatpak
flatpak run io.lamco.rdp-server   # launches the GUI

# or: snap install lamco-rdp-server

Native (Ubuntu 24.04 / Fedora / Arch): use the distribution package (see the Installation page). GNOME/Mutter needs PipeWire and xdg-desktop-portal-gnome, which ship by default on a GNOME desktop.

Verify the environment before connecting:

lamco-rdp-server --show-capabilities

Look for Portal (RemoteDesktop + ScreenCast) available and an Encoding backend.

Grant permission once (unattended access)

GNOME shows a portal permission dialog the first time a remote session starts. For unattended or headless use, grant it once and store a restore token:

lamco-rdp-server --grant-permission

This triggers the portal dialog, obtains a restore token, and stores it so future connections start without a prompt. Re-run it if you revoke access or change users.

Minimal config

~/.config/lamco-rdp-server/config.toml:

[server]
# Dual-stack by default: "[::]:3389" listens on IPv6 and, on a standard Linux
# host, also accepts IPv4 clients. Use "0.0.0.0:3389" only to force IPv4-only.
listen_addr = "[::]:3389"

[security]
tls = true          # self-signed by default; see Security for your own cert

[video]
codec = "auto"      # AVC444/AVC420 via EGFX where the client supports it

Start it:

lamco-rdp-server                     # native; binds dual-stack by default
# or: flatpak run io.lamco.rdp-server

Connect

The server listens dual-stack by default, so IPv4 and IPv6 clients both work. Use the host's name (it resolves to whichever family the client prefers) or an explicit address; IPv6 literals go in brackets.

  • Windows: built-in Remote Desktop Connection (mstsc.exe) → host:3389, or an IPv6 literal in brackets: [2001:db8::10]:3389.
  • Linux: Remmina, or FreeRDP: xfreerdp /v:host:3389 /u:USER (IPv6 literal: xfreerdp /v:[2001:db8::10]:3389 /u:USER).
  • macOS: Microsoft Remote Desktop.

Input uses libei by default on GNOME, which is the supported modern path.

GNOME-specific behavior (current in 1.4.5)

  • Area capture, so a fullscreen video no longer freezes the session. Mutter stops recording a monitor stream while a surface is handed to direct scanout (mutter#3903), which froze the remote picture for the length of any video. The server now resolves the monitor's rectangle through org.gnome.Mutter.DisplayConfig and records that area instead. Selected by capture.gnome_record_mode: auto (the default, area on a single monitor), area, or monitor. An area stands in for exactly one monitor, so multi-monitor layouts fall back to the monitor stream. The cost is that an area stream always re-composites where a monitor stream blits, and Mutter's area source runs at a fixed 60 fps.
  • DMA-BUF capture is attempted, with shared memory as fallback. The GNOME profile no longer forces shared memory. Virtual GPUs are checked for the Venus capset rather than refused by driver name, so a Venus-capable virtio-gpu can take the DMA-BUF path.
  • Headless servers can present the virtual monitor as a real display with capture.gnome_virtual_is_platform = true (GNOME 46 or newer, off by default). The compositor's logical scale is now read from the stream as org.gnome.scale on virtual-monitor sessions.
  • Multitouch over MS-RDPEI, enabled with input.enable_touch.
  • Many sequential sessions, no restart. On GNOME/Mutter the server now uses a per-connection session: it creates a fresh RemoteDesktop/ScreenCast session on each connect and releases it on disconnect. You can connect, disconnect, and reconnect all day. (Earlier versions kept one long-lived session that Mutter's idle timeout reaped a few seconds after a client left, which looked like "it only works once.")
  • GNOME 49 input works via a lazy Mutter EIS lifecycle with a kept-alive connection.
  • PAM authentication works under the hardened system service (the unit joins the shadow group and keeps full seccomp hardening).

Verified in the 1.4.5 campaign on GNOME 48 (Debian 13), GNOME 49 and 50 (Fedora, Arch), and Ubuntu 26.04.

Troubleshooting

SymptomCauseFix
Connects, then black screen (mouse/audio work)No working H.264 encoder, or portal capture not startedRun --show-capabilities; ensure an Encoding backend is present. On CPU-only systems install Cisco's OpenH264 (see Video Encoding); prefer a GPU for hardware VA-API
Works once, then every reconnect fails until restartOld persistent-session model reaped by Mutter idle timeoutUpdate to 1.4.4 (per-connection lifecycle)
Input does nothing on GNOME 49EIS lifecycle regressionFixed in 1.4.4
Screen freezes during fullscreen videoMutter stops recording a monitor stream during direct scanout (mutter#3903)Fixed in 1.4.5 by area capture; keep capture.gnome_record_mode = "auto"
Video is blurry or laggyMutter over-reports damageFixed in 1.4.5; the server distrusts the hints and uses its own pixel diff for the connection
Portal dialog on every connectNo stored restore tokenRun lamco-rdp-server --grant-permission once
PAM login always fails on the packaged system serviceHardened unit blocked the PAM helperFixed in 1.4.4 (unit joins shadow); or use the recommended auth method the server reports at startup

See also: Installation, Configuration, Security, Video Encoding, the Platform Compatibility matrix, and the sibling guides for KDE/KWin, sway/wlroots, Hyprland, and COSMIC.