为 x11vnc 打造注销后自动重启的 Systemd 服务
问题现象
在 Linux 桌面环境中,常通过 x11vnc 提供远程桌面访问。把 x11vnc 注册为 Systemd 服务后,首次开机可以正常启动;但当用户注销并重新登录后,VNC 连接会断开,服务不会自动恢复,必须重启系统才能再次使用。
原始 Unit 文件
下面是一份最基本的 x11vnc 服务配置:
[Unit]
Description=X11 VNC remote desktop daemon
After=display-manager.service network.target
Requires=display-manager.service
[Service]
Type=simple
ExecStart=/usr/bin/x11vnc -auth guess -forever -rfbauth /etc/vnc/x11vnc.pass -rfbport 5900 -shared
ExecStop=/usr/bin/killall x11vnc
[Install]
WantedBy=multi-user.target
这份配置只负责把 x11vnc 拉起来,一旦 X 会话因注销而重置,x11vnc 进程退出,Systemd 默认不会再次启动它。
关键改动
让服务在失败后自动恢复,核心是在 [Service] 段加入重启策略:
Restart=always:无论以何种状态退出,Systemd 都会尝试重新拉起服务。RestartSec=3:每次重启前等待 3 秒,避免在 X 会话尚未就绪时频繁重试。
同时保留 Type=simple。x11vnc 本身不是典型的双进程守护进程,改为 forking 后反而容易出现主进程判断不准、服务反复断开的情况。
改造后的 Unit 文件
这里把服务命名为 vnc-auto.service,并把认证文件与端口提取为环境变量,便于后续维护:
[Unit]
Description=X11 VNC remote desktop daemon
After=display-manager.service network.target
Wants=display-manager.service
[Service]
Type=simple
Environment="AUTH_FILE=/etc/vnc/x11vnc.pass"
Environment="VNC_PORT=5900"
ExecStart=/usr/bin/x11vnc -auth guess -forever -shared -rfbauth ${AUTH_FILE} -rfbport ${VNC_PORT}
ExecStop=/bin/sh -c 'killall x11vnc || true'
Restart=always
RestartSec=3
[Install]
WantedBy=multi-user.target
加载并验证
保存文件后重新加载 Systemd 配置并启用服务:
sudo systemctl daemon-reload
sudo systemctl enable --now vnc-auto.service
sudo systemctl status vnc-auto.service
观察实时日志,确认注销后服务能够自动重启:
sudo journalctl -fu vnc-auto.service
日志中应出现类似以下片段:
vnc-auto.service: Control process exited, code=exited, status=3/NOTIMPLEMENTED
vnc-auto.service: Failed with result 'exit-code'.
vnc-auto.service: Scheduled restart job, restart counter is at 5.
Starting vnc-auto.service - X11 VNC remote desktop daemon...
看到 Scheduled restart job 即说明服务已按策略自动恢复。
关于 Type 的选择
Systemd 的 Type 决定如何判定服务"已启动":
simple:服务进程本身即为主进程,不派生子进程,Systemd 直接认为启动完成。多数后台服务使用该类型即可。forking:启动时会派生子进程并退出父进程,需要配合PIDFile等参数,否则容易出现状态误判。oneshot:执行一次任务后立即退出,常用于初始化脚本。dbus/notify:分别通过 D-Bus 信号或sd_notify告知 Systemd 启动完成,适用于需要精确报告状态的服务。
对于 x11vnc 这种跟随图形会话运行的服务,simple 加上 Restart=always 是最稳妥的方案。