Dahao's Personal Website

See Your (Physical) Ubuntu Desktop on Your Mac (The Hard Way)

A story of ports, permissions, black screens, and one very stubborn GNOME session.


The Goal

I wanted something simple: see and control my Ubuntu desktop from my MacBook. Both machines are connected via Tailscale, so the network part was already sorted — no VPN headaches, no port forwarding, no dynamic DNS. Just two machines on the same Tailscale network with stable private IPs.


First Attempt: GNOME Remote Desktop

My Ubuntu machine was running GNOME Remote Desktop out of the box, which supports RDP natively. On the Mac side, I grabbed Microsoft Remote Desktop (MRD) from the App Store, punched in the Tailscale IP, and hit connect.

Error code: 0x207.

"We couldn't connect to the remote PC. This might be due to an expired password."

The credentials I was using were my Ubuntu system login credentials. Turns out, GNOME Remote Desktop has its own separate username and password — set inside Settings → System → Remote Desktop — completely independent from your Ubuntu account password. Once I set those and used them in MRD, authentication passed.

But then came the next problem.


The Black Screen of Despair

Connected. No error. Just... black. A perfectly empty void where my desktop should have been.

After some digging, I checked what session type Ubuntu was running:

echo $XDG_SESSION_TYPE

It returned x11. That was the clue. GNOME Remote Desktop is designed for Wayland, not X11. On X11, it connects but renders nothing useful — hence the black screen.

The natural fix seemed to be switching to Wayland. But when I tried disabling Wayland via /etc/gdm3/custom.conf:

WaylandEnable=false

I couldn't even log in via RDP anymore. I reverted that immediately and rethought the approach.


Switching to xrdp

Since GNOME Remote Desktop wasn't playing nicely on X11, the better solution was xrdp — a mature, battle-tested RDP server that works well on X11.

sudo apt install xrdp
sudo systemctl enable --now xrdp

Error.

[ERROR] g_tcp_bind(7, 3389) failed bind IPv6
[ERROR] trans_listen_address failed
[CORE ] Failed to start xrdp daemon, possibly another process is listening on the same port

Port 3389 was already taken. GNOME Remote Desktop was still holding it.


The Port War

To confirm:

sudo lsof -i :3389

Output:

COMMAND    PID                 USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
gnome-rem  xxxx gnome-remote-desktop   14u  IPv6  xxxxx      0t0  TCP *:ms-wbt-server (LISTEN)

Even after disabling GNOME Remote Desktop in Settings and rebooting, it came back. It was deeply embedded as a user-level systemd service. The fix was to kill it and prevent it from starting again:

sudo kill <PID>
systemctl --user disable gnome-remote-desktop
systemctl --user mask gnome-remote-desktop

The mask command is the nuclear option — it prevents the service from starting even if something else tries to enable it.

With GNOME Remote Desktop out of the way, xrdp started successfully:

sudo systemctl start xrdp
sudo systemctl status xrdp
# active (running) ✓

SSL Key Permission Errors

Victory was short-lived. Checking the xrdp logs:

sudo tail -f /var/log/xrdp.log

Revealed a cascade of errors:

[ERROR] Cannot read private key file /etc/xrdp/key.pem: Permission denied
[WARN ] Cannot accept TLS connections because certificate or private key file is not readable.
[ERROR] XRDP cannot read file: /etc/xrdp/rsakeys.ini (check permissions)

The SSL certificates that xrdp uses had wrong ownership and permissions. Fixed with:

sudo xrdp-keygen xrdp auto
sudo chown root:xrdp /etc/xrdp/key.pem /etc/xrdp/cert.pem /etc/xrdp/rsakeys.ini
sudo chmod 640 /etc/xrdp/key.pem /etc/xrdp/cert.pem /etc/xrdp/rsakeys.ini
sudo systemctl restart xrdp xrdp-sesman

Connected... But Nothing Happened

Back on the Mac, MRD would connect, show a brief "Configuring remote..." message, and then silently do nothing. No desktop. No error. Just silence.

Watching the xrdp log while connecting revealed the full picture:

[INFO ] login successful for user <your-username> on display 10
[INFO ] loaded module 'libxup.so' ok
[INFO ] started connecting
[INFO ] connected ok

