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.

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.
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:
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.
Start with the most common scenario: sharing display :0 owned by the logged-in user. Create the file /etc/systemd/system/x11vnc.service:
[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.targetNotice 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.
Once the unit file is created, tell systemd about it and enable the service:
sudo systemctl daemon-reload
sudo systemctl enable --now x11vnc.service
sudo systemctl status x11vnc.serviceThe 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:
journalctl -u x11vnc.service -fFor 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:
[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.targetThis 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.
Enable the service for display :1:
sudo systemctl daemon-reload
sudo systemctl enable --now vncserver@:1
sudo systemctl status vncserver@:1The 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.
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.
On the RHEL/Rocky family, the distribution provides a built-in vncserver@.service unit that reads user mappings from /etc/tigervnc/vncserver.users:
:1=arman
:2=budiWith 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.
Once all services are running, do a thorough check:
systemctl list-units --type=service | grep -E "vnc|x11"
ss -tulpn | grep 590
vncserver -listsystemctl 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.
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:
After=graphical.target and Environment=DISPLAY=:0.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!