SSD Nodes Learn 🎉 VPS from $5.50/mo
How to do am Matt ConnorBy Matt Connor

How to Run Linux VPS Desktop with xrdp and XFCE

Set up a real Linux VPS desktop with xrdp and XFCE, tunnel RDP through SSH instead of port 3389, and know when RustDesk no be the right tool.

Wetin remote desktop for Linux VPS really mean

Two different products dey answer the search "remote desktop on a Linux VPS", and if you choose the wrong one, e fit waste your whole afternoon. The first one na remote-access broker. RustDesk self-hosted server na common example: e dey relay session between two machines wey you already own, like your laptop and the PC for house. The rented server no dey draw any desktop. E just connect the two ends and forward packets when dem no fit reach each other directly. The second one na real graphical desktop wey dey run for the rented server, so na the data centre dey draw the pixels and stream dem come meet you. That one na xrdp, VNC (virtual network computing), or a container workspace.

One question dey separate the two. Once this thing dey work, where mouse pointer dey? If na machine wey you already own, you need broker. If na the VPS itself, you need desktop for the VPS. The second case get most of the space below, because na the case wey most guides dey skip.

Which option fit your job

  • RustDesk with your own relay. E protect the session make e no pass through public rendezvous server wey strangers dey run, because na you hold the key pair. E no protect the machine wey you dey control. Na still the PC wey you install the client on, with any password wey that PC get.
  • xrdp over an SSH tunnel or a VPN. E protect you from the constant internet-wide scanning of TCP 3389 and password guessing against the RDP login box, because that port no dey face internet at all. E no protect weak account password from anybody wey already get access to the tunnel.
  • VNC over the same tunnel. E give you desktop session wey fit continue after disconnection, with protocol wey old and simpler pass RDP. By itself, e no protect anything. Na the tunnel dey handle all the security work, so VNC alone for public port na the worst option here.
  • A container workspace such as Webtop or Kasm. E give you browser or complete desktop inside container wey you fit throw away and rebuild, so e protect your real machine from anything wey that browser touch. E no protect the host. These images dey run with broad privileges and passwordless sudo inside, so you no suppose trust the container as boundary for hostile workload.

Install xrdp and XFCE for Ubuntu 24.04

VPS server image no dey come with graphical desktop. You go install one, then install xrdp, the open-source server wey dey speak RDP (remote desktop protocol), the same protocol wey Windows client dey speak. Choose light desktop, and XFCE na the usual choice.

sudo apt update
sudo apt install -y xrdp xorgxrdp xfce4 xfce4-goodies dbus-x11
systemctl is-active xrdp

As of August 2026, Ubuntu 24.04 get xrdp 0.9.24 and xorgxrdp for the universe component. Install xorgxrdp by name even though na only recommended package e be: na the X server backend wey xrdp dey start for new session. If e no dey, the login box go accept your password, then return you straight back to the login box.

Now tell the session which desktop e suppose start. xrdp dey run /etc/xrdp/startwm.sh, and that one dey run ~/.xsession when the file dey exist.

echo "xfce4-session" > ~/.xsession
chmod 644 ~/.xsession

Finally, xrdp need read the TLS (transport layer security) key wey e dey offer clients. That file get mode 640 and the ssl-cert group own am.

ls -l /etc/ssl/private/ssl-cert-snakeoil.key
id xrdp

The listing dey show -rw-r----- 1 root ssl-cert. If id xrdp no print ssl-cert among the groups, run sudo adduser xrdp ssl-cert then sudo systemctl restart xrdp. If you skip this, xrdp no go fit open the key, and /var/log/xrdp.log go record the failure with the snakeoil filename for the line.

Wetin make you no open port 3389 to internet

Everything for internet dey scan TCP 3389 continuously, and RDP login box dey answer every password attempt politely. No open am. Bind xrdp to loopback address instead, then reach am through tunnel wey you already trust.

Edit /etc/xrdp/xrdp.ini and change listener for [Globals] section.

[Globals]
port=tcp://.:3389

The file wey ship with am document that syntax for its own comments: tcp://.:3389 mean 127.0.0.1:3389, while tcp://:3389 mean every interface. Restart and confirm, because typo here fit silently leave the service for all addresses.

sudo systemctl restart xrdp
ss -tlnp | grep 3389

You need 127.0.0.1:3389. If you see 0.0.0.0:3389, e mean xrdp ignore your edit. Most times, na because the line end up under another section heading further down the file.

Now open the tunnel from your own machine.

ssh -N -L 3389:127.0.0.1:3389 you@vps.example.com

-N mean “open the connection but run no command”, so the session dey exist only to carry the port. Leave that terminal running and point the RDP client to 127.0.0.1:3389. For Linux client, the software na FreeRDP 3, and its binary name for Ubuntu 24.04 na xfreerdp3:

sudo apt install -y freerdp3-x11
xfreerdp3 /v:127.0.0.1:3389 /u:you /dynamic-resolution +clipboard /sound

For Windows, use the built-in mstsc and type 127.0.0.1 as the computer. FreeRDP go ask you to trust the certificate for the first connection and print Do you trust the above certificate? (Y/T/N). That one dey expected with the self-signed snakeoil certificate.

If ssh answer bind [127.0.0.1]:3389: Address already in use, something for your own machine already dey use 3389. Move the local end with ssh -N -L 13389:127.0.0.1:3389 you@vps.example.com and connect to 127.0.0.1:13389.

One tunnel for each person fit become tiring, so private network na better option for team. Put the box behind self-hosted WireGuard VPN, give am tunnel address 10.8.0.1, and set port=tcp://10.8.0.1:3389 so xrdp go answer only inside the VPN. Any way wey you choose, firewall rule for 3389 no suppose exist at all. If you no sure wetin your current rules allow, start from ufw firewall basics for VPS and check before you connect, no be after.

How much RAM remote desktop dey use for a 2 GB VPS

The desktop wey you choose go decide whether 2 GB plan go comfortable or hopeless. The figures below na rounded typical numbers for memory wey dey use just after login for Ubuntu 24.04. Dem come from published comparisons, no be measurement for your machine. Measure your own with free -m immediately after you connect.

ChartTypical memory in use after login, Ubuntu 24.04 (published figures)
The data behind this chart
[
  {
    "label": "LXQt",
    "idle_ram_mb": 300
  },
  {
    "label": "XFCE",
    "idle_ram_mb": 400
  },
  {
    "label": "MATE",
    "idle_ram_mb": 500
  },
  {
    "label": "KDE Plasma",
    "idle_ram_mb": 800
  },
  {
    "label": "GNOME",
    "idle_ram_mb": "1,200"
  }
]

For those 5 desktops, the difference na the main point. LXQt dey near 300 MB and XFCE dey near 400 MB, so either one go leave space for browser on 2 GB machine. GNOME need roughly 1,200 MB before you open even one window. For 2 GB, browser go then dey fight desktop for the remaining memory.

Browser na the real cost, no be desktop shell. Modern browser dey use between 150 and 400 MB for each active tab, so 2 GB VPS wey dey run XFCE fit handle some tabs, then e go start swapping. Add swap so machine go slow down instead of killing processes: sudo fallocate -l 2G /swapfile, then sudo chmod 600 /swapfile, sudo mkswap /swapfile, sudo swapon /swapfile, and add matching line for /etc/fstab so e go survive reboot. When something disappear without warning, run dmesg | grep -i "killed process". That line mean say kernel out-of-memory killer don end the process, and browser na usually the victim.

CPU na the other limit, and e easy to underestimate am. VPS no get GPU, so X go fall back to software rendering through llvmpipe. This mean say CPU dey draw every pixel. Scrolling heavy page and playing video both go show as ordinary CPU load, and frame rate go drop instead of machine freezing. Na the same limit you go meet if you dey wonder whether VPS fit run games: for anything 3D, answer na no, and na exactly because of this.

Sound and clipboard inside xrdp session

Ubuntu 24.04 dey use PipeWire for audio, but xrdp sound redirection na PulseAudio dem write am for. So fresh install go give you working video but no sound. Ubuntu package the bridge.

sudo apt install -y pipewire-module-xrdp pulseaudio-utils alsa-utils

Log out from the RDP session completely, then log in again, because the module dey load when session start. Reconnect alone no dey enough. Then check from inside the session:

pactl list short sinks
speaker-test -c 2 -t wav -l 1

You suppose see a sink wey name mention xrdp, and hear the test tone through your client. If no xrdp sink dey, the module no load into this session. Your client also need request audio: na the /sound flag for xfreerdp3, or the "Remote audio" setting under Local Resources for the Windows client.

Text clipboard dey work for both directions once xrdp-chansrv dey run for your session. xrdp dey start am for you. Confirm am with pgrep -a xrdp-chansrv. If copy and paste stop working halfway through session, that process don die, and reconnecting go restart am. Copying files instead of text na separate channel wey dem call drive redirection: /drive:home,/home/you for xfreerdp3 mounts local folder inside the remote session.

The polkit popup, and other first-login failures

The most common first-login surprise na dialog wey dey show Authentication is required to create a color managed device. The cause dey specific. The colord service dey ask polkit for permission. polkit dey grant that action silently only to session wey e see as locally seated. RDP session no be seated, so polkit go ask you for password instead. Ubuntu 24.04 dey ship with polkit 124. E remove the old local authority .pkla files, so any guide wey tell you make you write /etc/polkit-1/localauthority/50-local.d/45-allow-colord.pkla no get effect at all for 24.04. Write JavaScript rule instead.

