This is the setup pattern I use on this Linux box so I can reach it remotely without a physical monitor attached.
The stack is:
Tailscalefor private network access.NoMachinefor remote desktop.Xvfbon display:99to provide a fake display.XFCErunning inside that virtual display.
These system services are enabled at boot:
tailscaled.servicenxserver.serviceheadless-xfce.service
The important local files are:
- /etc/systemd/system/headless-xfce.service
- /usr/local/bin/headless-xfce.sh
- /usr/lib/systemd/system/nxserver.service
- /usr/lib/systemd/system/tailscaled.service
- /usr/NX/etc/node.cfg
On a Debian/Ubuntu-style machine:
sudo apt update
sudo apt install -y xvfb xfce4 xfce4-session dbus-x11 tailscaleThen install NoMachine from their .deb package.
After that, verify the key binaries exist:
which Xvfb
which startxfce4
which tailscaled
test -x /etc/NX/nxserver && echo "NoMachine installed"Create /usr/local/bin/headless-xfce.sh with this content:
#!/bin/bash
export DISPLAY=:99
export XDG_SESSION_TYPE=x11
export XDG_CURRENT_DESKTOP=XFCE
export DESKTOP_SESSION=xfce
export XDG_RUNTIME_DIR=/run/user/1000
pkill -f "Xvfb :99" || true
rm -f /tmp/.X99-lock
rm -f /tmp/.X11-unix/X99
/usr/bin/Xvfb :99 -screen 0 1920x1080x24 -nolisten tcp -ac &
sleep 3
exec /usr/bin/dbus-run-session -- startxfce4Make it executable:
sudo chmod +x /usr/local/bin/headless-xfce.shWhat this does:
- forces everything onto display
:99 - starts a virtual X server at
1920x1080x24 - clears stale X lock files first
- launches
XFCEinside that fake display
Create /etc/systemd/system/headless-xfce.service:
[Unit]
Description=Headless XFCE on Xvfb :99
After=network.target
[Service]
User=clawffrey
Environment=DISPLAY=:99
ExecStart=/usr/local/bin/headless-xfce.sh
Restart=always
[Install]
WantedBy=multi-user.targetThen enable it:
sudo systemctl daemon-reload
sudo systemctl enable --now headless-xfce.serviceCheck it:
systemctl status headless-xfce.serviceNoMachine is the remote desktop layer. The service on this machine is:
sudo systemctl enable --now nxserverIts unit file runs:
ExecStart=-/etc/NX/nxserver --daemonThe main node config on this box is /usr/NX/etc/node.cfg.
One relevant line there is:
DefaultDesktopCommand "/usr/bin/cinnamon-session --session cinnamon"
Even though that line still says Cinnamon, my actual working headless session is the systemd-managed XFCE session on :99, started by headless-xfce.service. That is the part I rely on.
To verify NoMachine itself:
/etc/NX/nxserver --status
sudo systemctl status nxserverTailscale is just the secure path into the machine. The daemon is enabled at boot with:
sudo systemctl enable --now tailscaledThen bring the node into your tailnet:
sudo tailscale upUseful checks:
tailscale ip
tailscale status
sudo systemctl status tailscaledOnce the machine is on Tailscale, connect to it from NoMachine using the machine’s Tailscale IP or MagicDNS name instead of exposing NoMachine directly to the public internet.
Francesco also needs Tailscale and NoMachine installed on his own laptop or desktop.
- Install
Tailscale. - Install the
NoMachineclient. - Sign in to Tailscale using the same tailnet you shared this machine into.
- Confirm his computer is online in Tailscale.
Make sure this machine is also logged into Tailscale:
sudo tailscale up
tailscale ip -4
tailscale status
hostnamectl --staticThe useful address choices for NoMachine are:
- the machine's Tailscale IPv4 address from
tailscale ip -4 - the machine's Tailscale MagicDNS name, if enabled
- the host's normal name, which on this box is
clawffrey-Jasper-Lake-Client-Platform
In practice, the Tailscale IP is usually the easiest thing to hand Francesco.
On Francesco's computer:
- Open NoMachine.
- Click
New. - Choose the
NXprotocol. - For
Host, enter this machine's Tailscale IP or MagicDNS name. - Leave the default NoMachine port unless you intentionally changed it.
The default NoMachine TCP port is
4000. - Save the connection.
- Connect and log in with the Linux username and password for this machine.
Once connected, he should land in the headless XFCE desktop running on Xvfb :99.
Something like this:
1. Install Tailscale and NoMachine on your computer.
2. Join my Tailscale network.
3. In NoMachine, create a new NX connection to:
Host: <my tailscale IP or MagicDNS name>
Port: 4000
4. Log in with my Linux machine username/password.
If you want, replace the placeholder with the actual Tailscale IP before sending him the guide.
These are the main commands I’d run when checking whether the stack is healthy:
systemctl status headless-xfce.service
systemctl status nxserver
systemctl status tailscaled
ps -ef | grep Xvfb
echo $DISPLAY
tailscale status
/etc/NX/nxserver --statusIf you want to confirm the fake display exists:
ls -l /tmp/.X11-unix/You should see X99.
On this machine, /etc/NX/nxserver --status currently reports:
'/etc/NX/server/localhost/runner.cfg' has wrong ownership
That file currently belongs to nobody:nogroup, which is unusual. However, NoMachine is still actively working on this box, so treat this as a status-path warning, not proof that the remote desktop is broken.
If Francesco hits the same warning, check:
ls -l /etc/NX/server/localhost/runner.cfgand compare ownership with a clean NoMachine install. That is a NoMachine-specific warning, not a Tailscale or Xvfb :99 problem.
If Francesco only wants the gist:
- install
tailscale,xvfb,xfce4, andNoMachine - run
Xvfbon:99 - launch
XFCEagainstDISPLAY=:99 - keep that alive with
systemd - enable
nxserverandtailscaled - connect to NoMachine over the Tailscale network