I've been using a *nix VNC server and client since about 2004. Within the last several years, however, I am increasingly running into applications that demand support for GLX. On Ubuntu, GLX works out of the box if you're sitting at a physical terminal connected to your Linux machine, but if you're using a headless server or some other virtual X-windows environment, you might see something like this:
Xlib: extension "GLX" missing on display ":1"
One solution for this problem is to run TurboVNC and VirtualGL to create your VNC server. That's what I address here. If you're trying to use something like VirtualBox on Windows to create a virtual Ubuntu, that's out of my realm of experience.
First, make sure that you have installed your graphic card manufacturer's proprietary drivers. Ubuntu ships with all non-proprietary software, and the manufacturers are always ahead of the open source fast followers. So the default drivers are always less capable.
Second, I'm not entirely satisfied with the results I achieved. For example, the TurboVNC server hangs eventually (see "Why TurboVNC Hangs" below). Also google-chrome won't start properly in a VNC client. Nor can I run steam games in a VNC client. In addition, I have been unable to get the environment to start up properly as a systemd service. It seems to rely on something in my environment, and only works if I let the system come all the way up, log in and start the VNC server manually. But it was an adventure in frustration to get it working at all, so I want to share. If somebody has insight into these problems, please let me know!
Third, I offer no guarantees that any of this will work for you.
Go to TurboVNC sourceforge
Select "Files" tab Open lastest folder (I used 2.2.2) Download Turbovnc_2.2.2_amd64.deb Move turbovnc_2.2.2_amd64.deb to, for example, ~/tools/turbovnc
cd ~/tools/turbovnc sudo apt install ./turbovnc_2.2.2_amd64.deb
To see the installed files, you could use:
dpkg-query -L turbovnc
Binary is here: /opt/TurboVNC/bin/vncserver
All other VNC servers I've encountered use the server startup file ~/.vnc/xstartup.
TurboVNC leaves ~/.vnc/xstartup alone and uses ~/.vnc/xstartup.turbovnc. The first time you run it, it will create a default ~/.vnc/xstartup.turbovnc. So run it one time and let it do so.
/opt/TurboVNC/bin/vncserver
According to the TurboVNC docs, that is all that you should have to do, but in my experience, I ended up with a black screen. If you set your DISPLAY appropriately, you can use it like that, but it sure is ugly and kludgy.
So kill off the VNC server, and let's fix it.
/opt/TurboVNC/bin/vncserver -kill :[DISPLAY]
where [DISPLAY] should be 1 since we let it default.
By default, VNC servers listen on TCP ports 5900-5902 and will create a DISPLAY like :1, :2, ... Personally, I use a custom DISPLAY and VNC connection port. You might put something like this in your .bash_aliases:
vnc() { vncserver :50000 -alwaysshared -geometry 2400x1350 -depth 24 ; }
In this case, your DISPLAY is 50000, and you connect the VNC client on TCP port 55900.
The default window manager for Ubuntu 16.04 is Unity, a 3D window manager. I like a 2D window manager, plus this has the advantage of actually working instead of presenting a black workspace.
Edit ~/.vnc/xstartup.turbovnc, and add the "export TVNC_WM" line near the top:
#!/bin/sh
unset SESSION_MANAGER
unset DBUS_SESSION_BUS_ADDRESS
XDG_SESSION_TYPE=x11; export XDG_SESSION_TYPE
# Do NOT use 3D unity on Ubuntu 16.10
export TVNC_WM=2d
Restart TurboVNC, and you should get a nice desktop with a background, pulldown menus, etc. In addition, TurboVNC implements GLX support in software, so you should not be getting GLX errors any more. To test it out, try running "glxgears". It should work.
However, you still need VirtualGL to take advantage of your Linux machine's GPU and speed up the display.
For details, see Using TurboVNC with VirtualGL documentation page
Go to VirtualGL home page
Click on Official Binaries and Source Tarballs
In sourceforge, click on "2.6.2" (dated 2019-05-22)
Download virtualgl_2.6.2_amd64.deb
Put it somewhere, like ~/tools/virtualgl/virtualgl_2.6.2_amd64.deb
cd ~/tools/virtualgl
sudo dpkg -i virtualgl*.deb
Files are in /opt/VirtualGL
Follow this procedure. Details:
-
Log in remotely (e.g. using PuTTY from Windows) because as soon as you shut down the display manager (which is the next step), the physical display goes away.
-
sudo service lightdm stop
-
Switch to root: "sudo su - root"
-
Run /opt/VirtualGL/bin/vglserver_config
-
Select option 1 (configure server)
-
Restrict 3D X server access to vglusers group? Y
-
Restrict framebuffer device access to vglusers group? Y
-
Disable XTEST extension? N
-
Exit config tool
-
Edit /etc/group (e.g. sudo emacs /etc/group)
Add [user] and root to group vglusers, where [user] is your username
If your username is aswearengen, it should look like this:vglusers:x:1001:aswearengen,root
-
Restart the display manager
sudo service lightdm start -
At this point, I rebooted the machine
-
Do the 6.2.1 sanity check
-
Do the 6.4 SSH Server Configuration
Edit ~/.vnc/xstartup.turbovnc again, and add the "export TVNC_VGL" line:
#!/bin/sh unset SESSION_MANAGER unset DBUS_SESSION_BUS_ADDRESS XDG_SESSION_TYPE=x11; export XDG_SESSION_TYPE # Do NOT use 3D unity on Ubuntu 16.10 export TVNC_WM=2d # Start the window manager under VGL so that we always get acceleration export TVNC_VGL=1
Kill off TurboVNC and restart it. Run glxgears again. It should still work. In my case, I noticed a marked difference in speed when I maximized the glxgears dispaly window. It was much faster with VirtualGL enabled.
After setting this up, whenever I started any application in the VNC client environment, I would get an error:
[1002] jaguar: xterm & [1003] jaguar: ERROR: ld.so: object 'libdlfaker.so' from LD_PRELOAD cannot be preloaded (cannot open shared object file): ignored. ERROR: ld.so: object 'libvglfaker.so' from LD_PRELOAD cannot be preloaded (cannot open shared object file): ignored.
This is caused by the way the program /opt/VirtualGL/bin/vglrun sets up LD_PRELOAD. Reading the docs on LD_PRELOAD, I frankly do not understand why it doesn't work as coded in vglrun, but it doesn't for me. The fix (or kludge, if you like) is to edit /opt/VirtualGL/bin/vglrun and change this line:
export LD_PRELOAD=libdlfaker.so:libvglfaker.so
to this:
export LD_PRELOAD=/usr/lib/libdlfaker.so:/usr/lib/libvglfaker.so
Prior to installing TurboVNC, I was using TightVNC. The installation procedure for TightVNC had set up system symbolic links. I had to manually reconfigure them for TurboVNC. This is optional. But here's what I did.
[1014] jaguar: ls -l /etc/alternatives [snip] lrwxrwxrwx 1 root root 24 Dec 1 2016 vncconnect -> /usr/bin/tightvncconnect* lrwxrwxrwx 1 root root 40 Dec 1 2016 vncconnect.1.gz -> /usr/share/man/man1/tightvncconnect.1.gz lrwxrwxrwx 1 root root 23 Dec 1 2016 vncpasswd -> /usr/bin/tightvncpasswd* lrwxrwxrwx 1 root root 39 Dec 1 2016 vncpasswd.1.gz -> /usr/share/man/man1/tightvncpasswd.1.gz lrwxrwxrwx 1 root root 23 Dec 1 2016 vncserver -> /usr/bin/tightvncserver* lrwxrwxrwx 1 root root 39 Dec 1 2016 vncserver.1.gz -> /usr/share/man/man1/tightvncserver.1.gz [snip] lrwxrwxrwx 1 root root 18 Dec 1 2016 Xvnc -> /usr/bin/Xtightvnc* lrwxrwxrwx 1 root root 34 Dec 1 2016 Xvnc.1.gz -> /usr/share/man/man1/Xtightvnc.1.gz [snip] And [1005] jaguar: ls -l /usr/share/man/man1/vnc* lrwxrwxrwx 1 root root 33 Dec 1 2016 /usr/share/man/man1/vncconnect.1.gz -> /etc/alternatives/vncconnect.1.gz lrwxrwxrwx 1 root root 32 Dec 1 2016 /usr/share/man/man1/vncpasswd.1.gz -> /etc/alternatives/vncpasswd.1.gz lrwxrwxrwx 1 root root 32 Dec 1 2016 /usr/share/man/man1/vncserver.1.gz -> /etc/alternatives/vncserver.1.gz [1006] jaguar: ls -l /usr/share/man/man1/Xvnc lrwxrwxrwx 1 root root 27 Dec 1 2016 /usr/share/man/man1/Xvnc -> /etc/alternatives/Xvnc.1.gz
The equivalents for TurboVNC are:
[1002] jaguar: ls /opt/TurboVNC/bin checkshmpixmaps* vncconnect* vncpasswd* vncserver* vncviewer* Xvnc* [1004] jaguar: ls /opt/TurboVNC/man/man1 vncconnect.1 vncpasswd.1 vncserver.1 vncviewer.1 Xserver.1 Xvnc.1
cd /etc/alternatives sudo rm vncconnect sudo rm vncconnect.1.gz sudo rm vncpasswd sudo rm vncpasswd.1.gz sudo rm vncserver sudo rm vncserver.1.gz sudo rm Xvnc sudo rm Xvnc.1.gz sudo ln -s /opt/TurboVNC/bin/vncconnect sudo ln -s /opt/TurboVNC/man/man1/vncconnect.1 sudo ln -s /opt/TurboVNC/bin/vncpasswd sudo ln -s /opt/TurboVNC/man/man1/vncpasswd.1 sudo ln -s /opt/TurboVNC/bin/vncserver sudo ln -s /opt/TurboVNC/man/man1/vncserver.1 sudo ln -s /opt/TurboVNC/bin/Xvnc sudo ln -s /opt/TurboVNC/man/man1/Xvnc.1 cd /usr/share/man/man1 sudo rm vncconnect.1.gz sudo rm vncpasswd.1.gz sudo rm vncserver.1.gz sudo rm Xvnc.1.gz sudo ln -s /opt/TurboVNC/man/man1/vncconnect.1 sudo ln -s /opt/TurboVNC/man/man1/vncpasswd.1 sudo ln -s /opt/TurboVNC/man/man1/vncserver.1 sudo ln -s /opt/TurboVNC/man/man1/Xvnc.1
As mentioned above, this does not work correctly for me. It seems to come down to starting the VNC server via /sbin/runuser. In that environment, the system cannot start all of the pieces of the environment, e.g. the window manager. Still, it's partially working, so here's what I know.
Create a file /etc/systemd/system/vncserver@[NUM].service, where [NUM] is the DISPLAY you'll be creating. For example, if the command that you want to run looks like this:
vncserver :50000 -alwaysshared -geometry 2400x1350 -depth 24
The file you create will be
/etc/systemd/system/vncserver@50000.service
The contents of the file should be like the following, with "aswearengen" replaced by your user name.
#-------------------------------------------------------------------------------
# The vncserver service unit file
#
# Quick HowTo:
# 1. Copy this file to /etc/systemd/system/vncserver@:.service
# 2. Edit and vncserver parameters appropriately
# ("runuser -l -c /usr/bin/vncserver %i -arg1 -arg2")
# 3. Run `systemctl daemon-reload`
# 4. Run `systemctl enable vncserver@:.service`
#
# DO NOT RUN THIS SERVICE if your local area network is
# untrusted! For a secure way of using VNC, you should
# limit connections to the local host and then tunnel from
# the machine you want to view VNC on (host A) to the machine
# whose VNC output you want to view (host B)
#
# [user@hostA ~]$ ssh -v -C -L 590N:localhost:590M hostB
#
# this will open a connection on port 590N of your hostA to hostB's port 590M
# (in fact, it ssh-connects to hostB and then connects to localhost (on hostB).
# See the ssh man page for details on port forwarding)
#
# You can then point a VNC client on hostA at vncdisplay N of localhost and with
# the help of ssh, you end up seeing what hostB makes available on port 590M
#
# Use "-nolisten tcp" to prevent X connections to your VNC server via TCP.
#
# Use "-localhost" to prevent remote VNC clients connecting except when
# doing so through a secure tunnel. See the "-via" option in the
# `man vncviewer' manual page.
[Unit]
Description=Remote desktop service (VNC)
After=syslog.target network.target
[Service]
Type=simple
# Clean any existing files in /tmp/.X11-unix environment
ExecStartPre=/bin/sh -c '/usr/bin/vncserver -kill :%i > /dev/null 2>&1 || :'
ExecStart=/sbin/runuser -l aswearengen -c "/usr/bin/vncserver :%i -alwaysshared -geometry 2400x1350 -depth 24"
#ExecStop=/sbin/runuser -l aswearengen -c "/usr/bin/vncserver -kill :%i"
[Install]
WantedBy=multi-user.target
#-------------------------------------------------------------------------------
Note: do not uncomment-out the "ExecStop" line. There is a bug in Ubuntu 16.04 such that, if you leave this line in the file, the VNC server will start up and be immediately stopped.
Then enable the service:
sudo systemctl enable vncserver@50000.service sudo systemctl start vncserver@50000.service
For whatever reason, on my setup, the VNC server periodically disconnects from the VNC client. When this happens, the server leaves its TCP socket open. Eventually all of the server's FDs get used up (I assume it has a static max number of them). At this point, the VNC server refuses to accept any new connections. You can see the open FDs using "lsof".
[1009] jaguar: lsof -i COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME vino-serv 2453 vsperry 13u IPv6 30785 0t0 TCP *:5900 (LISTEN) vino-serv 2453 vsperry 14u IPv4 30786 0t0 TCP *:5900 (LISTEN) Xvnc 3344 vsperry 5u IPv4 33686 0t0 TCP *:55900 (LISTEN) Xvnc 3344 vsperry 6u IPv4 33687 0t0 TCP *:55800 (LISTEN) Xvnc 3344 vsperry 20u IPv4 154586 0t0 TCP 192.168.0.90:55900->coronado:52424 (ESTABLISHED) Xvnc 3344 vsperry 27u IPv4 184533 0t0 TCP 192.168.0.90:55900->coronado:56361 (ESTABLISHED) Xvnc 3344 vsperry 28u IPv4 227719 0t0 TCP 192.168.0.90:55900->coronado:63215 (ESTABLISHED) Xvnc 3344 vsperry 29u IPv4 246442 0t0 TCP 192.168.0.90:55900->coronado:50628 (ESTABLISHED) Xvnc 3344 vsperry 30u IPv4 271044 0t0 TCP 192.168.0.90:55900->coronado:54404 (ESTABLISHED) Xvnc 3344 vsperry 31u IPv4 298538 0t0 TCP 192.168.0.90:55900->coronado:58175 (ESTABLISHED) Xvnc 3344 vsperry 32u IPv4 324223 0t0 TCP 192.168.0.90:55900->coronado:61956 (ESTABLISHED) Xvnc 3344 vsperry 33u IPv4 415201 0t0 TCP 192.168.0.90:55900->coronado:56854 (ESTABLISHED) Xvnc 3344 vsperry 34u IPv4 382695 0t0 TCP 192.168.0.90:55900->coronado:53079 (ESTABLISHED) Xvnc 3344 vsperry 35u IPv4 436910 0t0 TCP 192.168.0.90:55900->coronado:60611 (ESTABLISHED) Xvnc 3344 vsperry 36u IPv4 459820 0t0 TCP 192.168.0.90:55900->coronado:64348 (ESTABLISHED) Xvnc 3344 vsperry 37u IPv4 481632 0t0 TCP 192.168.0.90:55900->coronado:51766 (ESTABLISHED) Xvnc 3344 vsperry 38u IPv4 490868 0t0 TCP 192.168.0.90:55900->coronado:55551 (ESTABLISHED) vino-serv 3623 vsperry 13u IPv6 36327 0t0 TCP *:5901 (LISTEN) vino-serv 3623 vsperry 14u IPv4 36328 0t0 TCP *:5901 (LISTEN)
To fix this situation, you can follow the advice here
... and use GDB to manually close the abandoned connections.
[1014] jaguar: sudo gdb -p 3344
GNU gdb (Ubuntu 7.11.1-0ubuntu1~16.5) 7.11.1
Copyright (C) 2016 Free Software Foundation, Inc.
[snip]
(gdb) p close(20)
$1 = 0
(gdb) p close(27)
$2 = 0
...
(gdb) p close(38)
$13 = 0
(gdb) quit
A debugging session is active.
Inferior 1 [process 3344] will be detached.
Quit anyway? (y or n) y
Detaching from program: /opt/TurboVNC/bin/Xvnc, process 3344
[1001] jaguar: lsof -i
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
vino-serv 2453 vsperry 13u IPv6 30785 0t0 TCP *:5900 (LISTEN)
vino-serv 2453 vsperry 14u IPv4 30786 0t0 TCP *:5900 (LISTEN)
Xvnc 3344 vsperry 5u IPv4 33686 0t0 TCP *:55900 (LISTEN)
Xvnc 3344 vsperry 6u IPv4 33687 0t0 TCP *:55800 (LISTEN)
vino-serv 3623 vsperry 13u IPv6 36327 0t0 TCP *:5901 (LISTEN)
vino-serv 3623 vsperry 14u IPv4 36328 0t0 TCP *:5901 (LISTEN)
This is likely specific to my local network, but this is why.
Background: I had Windows configured to use DHCP to get an IP address from my router. I had my router configured to serve up a static IP address based on the Windows machine’s MAC address. This would have allowed the DNS addresses to change, even though my Windows machine always had the same IP address. The latter is important in case I want to temporarily open port forwarding to the Windows machine in the router.
Details: Wireshark showed that Windows lost its mind every hour, flooding the local Ethernet with DHCP requests (one message every few hundred microseconds -- that is not right), and refusing to respond to the router’s ARPs, probably because it had already un-configured it’s IP address on the interface. After 30 seconds or a minute, it recovers, but in so doing, it re-applies its IP address to the interface, and this causes PuTTY and VNC client to drop their connections. The PuTTY session has to be manually restarted. The VNC client re-negotiates and recovers, but the TurboVNC server can leave open many stale sockets, eventually using up its available pool, whereupon it becomes unresponsive. I have also seen the TurboVNC server automatically recover from this unresponsive state (by cleaning up its stale sockets), but it takes time.
Nice, works for me, thanks for sharing!