/* /etc/polkit-1/rules.d/45-allow-colord.rules */
polkit.addRule(function(action, subject) {
    if (action.id.indexOf("org.freedesktop.color-manager.") === 0 &&
        subject.isInGroup("sudo")) {
        return polkit.Result.YES;
    }
});

Run sudo systemctl restart polkit and reconnect. Two other failures dey worth knowing from their symptoms.

The login box accepts your password, then e come back immediately. The session start and die. Read /var/log/xrdp-sesman.log first, then ~/.xsession-errors for your home directory. Missing xorgxrdp, ~/.xsession wey name desktop wey no dey installed, home directory wey you no fit write to, or full disk fit all cause this problem.

You connect and see grey screen with X cursor. X start, but the desktop no start. Na ~/.xsession again: run xfce4-session by hand over SSH and read the error wey e print.

Wetin the self-hosted RustDesk server dey do

RustDesk dey split into two processes. hbbs na the ID and rendezvous server wey clients dey register with, while hbbr na the relay wey dey carry the session when direct peer-to-peer connection fail. None of dem dey run desktop. Both come from one image, and na this compose file the project publish, with the relay address changed to your own host name:

services:
  hbbs:
    container_name: hbbs
    image: rustdesk/rustdesk-server:latest
    command: hbbs -r rustdesk.example.com:21117
    ports:
      - 21115:21115
      - 21116:21116
      - 21116:21116/udp
      - 21118:21118
    volumes:
      - ./data:/root
    restart: unless-stopped
  hbbr:
    container_name: hbbr
    image: rustdesk/rustdesk-server:latest
    command: hbbr
    ports:
      - 21117:21117
      - 21119:21119
    volumes:
      - ./data:/root
    restart: unless-stopped

Bring am up, then read the public key wey the server generate for the first time e start:

sudo docker compose up -d
sudo cat ./data/id_ed25519.pub

Every client need your host name and that public key. Enter both of dem under Network settings for the RustDesk client. The matching private key dey inside ./data/id_ed25519. If you delete the data directory, the server go generate fresh key pair, so every client go need reconfigure with the new key. Back up that directory.

Firewall must allow these ports directly. hbbs uses TCP 21115, 21116 and 21118, plus UDP 21116. hbbr uses TCP 21117 and 21119.

sudo ufw allow 21115/tcp
sudo ufw allow 21116/tcp
sudo ufw allow 21116/udp
sudo ufw allow 21117/tcp
sudo ufw allow 21118/tcp
sudo ufw allow 21119/tcp

Why RustDesk no go behind nginx or Traefik

Readers wey already dey terminate TLS for everything for one reverse proxy dey try this, but e dey fail. hbbs and hbbr dey use their own binary protocols over TCP and UDP, no be HTTP. No Host header dey to route with, and no HTTP request dey to inspect, so nginx server block or Traefik HTTP router get nothing to match. The UDP listener for 21116 no be HTTP thing for any layer.

Two things dey work. nginx fit forward the TCP ports with a stream block. This na plain layer 4 forwarding, no be reverse proxy for the usual meaning. Ports 21118 and 21119 carry the websockets wey RustDesk web client dey use. This one na ordinary HTTP, so both ports fit sit behind your proxy. If you do this, add firewall rules so na only the proxy fit reach 21118 and 21119. hbbs trusts the X-Real-IP header for websocket connections to determine the real client address.

Container wey get disposable browser

Sometimes wetin you need na clean browser with IP wey no dey change, and wey dey separate from your own machine. Container workspace fit do this with much less software installation. LinuxServer Webtop na the light option:

services:
  webtop:
    image: lscr.io/linuxserver/webtop:latest
    container_name: webtop
    environment:
      - PUID=1000
      - PGID=1000
      - TZ=Etc/UTC
    volumes:
      - /path/to/data:/config
    ports:
      - 127.0.0.1:3000:3000
      - 127.0.0.1:3001:3001
    shm_size: "1gb"
    restart: unless-stopped

Port 3000 dey serve HTTP, while 3001 dey serve HTTPS. You go reach the desktop through browser tab, without any RDP client. Image tags cover XFCE, KDE, MATE, and i3 for several base distributions. The project documentation talk the risk plainly: the container get privileged access to host and e include terminal with passwordless sudo. So, you no suppose expose am to internet without protection. Na why the ports above dey bind to 127.0.0.1 instead of publishing dem for all addresses. Reach am through the same SSH tunnel or VPN wey you use for xrdp.

