X11 VNC On demand
I have the peculiarity that I dislike laptops. While they are great for on the go, I still prefer a standard desktop tower machine for my regular work. However, as I’m traveling to my girlfriend each weekend, I won’t be able to work behind my tower. Next, being the chaotic person I am, I actually tend to forget to move files or sometimes I need functionality only available on my own machine. So I was investigating the most convenient way of reaching my machine remotely.
x11vnc
I’ve already worked with x11vnc in the past. Mostly to assist people remotely without requiring a closed-source propriety piece of software like TeamViewer. It works great and would help get into my desktop. I was already aware of security implications (VNC not being encrypted) so generally I was doing:
ssh dsonck@desktop -L5900:localhost:5900
x11vnc -localhost -nopwAnd next VNC’ing in
vncviewer localhost:5900This works, but still requires me to type in x11vnc.
systemd
While there is a lot of debate whether systemd is a good or bad thing. However, I personally appreciate all its features it provides. While I understand separation of concerns and realize that exploding systemd back into init, inetd, cron might improve stability, I don’t really experience that much issues from this complexity.
I recently learned about user services, so I thought of having that as basis to autostart x11vnc:
# /etc/systemd/user/xvnc.service
[Unit]
Description=XVNC Daemon
[Service]
ExecStart=/usr/bin/x11vnc -display :0 -bg -forever -shared
[Install]
WantedBy=multi-user.targetNext enabling it:
systemctl --user enable xvnc
systemctl --user start xvncThis will remove the need to launch x11vnc .... But, it’s not ideal. Because now x11vnc will always run in the background.
systemd.socket
systemd again to the rescue (together with a feature from x11vnc). In the olden days, people used inetd or xinetd. It would allow one daemon which accepts connections and then spawn the respective program to handle the actual protocol. x11vnc supports that with its -inetd flag. Before starting (x)inetd, systemd already supports sockets on its own. So, by creating a new config file and slightly tweaking the existing one, we can turn it into an on-demand service:
# /etc/systemd/user/xvnc.socket
[Unit]
Description=XVNC Server
[Socket]
ListenStream=5900
Accept=yes
[Install]
WantedBy=sockets.targetNext we should rename xvnc.service to xvnc@.service as required by socket activation, and edit it:
# /etc/systemd/user/xvnc@.socket
[Unit]
Description=XVNC Per-Connection Daemon
[Service]
ExecStart=/usr/bin/x11vnc -display :0 -bg -forever -shared -inetd
StandardInput=socket
StandardError=syslogNow, systemd will automatically spawn x11vnc when necessary, and bind the socket to its standard input and output. However, localhost may be used by anyone with access on this host. Now, for me this isn’t an issue as I’m the sole user, but as I like to reuse my stuff sometimes, I want to be on the safe side. Thankfully this is very easy.
Unix sockets and SSH
Many might not realize it (I didn’t) but since OpenSSH 6.7, SSH can forward unix domain sockets. This can even translate between regular TCP sockets. So it’s possible to forward local port 5900 to a remote unix-socket! So with a small adaptation:
# /etc/systemd/user/xvnc@.socket
[Unit]
Description=XVNC Server
[Socket]
ListenStream=%h/.xvnc
Accept=yes
[Install]
WantedBy=sockets.targetThis will create a /home/dsonck/.xvnc socket (based on the username). This actually gives a few benefits:
- Access of
.xvnccan be limited to the owning user (only allow me to connect to my desktop - Multiple users each have their own private
.xvncfile whereas the old solution hardcoded5900as port
It does require a slight adaption of the ssh command:
ssh dsonck@desktop -L5900:/home/dsonck/.xvncWhich, to me, even looks cleaner: I want port 5900 to forward xvnc.
Conclusion
So, with the addition of two systemd configuration files in /etc/systemd/user, it’s possible to have x11vnc automatically launch when necessary. Together with unix domain sockets it’s possible to add permissions to this socket to limit others from interfering. And OpenSSH allows us to connect our local vncviewer via a port to this remote unix domain socket.