RSS Amplifier

Blogs by otaku - Coding Otaku · Jan 15, 2026

My Remote Desktop Setup in Wayland

0
Sign in to vote or save

Coding Otaku · Coding Otaku

Dependencies

The tools I use are the following:

  • wayvnc for the VNC server
  • wlvncc for the VNC client
  • PulseAudio for forwarding audio
  • fzf for setting up headless Wayland session

That’s it!

Starting Headless Wayland session

I wrote a start-sway script that launches on login, it can also be run via SSH. What it does is show a FZF menu that let me select whether I want to launch swaywm in headless mode or in normal mode.

The headless mode lets you run sway without having a real monitor, instead it creates a dummy output that you can still interact with.

To launch a wayland session in headless mode, we need to set the following environment variables.

export WLR_BACKENDS=headless
export WLR_LIBINPUT_NO_DEVICES=1
export WAYLAND_DISPLAY=wayland-1

The script set up more environment variables, but those are the essential ones.

This is the complete script which creates XDG_RUNTIME_DIR, and setup other essential XDG variables before starting sway:

setup_runtime() {
    ID=$(id -u)
    if test -z "${XDG_RUNTIME_DIR}"; then
        export XDG_RUNTIME_DIR="/run/user/${ID}"
    fi
    if test -d "${XDG_RUNTIME_DIR}"; then
        perms="$(stat -c '%a %u' "${XDG_RUNTIME_DIR}")"
        if [ "${perms}" != "700 ${ID}" ]; then
            unset XDG_RUNTIME_DIR
            echo "WARNING! XDG_RUNTIME_DIR has incorrect permissions, unsetting it"
        fi
    else
        mkdir -p "${XDG_RUNTIME_DIR}"
        chmod 0700 "${XDG_RUNTIME_DIR}"
    fi
    if test -z "${DBUS_SESSION_BUS_ADDRESS}"; then
        #https://github.com/OpenRC/openrc/issues/924
        export DBUS_SESSION_BUS_ADDRESS="unix:path=${XDG_RUNTIME_DIR}/bus"
    fi
}
select_session() {
    session_type=$(printf 'Headless\nNormal\n' | fzf --reverse --height=10 --prompt='Choose Session type > ')
    if [ "${session_type}" = "Headless" ]; then
        export WLR_BACKENDS=headless
        export WLR_LIBINPUT_NO_DEVICES=1
        export WAYLAND_DISPLAY=wayland-1
    fi
    export XDG_SESSION_TYPE=wayland
    export XDG_SESSION_DESKTOP=sway
    export XDG_CURRENT_DESKTOP=sway
}
setup_runtime
select_session
dbus-run-session sway

You can replace sway at the end with any Wayland compositor.

Connecting to VNC

Once sway has started in headless mode (you can start it through SSH too!), the next step is to run the VNC server.

I usually run only one VNC server at a time, so I kill any existing server before starting a new one. So that my programs won’t overwrite files from different sessions.

ssh [ip address] WAYLAND_DISPLAY=wayland-1 killall wayvnc

The next step is to run a VNC server and forward the server port to the local.

ssh -L 5900:localhost:5900 [ip address] WAYLAND_DISPLAY=wayland-1  wayvnc localhost

You may also use a nix socket instead, like this, before running the server:

ssh -L 35900:/home/[username]/.config/wayvnc/sock

The WAYLAND_DISPLAY and XDG_RUNTIME_DIR variables may not be needed depending on your setup. I set my system in a way that most user-specific variables are unset when connecting through ssh, so this is more of a failsafe.

Connecting to PulseAudio

In the client, we need to load the module-native-protocol-tcp module though PulseAudio so that the server can connect to it.

pactl load-module module-native-protocol-tcp

You can unload it at the end of the session

pactl unload-module module-native-protocol-tcp

You could combine everything together on the client in a single script:

printf 'Killing existing VNC server\n'
ssh "${USERNAME}@${HOST}" killall wayvnc
printf 'Setting up audio tunnel\n'
pactl load-module module-native-protocol-tcp
printf 'Starting VNC\n'
ssh -L 5900:localhost:5900 "${USERNAME}@${HOST}" WAYLAND_DISPLAY=wayland-1 XDG_RUNTIME_DIR=/var/run/user/1000 wayvnc localhost
printf 'Removing audio tunnel\n'
pactl unload-module module-native-protocol-tcp

Now on the server, you need to connect to the client’s PulseAudio tunnel/server:

pactl load-module module-tunnel-sink server="${CLIENT_IP}"

That’s it! Now you can select the tunnel as the audio output to get audio.

Launching VNC

You could use any VNC client for this. All I do is wlvncc localhost 5800.

Conclusion

Running VNC through Wayland is now easier than before. But we still lack an all-in-one solution, unlike the X11 ecosystem has.

Read the original on codingotaku.com

Comments

Nothing yet. Say the first thing.

    Sign in to join the conversation.