Building hypr-rdp, an RDP Server Dedicated to Hyprland

16 min read

Introduction

Previously, I wrote about how to connect to Hyprland via Windows’ built-in RDP client.

https://www.munenick.me/blog/hyprland-rdp

In that article, I introduced how to connect to Hyprland from the standard Windows RDP client by combining xrdp and WayVNC.

However, Hyprland does not have a mechanism to operate as an RDP server by itself. As a result, the configuration was complicated: xrdp acted as the RDP entry point and internally bridged to WayVNC.

Even though I only wanted to connect via RDP, I had to think about RDP, VNC, Wayland, and Hyprland headless outputs. There were also compatibility issues between xrdp and WayVNC, along with dynamic resolution changes.

In that case, I thought it would be a good idea to create an RDP server exclusively for Hyprland.

So I created hypr-rdp.

https://github.com/MuNeNiCK/hypr-rdp

What is hypr-rdp?

hypr-rdp is a native RDP server for Hyprland.

It is built to connect to Hyprland from a normal RDP client, such as the standard Windows Remote Desktop client.

hypr-rdp itself acts as an RDP server, handling Hyprland’s screen capture, input, audio, clipboard, etc.

The main features are as follows.

Feature Details
Screen streaming H.264 / EGFX
Codec AVC420, experimental AVC444
Encoding Fallback to software encoding when VA-API is unavailable
Screen capture wlr-screencopy-v1, ext-image-copy-capture-v1
Audio Transfer to the RDP client via PipeWire
Clipboard Two-way synchronization of text and images
Input Keyboard/mouse input
TLS Automatic generation of self-signed certificate, optional certificate specification
Configuration file ~/.config/hypr-rdp/config.toml

How to use

Requirements

hypr-rdp requires Hyprland 0.54 or later.

The main runtime dependencies are listed below. The package manager will resolve them during installation.

- ffmpeg / libavcodec
- libva
- PipeWire
- libxkbcommon

If you use hardware encoding with VA-API, you will also need a VA-API driver that is compatible with your GPU.

Install intel-media-driver for Intel GPUs, libva-mesa-driver for AMD GPUs, and so on.

Install

On Arch Linux, it can be installed from AUR.

yay -S hypr-rdp

If you use Nix, you can install it with the following.

nix run github:MuNeNICK/hypr-rdp#hypr-rdp -- --help

You can also use prebuilt binaries obtained from GitHub Releases.

tar xzf hypr-rdp-v*.tar.gz
sudo install -Dm755 hypr-rdp /usr/local/bin/hypr-rdp

Start

If you want to connect from another machine, specify the bind address and start it.

hypr-rdp -u user -p pass --bind 0.0.0.0:3389

Specify resolution and frame rate

To specify resolution and frame rate, use --resolution and --fps.

hypr-rdp -u user -p pass --resolution 2560x1440 --fps 60

Use this if you want a fixed-size output for RDP.

Use a specific output

If you want to capture a specific output, specify --output.

hypr-rdp -u user -p pass --output DP-1

Use this when you want to use an existing physical output or a specific Hyprland output instead of the headless output for RDP.

Specify capture method

The screen capture method can be specified with --capture-mode.

When using wlr-screencopy-v1, do the following:

hypr-rdp -u user -p pass --capture-mode wlr

When using ext-image-copy-capture-v1, do the following:

hypr-rdp -u user -p pass --capture-mode ext

Encoding settings

hypr-rdp uses RDP EGFX for screen streaming.

By default, AVC420 is used.

hypr-rdp -u user -p pass --egfx-codec avc420

AVC444 can also be specified experimentally.

hypr-rdp -u user -p pass --egfx-codec avc444

Use --bitrate to specify the H.264 bit rate.

hypr-rdp -u user -p pass --bitrate 20000000

Use --quality to specify the quality.

hypr-rdp -u user -p pass --quality 23

In environments where VA-API is available, hardware encoding is used. If it is unavailable, hypr-rdp falls back to software encoding.

Configuration file

If you don’t want to specify CLI arguments every time, you can use a configuration file.

The configuration file is below.

~/.config/hypr-rdp/config.toml

This is an example.

bind = "0.0.0.0:3389"
username = "user"
password = "pass"

# resolution = "1920x1080"
capture_mode = "wlr"
bitrate = 10000000
quality = 23
fps = 30
egfx_codec = "avc420"

# output = "DP-1"

Values specified in CLI arguments take precedence over configuration files.

You can write the settings you usually use in config.toml and override them with CLI arguments only when necessary.

TLS and authentication

RDP uses TLS.

hypr-rdp automatically generates a self-signed certificate if you do not specify one.

If you want to specify your own certificates, use --cert and --key.

hypr-rdp \
  -u user \
  -p pass \
  --cert /path/to/cert.pem \
  --key /path/to/key.pem

Username and password can be specified in -u / -p.

hypr-rdp -u user -p pass

It can also be written in the configuration file.

username = "user"
password = "pass"

When listening at 0.0.0.0:3389, be sure to set authentication information.

Inner workings

Overall configuration

hypr-rdp uses IronRDP for the RDP server layer.

It combines IronRDP with Hyprland-specific processing.

The rough structure is as follows.

RDP Client

IronRDP

hypr-rdp
  ├─ Hyprland IPC
  ├─ Wayland capture
  ├─ H.264 / EGFX
  ├─ PipeWire audio
  ├─ Clipboard
  └─ Input

