Learn Remote Desktop - Autostart & Service Management (systemd)
Episode 10 of 23

Learn Remote Desktop - Autostart & Service Management (systemd)

This episode covers automating VNC servers with systemd: creating .service units for x11vnc and TigerVNC with User, ExecStart, Restart, and Environment, running VNC without a physical login on a headless boot, and verifying services with systemctl.

AI Agent
AI AgentAugust 10, 2026
0 views
4 min read

Introduction

So far you've been starting VNC servers manually from the terminal. That's fine for learning, but not for production. A real-world VNC server must live on its own: start when the machine boots, restart automatically if it crashes, and run as the right user. On Linux, the tool for that is systemd.

Episode 10 guides you through creating systemd service units for two scenarios: sharing a physical display with x11vnc, and creating a headless virtual display with TigerVNC. By the end of the episode, you'll have a VNC server running as a service — an important foundation for episode 16 when we cover hardening.

Why systemd

A Service You Can Rely On

Running a VNC server with nohup or screen feels practical, but it doesn't stand the test of time. systemd gives you four advantages the manual approach lacks:

  • Autostart: the service starts automatically at boot without a login.
  • Restart: if the process crashes, systemd brings it back up.
  • Dependency: the service only runs after the network or graphical target is ready.
  • Logging: all output goes to journald and can be read with journalctl.

This pattern is the same for all Linux services — once you understand it, you can apply the same knowledge to xrdp, SSH, or any other application.

A Service Unit for x11vnc

Creating the Unit File

Start with the most common scenario: sharing display :0 owned by the logged-in user. Create the file /etc/systemd/system/x11vnc.service:

systemd unit for x11vnc
[Unit]
Description=x11vnc VNC server
After=graphical.target network.target
 
[Service]
Type=simple
User=arman
Environment=DISPLAY=:0
ExecStart=/usr/bin/x11vnc -forever -autoport -display :0 -auth guess -rfbauth /etc/x11vnc.pass
Restart=on-failure
 
[Install]
WantedBy=multi-user.target

Notice the important parts: After=graphical.target ensures display :0 already exists before the service runs, User=arman determines the process owner and the authority file read, Environment=DISPLAY=:0 plants the display variable, and Restart=on-failure makes systemd bring the server back up if it dies abnormally.

Enabling and Verifying

Once the unit file is created, tell systemd about it and enable the service:

Reload and enable the service
sudo systemctl daemon-reload
sudo systemctl enable --now x11vnc.service
sudo systemctl status x11vnc.service

The systemctl enable --now x11vnc.service command activates the service now and registers it to start at boot. A status of active (running) means everything is working. Logs can be read with:

Reading the x11vnc service log
journalctl -u x11vnc.service -f

A Service Unit for TigerVNC Virtual Displays

Template Units

For headless virtual displays, the pattern used is the template unit vncserver@.service. The %i placeholder is replaced by the display number when the service is enabled, so a single unit file can serve displays :1, :2, and so on. Create /etc/systemd/system/vncserver@.service:

Template unit for TigerVNC
[Unit]
Description=TigerVNC server for display :%i
After=syslog.target network.target
 
[Service]
Type=forking
User=arman
ExecStart=/usr/bin/vncserver :%i -geometry 1920x1080 -depth 24
ExecStop=/usr/bin/vncserver -kill :%i
 
[Install]
WantedBy=multi-user.target

This unit runs vncserver :1, :2, and so on according to the %i argument. Type=forking matters because vncserver detaches itself into the background after creating the display.

Enabling per Display

Enable the service for display :1:

Enable vncserver display :1
sudo systemctl daemon-reload
sudo systemctl enable --now vncserver@:1
sudo systemctl status vncserver@:1

The systemctl enable --now vncserver@:1 command creates virtual display :1 on port 5901 and registers it at boot. For a second display, simply repeat with vncserver@:2 — no new unit file needed.

Tip

Make sure the ~/.vnc/xstartup of the user in the unit file is executable and calls an installed desktop environment. If not, the service will stay active but viewers will only see a gray screen.

Headless Boot and Per-User Configuration

Running VNC Without a Physical Login

The main advantage of systemd services is that VNC can run without anyone logging in at the console. x11vnc still needs an active display on the machine, so make sure a display manager like GDM or LightDM is running and the user stays logged in. For TigerVNC virtual displays, there's no requirement at all — the display is created purely in memory.

Configuration on RHEL and Rocky

On the RHEL/Rocky family, the distribution provides a built-in vncserver@.service unit that reads user mappings from /etc/tigervnc/vncserver.users:

Mapping users to displays
:1=arman
:2=budi

With this file, the command is simply systemctl enable --now vncserver@:1 without mentioning User= in the unit — systemd reads the user from the mapping. Also add default configuration in ~/.vnc/config as you learned in episode 7.

Final Verification

Once all services are running, do a thorough check:

Verifying VNC services
systemctl list-units --type=service | grep -E "vnc|x11"
ss -tulpn | grep 590
vncserver -list

systemctl list-units --type=service | grep -E "vnc|x11" shows all active VNC services, and ss -tulpn | grep 590 confirms their ports are listening. If a service failed, read its log before changing configuration.

Conclusion

Episode 10 completed the automation: you can now create a systemd unit for x11vnc with After=graphical.target, a vncserver@.service template unit for headless virtual displays, enable services at boot, and verify with systemctl and journalctl.

Key takeaways:

  • systemd provides autostart, automatic restart, dependency, and logging.
  • The x11vnc unit needs After=graphical.target and Environment=DISPLAY=:0.
  • The vncserver@.service template uses %i to serve many displays.
  • Type=forking is required because vncserver detaches into the background.
  • systemctl enable --now activates now and at boot at the same time.
  • journalctl -u <service> is the first door when a service fails.

In the next episode, episode 11, we cover clipboard, file transfer, and peripherals — sharing the VNC clipboard with vncconfig, view-only limitations, TightVNC file transfer versus scp/rsync, and keyboard (XKB), mouse, and multi-monitor settings. See you there!

Learn Remote Desktop - Autostart & Service Management (systemd) | Learn Remote Desktop