Published on Jul 13 2012 in Dedicated Server Java VPS

Java GUI can easily be used on a headless server via Xvnc or Xvfb and x11vnc. Read on.

By default there is no graphical display device support on VPSes. We inform JVM about it with -Djava.awt.headless=true in $JAVA_OPTS environment variable or in Java command line. Generating text-only output from a Java server or application is faster and uses less resources so it is preferred in general. If your code just requires graphical buffer then usual approach is to install Xvfb server (frame buffer emulator) then export DISPLAY=:0 and append -Djava.awt.headless=false to $JAVA_OPTS.

You may later run x11vnc and connect it with Xvfb this way allowing for remote connection to the display with VNC protocol. You may also choose to replace Xvfb/x11vnc tandem with Xvnc (frame buffer + VNC server in one). We will present the Xvnc method below.

Let's have a simple GUI java code built (-Djava.awt.headless=false is already included in $JAVA_OPTS environment variable - you can also provide the switch in command line if you wish). Put the below dialog code in GUITest.java file, compile and execute it.

cat >GUITest.java<<EOF
    import javax.swing.JOptionPane; 
    public class GUITest {
     public static void main(String[] args) {
     JOptionPane.showMessageDialog(null, "Click OK to close the application");
     System.exit(0); 
     } 
    }
    EOF
javac GUITest.java 
java GUITest
    Exception in thread "main" java.awt.HeadlessException: 
    No X11 DISPLAY variable was set, but this program performed an operation which requires it.
     at java.awt.GraphicsEnvironment.checkHeadless(GraphicsEnvironment.java:159)
     at java.awt.Window.(Window.java:431)
     at java.awt.Frame.(Frame.java:403)
     at java.awt.Frame.(Frame.java:368)
     at javax.swing.JFrame.(JFrame.java:158)
     at GUITest.(GUITest.java:6)
     at GUITest.main(GUITest.java:12)

We are on a VPS so can arbitrarily set our display number. Let it be 0. It is denoted as displaynumber:screennumber. We will omit displaynumber leaving it with default value of 0 and by display we will refer to value of DISPLAY variable.

export DISPLAY=:0
java GUITest
    Exception in thread "main" java.lang.UnsatisfiedLinkError: /opt/jdk1.6.0_33/jre/lib/amd64/xawt/libmawt.so: libXext.so.6: cannot open shared object file: No such file or directory
     at java.lang.ClassLoader$NativeLibrary.load(Native Method)
     at java.lang.ClassLoader.loadLibrary0(ClassLoader.java:1807)
     at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1703)
     at java.lang.Runtime.load0(Runtime.java:770)
     at java.lang.System.load(System.java:1003)
     at java.lang.ClassLoader$NativeLibrary.load(Native Method)
     at java.lang.ClassLoader.loadLibrary0(ClassLoader.java:1807)
     at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1724)
     at java.lang.Runtime.loadLibrary0(Runtime.java:823)
     at java.lang.System.loadLibrary(System.java:1028)
     at sun.security.action.LoadLibraryAction.run(LoadLibraryAction.java:50)
     at java.security.AccessController.doPrivileged(Native Method)
     at sun.awt.NativeLibLoader.loadLibraries(NativeLibLoader.java:38)
     at sun.awt.DebugHelper.(DebugHelper.java:29)
     at java.awt.Component.(Component.java:566)
    Could not find the main class: GUITest. Program will exit.

The problem here is missing libXext library (and a few more libraries) that we install with dependencies using yum install libXext libXtst libXi twm. TWM is a lightweight window manager that will provide frame and control buttons to our window. When running the program now we will see:

java GUITest
    Exception in thread "main" java.lang.InternalError: Can't connect to X11 window server using ':0' as the value of the DISPLAY variable.
     at sun.awt.X11GraphicsEnvironment.initDisplay(Native Method)
     at sun.awt.X11GraphicsEnvironment.access$100(X11GraphicsEnvironment.java:52)
     at sun.awt.X11GraphicsEnvironment$1.run(X11GraphicsEnvironment.java:155)
     at java.security.AccessController.doPrivileged(Native Method)
     at sun.awt.X11GraphicsEnvironment.(X11GraphicsEnvironment.java:131)
     at java.lang.Class.forName0(Native Method)
     at java.lang.Class.forName(Class.java:169)
     at java.awt.GraphicsEnvironment.getLocalGraphicsEnvironment(GraphicsEnvironment.java:68)
     at java.awt.Window.init(Window.java:379)
     at java.awt.Window.(Window.java:432)
     at java.awt.Frame.(Frame.java:403)
     at java.awt.Frame.(Frame.java:368)
     at javax.swing.JFrame.(JFrame.java:158)
     at GUITest.(GUITest.java:6)
     at GUITest.main(GUITest.java:12)

We instructed our JVM to connect to display 0 but there is no X server servicing the display. Let's install Xvnc. We STRONGLY recommend to have your Java running as regular (non-root) user. In this example we use root account for simplicity.

yum install vnc-server
echo -e "VNCSERVERS=\"1:root\"\nVNCSERVERARGS[1]=\"-geometry 800x600\"" >> /etc/sysconfig/vncservers
vncpasswd
/etc/init.d/vncserver start
    
    Starting VNC server: 0:root 
    xauth: creating new authority file /root/.Xauthority
    New 'guitest:0 (root)' desktop is guitest:0
    Creating default startup script /root/.vnc/xstartup
    Starting applications specified in /root/.vnc/xstartup
    Log file is /root/.vnc/guitest:0.log

We can now run our program and it should connect to the display without issues. Connect with a VNC client to your VPS to see the created dialog for example

[user@remotehost ~]#vncviewer 10.10.10.10:0

You should see below dialog and the application will exit afer your click the button.

Xvnc java test dialog
In case you want to try Xvfb + x11vnc method on Centos 5 the quick guide follows. You can download and install x11vnc for CentOS 5 from https://pkgs.org/download/x11vnc/.

yum install Xvfb libXdamage libXfixes libXinerama libXrandr avahi libjpeg xorg-x11-utils xorg-x11-server-Xorg libXext libXtst libXi twm
adduser xvfb; chsh -s /bin/false xvfb; touch /var/log/Xvfb.log; chown xvfb /var/log/Xvfb.log
export DISPLAY=:0
/usr/bin/Xvfb :0 -screen 0 800x600x24 >> /tmp/Xvfb.out 2>&1 &
twm >> /tmp/Xvfb.out 2>&1 &
java GUITest &
rpm -ivh x11vnc-0.9.13-1.el5.rf.x86_64.rpm
x11vnc --nopw

Now connect with a VNC viewer just like in the previous example.