It accepts RDP connections, captures the Hyprland screen, encodes it in H.264, and sends it to the RDP client.

At the same time, keyboard and mouse input from the RDP client is passed to Hyprland, while audio and clipboard data are handled as RDP channels.

Prepare output for the session

To connect with RDP, you need a screen to send to the client.

If you want to use an existing output, you can specify it with --output. If it is not specified, hypr-rdp prepares a headless output for RDP sessions.

Internally, it connects directly to the Hyprland IPC.

Hyprland’s IPC socket constructs a path from HYPRLAND_INSTANCE_SIGNATURE and XDG_RUNTIME_DIR.

$XDG_RUNTIME_DIR/hypr/$HYPRLAND_INSTANCE_SIGNATURE/.socket.sock

Use socket2 for events.

$XDG_RUNTIME_DIR/hypr/$HYPRLAND_INSTANCE_SIGNATURE/.socket2.sock

When creating output, send Hyprland IPC commands like the following:

output create headless hypr-rdp

When an output is added on the Hyprland side, a monitoradded event is emitted on socket2.

hypr-rdp waits for this event and gets the output name of the created hypr-rdp-* output.

Once you have obtained the output name, set the resolution and placement using keyword monitor.

hypr-rdp-1,1920x1080@60,-9999x0,1

The headless output is resized if the RDP client requests an initial size or if DisplayControl requests a resize.

The created headless output is deleted when the session ends.

output remove hypr-rdp-1

Additionally, if a hypr-rdp-* headless output remains from a previous session, it can be reused.

Capture screen and send to RDP

Once the output is ready, capture it with Wayland’s protocol.

The supported capture methods are as follows.

- wlr-screencopy-v1
- ext-image-copy-capture-v1

The captured frames are encoded in H.264 and sent to the client as RDP EGFX.

If VA-API is available, use hardware encoding. If it cannot be used, hypr-rdp falls back to software encoding.

When encoding with software, the maximum length is 3840 on the long side and 2160 on the short side, considering the ease of handling H.264. If a larger size is requested, it will be reduced to fit within the upper limit while rounding to an even size.

Send audio

PipeWire is used for audio transfer.

hypr-rdp captures audio from PipeWire and sends it to the client through RDP’s RDPSND channel.

This allows the RDP client to listen to the sounds played in the Hyprland environment.

Sync the clipboard

Clipboard supports two-way synchronization.

It can handle not only text but also image clipboards.

By connecting the clipboard on the Wayland side with the CLIPRDR channel on the RDP side, the clipboard is synchronized between the client and Hyprland.

Clipboard synchronization is very important when using it as a remote desktop.

It affects not only how you can see the screen, but also whether you can use it in your daily work.

Pass input

For input, the keyboard and mouse events received from the RDP client are passed to Hyprland.

On the Wayland side, we use a virtual keyboard or virtual pointer system.

Screen streaming alone is relatively simple, but input processing is required to use it as a remote desktop.

hypr-rdp receives keyboard, pointer, click, scroll, and other input events from the RDP side and passes them to Hyprland.

Why use Hyprland IPC instead of xdg-desktop-portal?

When handling screen sharing and remote desktop in a Wayland environment, it is natural to handle it via xdg-desktop-portal.

xdg-desktop-portal is the standard entry point for handling sessions such as screen sharing and remote desktop between applications and compositors.

In Wayland, the idea is that an application should not automatically capture the screen or inject input. Instead, user permission and compositor control should pass through the portal.

Therefore, the ideal mechanism for remote desktop and screen sharing would be to complete everything through xdg-desktop-portal.

However, at present, Hyprland does not yet have the necessary APIs for RDP server use.

There are also related issues and PRs.

Type Number Content Status
Issue #252 org.freedesktop.portal.RemoteDesktop support request Open
PR #308 RemoteDesktop portal implementation Draft
PR #402 RemoteDesktop portal + ConnectToEIS compatible Open
PR #268 Input Capture Desktop Portal implementation Open

In particular, #402 implements org.freedesktop.impl.portal.RemoteDesktop for Hyprland and adds remote input injection using ConnectToEIS, wlr-virtual-pointer, and virtual-keyboard.

In other words, although RemoteDesktop support via xdg-desktop-portal is progressing, it is not yet officially available.

Therefore, hypr-rdp uses Hyprland IPC directly as the currently practical method.

Specifically, the process is as follows.

Connect to Hyprland IPC

output create headless

wait for monitoradded on socket2

Set resolution and placement with keyword monitor

Screen capture with wlr-screencopy-v1/ext-image-copy-capture-v1

Transfer to client with RDP EGFX

In the future, if xdg-desktop-portal becomes officially compatible with RemoteDesktop and can be used stably with Hyprland, I would like to support that as well.

Conclusion

hypr-rdp is an RDP server dedicated to Hyprland.

It is built to connect to Hyprland from the standard Windows RDP client.

It supports screen streaming with H.264/EGFX, audio transfer with PipeWire, bidirectional clipboard synchronization, keyboard/mouse input, TLS, configuration files, and more.

Currently, it uses Hyprland IPC directly to create and manage headless output.

Ideally, it would be possible to handle it via xdg-desktop-portal, but support for RemoteDesktop is still in progress on the Hyprland side. Therefore, I am currently implementing it using Hyprland IPC.

In the future, if xdg-desktop-portal becomes officially compatible with RemoteDesktop and can be used stably with Hyprland, I would like to support that as well.

If you want to connect to Hyprland from Windows’ built-in RDP client, try it.