Kasm Workspaces na the same idea, but e dey operate for much bigger scale. E get web console, user accounts, and per-session containers wey reset when the session end. E need more machine resources than small VPS fit get. As of August 2026, the documented minimum na 2 CPU cores, 4 GB memory, and 50 GB SSD. On top of that, each user session dey default to 2 cores and 2768 MB. 2 GB plan no go run am. The installation na download plus script:

cd /tmp
curl -O https://kasm-static-content.s3.amazonaws.com/kasm_release_1.17.0.7f020d.tar.gz
tar -xf kasm_release_1.17.0.7f020d.tar.gz
sudo bash kasm_release/install.sh

VNC, and where e still fit

VNC dey send framebuffer updates instead of drawing commands, so e dey feel heavier pass RDP for slow link, and e no carry sound channel. E make sense for one situation: you want desktop session wey go continue to run after you disconnect, and you want the same session back when you return. TigerVNC dey do that. vncserver -localhost yes :1 dey bind Xvnc to 127.0.0.1 for TCP 5901, and e dey reject connections from anywhere else, so you tunnel am exactly like xrdp with ssh -N -L 5901:127.0.0.1:5901 you@vps.example.com. Never publish VNC port. Most VNC servers dey protect password during handshake, but nothing after that. So, if port dey public, anybody fit read the session contents for the network.

VPS good desktop be?

As daily-use machine, no, and reasons plenty. GPU no dey, so CPU dey draw everything. Every keystroke dey wait for network round trip, and 40 ms latency wey feel okay for SSH dey noticeable for text editor. Site compress video once, then RDP encoder compress am again. Your files dey on disk wey you no hold, and heavy desktop use dey finish monthly bandwidth allowance wey dem size for web server.

As disposable machine, e good well, and na the same properties explain why. IP address stable and e belong to data centre, na wetin you want when service must see consistent address. Machine fit rebuild from image within minutes, so if session pick something nasty, e no cost you anything. E separate from your real hardware, and e continue to run when you close laptop. Hourly billing make throwaway desktop cheap.

If you still dey work out wetin the box go do, this practical list of wetin VPS good for worth reading before you install desktop on top. And if na one Windows application make you want desktop, compare am with the real differences between Linux and Windows Server first, because the licence dey change the cost of the answer.

FAQ

I fit run remote desktop for 2 GB VPS?

Yes, if you use light desktop. XFCE or LXQt dey use around 300 to 400 MB after login, so memory still dey enough for browser with small number of tabs. GNOME or KDE Plasma for 2 GB go leave almost no memory for applications. Add 2 GB swap file so memory pressure go slow the machine instead of killing processes. If something disappear without any message, check dmesg | grep -i "killed process" for kernel out-of-memory killer.

I suppose open port 3389 for my VPS firewall?

No. TCP 3389 dey under constant scanning, and exposed RDP login box dey invite password guessing. Set port=tcp://.:3389 inside /etc/xrdp/xrdp.ini so xrdp go listen only on 127.0.0.1. Confirm am with ss -tlnp | grep 3389, then reach am with ssh -N -L 3389:127.0.0.1:3389 you@vps.example.com. If more than one or two people go use am, bind xrdp to WireGuard address instead of loopback.

Why xrdp dey ask "Authentication is required to create a color managed device"?

colord service dey ask polkit for permission. polkit dey grant that action silently only to session wey person dey physically sit for the machine. RDP session no be seated session, so password prompt go show for every login. For Ubuntu 24.04, the old .pkla fix no dey work because polkit 124 remove support for local authority files. Create /etc/polkit-1/rules.d/45-allow-colord.rules with JavaScript rule wey returns polkit.Result.YES for action ids wey start with org.freedesktop.color-manager., then run sudo systemctl restart polkit.

I fit put self-hosted RustDesk server behind nginx or Traefik?

No be the main service. hbbs and hbbr dey use their own binary protocols instead of HTTP, so dem no get Host header wey proxy fit use for routing. UDP 21116 no fit pass through HTTP proxy at all. Open TCP 21115 through 21119 and UDP 21116 for firewall, then make clients connect directly. The websocket ports 21118 and 21119, wey web client dey use, na HTTP and fit stay behind proxy. If you do this, configure firewall so na only proxy fit reach dem, because hbbs trusts X-Real-IP for those connections.

Why sound no dey for my xrdp session?

Ubuntu 24.04 dey use PipeWire, but xrdp sound redirection na for PulseAudio, so audio no go show until you install bridge. Run sudo apt install -y pipewire-module-xrdp, then log out of the session completely and log in again. The module dey load when session start, and reconnect no go load am. Check with pactl list short sinks for sink wey name xrdp. Also make sure client request audio. For /sound on xfreerdp3, or "Remote audio" for Windows client, na that setting dey control am.

#remote-desktop#xrdp#rustdesk#vnc#self-hosting