The connection was fully succeeding. xrdp was authenticating, establishing a session, connecting to the display — everything worked. The problem was that no desktop session was being launched on the other end.


Getting a Desktop to Show Up

The fix was two-part. First, tell xrdp what session to launch by creating a ~/.xsession file:

echo "gnome-session" > ~/.xsession
chmod +x ~/.xsession

But GNOME over xrdp on X11 is notoriously finicky. The more reliable approach was to install a lighter desktop environment that xrdp handles well — XFCE4:

sudo apt install xfce4 xfce4-goodies
echo "startxfce4" > ~/.xsession
chmod +x ~/.xsession
sudo systemctl restart xrdp xrdp-sesman

During installation, a prompt appeared asking which display manager to use — gdm3 or lightdm. Since the machine uses GNOME locally, gdm3 was the right choice to keep things consistent.


It Works!

After restarting xrdp and connecting from the Mac, the XFCE4 desktop appeared — a fully functional Ubuntu desktop, rendered over Tailscale.

Any changes made in this session (files, installed apps, terminal configs) are saved to the real Ubuntu user account. Only the desktop appearance is XFCE4-specific. Everything else is shared with the normal Ubuntu environment.


Making It Survive Reboots

What happens when Ubuntu reboots? A few things needed to be in place:

1. xrdp starts automatically (already done):

sudo systemctl enable xrdp

2. Prevent GNOME Remote Desktop from coming back:

systemctl --user mask gnome-remote-desktop

3. Enable auto-login so there's always an active session:

Without auto-login, Ubuntu sits at the GDM login screen after a reboot, and xrdp has no session to connect to.

sudo nano /etc/gdm3/custom.conf

Add:

[daemon]
AutomaticLoginEnable=true
AutomaticLogin=<your-username>

With auto-login enabled, Ubuntu boots straight into a logged-in session, xrdp starts automatically, and you can connect from your Mac without ever touching the physical machine.


Plot Twist: It Came Back

After a reboot, I smugly opened MRD expecting everything to just work. Instead:

Error code: 0x207. Again.

sudo lsof -i :3389

GNOME Remote Desktop was back. And this time it was running under two users — my account and gdm. Masking it for just my user wasn't enough. gdm has its own user-level systemd instance and was starting its own copy of gnome-remote-desktop on boot.

The real fix required masking it at all three levels:

# Kill all instances
sudo kill $(sudo lsof -t -i :3389)

# Mask for your user
systemctl --user mask gnome-remote-desktop

# Mask for the gdm user
sudo -u gdm systemctl --user mask gnome-remote-desktop

# Mask at the system level for good measure
sudo systemctl mask gnome-remote-desktop

# Start xrdp
sudo systemctl start xrdp

After this, xrdp finally held port 3389 through reboots on its own.


The Final Setup

Here's what the working stack looks like:

Component Role
Tailscale Secure private network between Mac and Ubuntu — no firewall rules needed
xrdp RDP server on Ubuntu, starts on boot, listens on port 3389
XFCE4 Lightweight desktop environment served over RDP
GNOME Remote Desktop Masked and disabled so it never conflicts
Auto-login (gdm3) Ensures a session is always available after reboot
Microsoft Remote Desktop (Mac) RDP client, connects via Tailscale IP

Lessons Learned

GNOME Remote Desktop and xrdp cannot share port 3389. You must fully disable (and mask) one before the other will work.

GNOME Remote Desktop is built for Wayland. On X11, it connects but shows a black screen — not an error, just nothing.

xrdp SSL key permissions matter. The xrdp user must own and be able to read the key files, or TLS connections silently fail.

A successful RDP connection ≠ a successful desktop session. xrdp can authenticate and connect fine while the desktop session silently fails. Always check /var/log/xrdp.log and /var/log/xrdp-sesman.log.

XFCE4 is the most reliable desktop environment for xrdp on Ubuntu. GNOME over xrdp works but requires more configuration. XFCE4 just works.

systemctl mask is your friend. Unlike disable, masking a service prevents it from being started by anything — including other services or boot triggers.

Mask at all levels. GNOME Remote Desktop runs as both your user and the gdm user. You need to mask it for both with systemctl --user mask (run once as yourself, once as gdm via sudo -u gdm), plus sudo systemctl mask at the system level.


Total time spent: one evening, several errors, and a healthy respect for Linux display servers.