Library and examples for creating an RDP server.
Remote Desktop System Settings page (KCM) that lives in the Networking category.
Features:
- User can toggle the server (running the
krdpserverbinary) on and off using a toggle switch. - The server can be set to auto-start at session login.
- The KCM uses SystemD DBus messages to toggle the server on and off and auto-start it.
- User can easily add, modify, and remove usernames and passwords that are allowed to connect to the server.
- User can change the port of the server.
- Do note that the address is currently set to
0.0.0.0, which means any interface that accepts connections forkrdpserverwill work.
- Do note that the address is currently set to
- Certificates can be auto-generated (this is done by default), or the user can supply their own certificates.
- Video quality can be changed between responsiveness and quality.
- Do note that in software encoding mode, the quality slider might not necessarily do anything. This seems to be an encoder issue.
- Display target can be set to stream the full workspace, primary monitor only, or a specific monitor by ID.
- A read-only monitor ID map shows which ID corresponds to which screen.
- VAAPI hardware encoder driver can be configured (automatic, disabled, AMD radeonsi, or Intel iHD).
- The KCM will do some basic sanity-checking and warn the user about the following issues:
- Password manager inaccessible (for KRDP user passwords)
- No supported H264 encoder
- Failures with generating certificates
Not all setting changes require a server restart. Settings that take effect immediately without disconnecting active sessions:
- Video quality
- Display target, monitor ID
- VAAPI driver mode
- Autostart on login
Settings that require a server restart (the KCM will show a warning banner):
- Listening port
- User credentials (add/modify/remove)
- System user authentication toggle
- Certificate configuration (auto-generate toggle, certificate paths)
The example server requires a username and password to be provided on the command line, which will be used when connecting from an RDP client. They can be provided using the -u and -p command line parameters, respectively. For example:
krdpserver -u user -p test
The server will then listen on all interfaces on port 3389, and clients can connect with the username "user" and the password "pass".
To connect to the server, make sure to pass the username and password the server was started with. Note that the username is case-sensitive; this may be especially unexpected for those using Microsoft Windows RDP clients to connect, as system usernames on that platform are generally not case-sensitive.
Currently, the main client that has been used for testing and is confirmed to work is the FreeRDP client. Launch the FreeRDP client with the following command: xfreerdp /u:<username> /p:<password> -clipboard /v:<ip_address>:3389, filling in the username, password and IP address as appropriate. If testing locally, substitute localhost for an IP address.
In addition, a valid TLS certificate and key are required to encrypt the communication between client and server. The server will look for a file called server.crt and server.key in the current working directory, but a different path can be provided using the --certificate and --certificate-key command line parameters. If no valid certificate is found using any of these methods, the server will internally generate a self-signed certificate and use that.
The following command line options are available for the example server:
- -u, --username
- The username to use when a client tries to login. Required.
- -p, --password
- The password to require when a client tries to login. Required.
- --port
- The port to listen on for connections. Defaults to 3389.
- --certificate
- The path to a TLS certificate file to use. If not supplied or it cannot be found a temporary self-signed certificate will be generated.
- --certificate-key
- The path to the TLS certificate key that matches the provided certificate.
- --monitor The index of the monitor to use for streaming video. If not supplied the whole workspace is used.
- --quality
- Set the video quality, from 0 (lowest) to 100 (highest).
When --monitor is not supplied, KRDP uses persisted config keys:
General/MonitorMode=workspace|primary|specificGeneral/MonitorIndex=<id>(used when mode isspecific)
The KDE Remote Desktop settings page exposes this as Display target and
Monitor ID, and shows the current monitor ID map (0: <screen name>, etc.).
The following clients are known to work with the server:
- XFreeRDP and wlFreeRDP from the FreeRDP project.
- Remmina, a remote desktop client for Gnome.
- Thincast Remote Desktop Client
- Windows Remote Desktop client, at least as shipped with a recent Windows 10.
The following clients are known not to work:
- Microsoft's Remote Desktop client for Android. While it should support H.264 it seems to not enable it.
- Only video streaming and remote input is supported.
- Only the NLA security type of RDP is supported.
- Only one username and password combination is supported for login.
- Only the "Graphics Pipeline" extension of the RDP protocol is implemented for video streaming. This extension allows using H.264 for video streaming, but it means only clients supporting that extension are supported.
- H.264 encoding is done using hardware encoding if possible, but currently we only support using VAAPI for this. Most notably this means hardware encoding on NVidia hardware can not be used and software encoding will be used instead. Additionally, on certain hardware there are limits to what size of frame can be encoded by the hardware. In both cases, encoding will fall back to software encoding.
- KDE's implementation of the Remote Desktop portal is rather limited as
shipped with Plasma 5.27. Most notably it does not allow selecting which screen
to stream, nor does it have an option to remember the setup and reuse it when
the same application requests a new connection. As a workaround, the server
will open a remote desktop session on startup and reuse that session for all
RDP connections. Additionally, monitor selection can be done using the
--monitorcommand line option. - Input on a high DPI screen may be offset incorrectly. This is due to a bug in the Remote Desktop Portal that has been fixed in the meantime. The fix will be released with KDE Plasma 5.27.8.
While currently not very well supported it is possible to configure KRdp purely from a CLI. This is particularly useful when you have access over SSH but haven't yet configured KRdp.
# Authorize the krdpserver for remote desktop access
flatpak permission-set kde-authorized remote-desktop org.kde.krdpserver yes
# Generate a server certificate
mkdir --parents "$HOME/.local/share/krdpserver"
certificatePath="$HOME/.local/share/krdpserver/krdp.crt"
certificateKeyPath="$HOME/.local/share/krdpserver/krdp.key"
openssl req -nodes -new -x509 -keyout "$certificateKeyPath" -out "$certificatePath" -days 1 -batch
# Configure the certificate and enable system user authentication
kwriteconfig6 --file krdpserverrc --group General --key Certificate "$certificatePath"
kwriteconfig6 --file krdpserverrc --group General --key CertificateKey "$certificateKeyPath"
kwriteconfig6 --file krdpserverrc --group General --key SystemUserEnabled true
# Optional: display target (workspace|primary|specific) and monitor ID
kwriteconfig6 --file krdpserverrc --group General --key MonitorMode workspace
kwriteconfig6 --file krdpserverrc --group General --key MonitorIndex 0
# Optional: VAAPI driver mode (auto|off|radeonsi|iHD)
kwriteconfig6 --file krdpserverrc --group General --key VaapiDriverMode auto
# Enable/restart the systemd service
systemctl --user enable --now app-org.kde.krdpserver.service
systemctl --user restart app-org.kde.krdpserver.serviceWhen testing changes from your local checkout, use a user service drop-in and a
matching desktop entry override so Wayland privilege checks (fake_input and
zkde_screencast_unstable_v1) apply to your local binary.
# Build
cmake -S . -B build -DCMAKE_BUILD_TYPE=Debug
cmake --build build -j"$(nproc)"
# Desktop entry override (required when ExecStart points to the build tree)
mkdir -p "$HOME/.local/share/applications"
cp /usr/share/applications/org.kde.krdpserver.desktop "$HOME/.local/share/applications/org.kde.krdpserver.desktop"
sed -i "s#^Exec=.*#Exec=$PWD/build/bin/krdpserver#" "$HOME/.local/share/applications/org.kde.krdpserver.desktop"
kbuildsycoca6 --noincremental
# systemd user drop-in
mkdir -p "$HOME/.config/systemd/user/app-org.kde.krdpserver.service.d"
cat > "$HOME/.config/systemd/user/app-org.kde.krdpserver.service.d/zz-krdp-plasma.conf" <<EOF
[Service]
UnsetEnvironment=LIBVA_DRIVER_NAME
Environment=XDG_DATA_DIRS=%h/.local/share:/usr/local/share:/usr/share
ExecStart=
ExecStart=$PWD/build/bin/krdpserver --plasma --monitor 0
EOF
# Reload and restart
systemctl --user daemon-reload
systemctl --user restart plasma-xdg-desktop-portal-kde app-org.kde.krdpserver
# Verify active command
systemctl --user show app-org.kde.krdpserver.service -p ExecStartTo switch back to the packaged binary:
cat > "$HOME/.config/systemd/user/app-org.kde.krdpserver.service.d/zz-krdp-plasma.conf" <<EOF
[Service]
UnsetEnvironment=LIBVA_DRIVER_NAME
ExecStart=
ExecStart=/usr/bin/krdpserver --plasma --monitor 0
EOF
systemctl --user daemon-reload
systemctl --user restart plasma-xdg-desktop-portal-kde app-org.kde.krdpserverUseful runtime log command:
journalctl --user -f -o cat -u app-org.kde.krdpserver -u plasma-xdg-desktop-portal-kdeKRDP_EXPERIMENTAL_AVC444=1 and KRDP_EXPERIMENTAL_AVC444V2=1 enable
AVC444 capability negotiation experiments.
KRDP_EXPERIMENTAL_TRUE_AVC444=1 enables experimental AVC444 wire transport
(RDPGFX_AVC444_BITMAP_STREAM, single-stream mode) when AVC444/AVC444v2 is
negotiated.
Without KRDP_EXPERIMENTAL_TRUE_AVC444=1, KRDP automatically falls back to
AVC420 transport while preserving AVC444 intent for quality tuning.
On mixed-GPU systems, KRDP now attempts to avoid decode-only VAAPI backends by
auto-selecting a non-NVIDIA LIBVA_DRIVER_NAME when possible.
The persisted KCM/config key is General/VaapiDriverMode with these values:
auto(default): automatic mixed-GPU selection.off: disable KRDP VAAPI driver auto-selection.radeonsi: force AMD VAAPI driver.iHD: force Intel VAAPI driver (runtime fallback toi965remains available).
Note for NVIDIA-only systems: current KRDP hardware encode integration is
VAAPI-based. NVIDIA acceleration typically uses NVENC instead, so KRDP falls
back to software (libx264) unless a non-NVIDIA VAAPI encode path is present.
This is an API-path limitation, not raw GPU compute performance.
KRDP can optionally retry once with forced libx264 if the PipeWire stream
becomes active but does not deliver encoded packets within the timeout window.
This stall watchdog is disabled by default and must be opted into:
systemctl --user set-environment KRDP_ENABLE_STALL_WATCHDOG=1When enabled, the override is temporary for that retry path and then restored, so panel-selected VAAPI mode continues to apply for subsequent sessions.
Manual environment override examples:
systemctl --user set-environment KRDP_AUTO_VAAPI_DRIVER=0
systemctl --user set-environment KRDP_FORCE_VAAPI_DRIVER=radeonsiThe local KRDP improvements can use extra encoded-frame metadata from a patched KPipeWire build. The patch is tracked in this repository:
patches/kpipewire/0001-damage-metadata-encoded-stream.patch
Apply it in a KPipeWire checkout with:
cd /path/to/kpipewire
git apply /path/to/krdp/patches/kpipewire/0001-damage-metadata-encoded-stream.patchRecent KRDP builds include several latency and artifact-reduction behaviors:
- Damage-aware region updates with rectangle coalescing.
- Freshest-frame delivery under load (stale queued frames are dropped).
- Packet/damage metadata pairing with a short wait budget before full-frame fallback.
- Tile activity classification (static regions biased for crisp quality, transient regions biased for compression).
- Progressive refinement: after motion settles, one high-quality full-frame refresh is sent.
- AVC444-intent fallback bias: if a client asks for AVC444 but local transport is AVC420-only, KRDP slightly raises quality for text/static UI regions.
Useful debug markers:
journalctl --user -f -o cat -u app-org.kde.krdpserver | \
rg -i 'Dropped stale queued frames|No matching damage metadata|Sent progressive refinement frame|Using AVC444 wire transport mode'Since SDDM currently has no RDP support, you either need to already be logged in, or let SDDM auto log in to the user.
Mind that your session starts physically unlocked on your PC. Also when you are remote logging into your session it will be physically unlocked.
# Configure autologin for your current user
user=$(whoami)
sudo kwriteconfig6 --file /etc/sddm.conf.d/kde_settings.conf --group Autologin --key User $user
# Enable automatic relogin on logout to avoid scenarios where the system is stuck on sddm
sudo kwriteconfig6 --file /etc/sddm.conf.d/kde_settings.conf --group Autologin --key Relogin true
# Restart sddm to force an autologin (don't run this if you are already logged in :D)
## systemctl restart sddm.serviceUse the bundled smoke test helper to rebuild KRDP, restart services, and watch the key log markers used during tuning:
./smoke-test.shUseful flags:
./smoke-test.sh --no-build --watch-seconds 180
./smoke-test.sh --no-watch
./smoke-test.sh --no-build --assert-encoder vaapi
./smoke-test.sh --no-build --assert-encoder software