«

»

Nov 16

Using Xvfb to Hide those Pesky Windows

XvfbDo you have a script that opens up all sorts of windows? Maybe a scraping/posting script that opens up a Firefox session or some other window that you really don’t care to watch or clutter your desktop? As an example, I run a series of selenium scripts (I’ll have a tutorial on this later) that I run on a headless Linux server. Since I don’t have a normal window manager on my server, nor a physical display, I need to use something that will “simulate” a frame buffer so Firefox can still be “drawn” to the screen. This is where Xvfb fits in.

So, what the heck is Xvfb?

Ah! I knew you’d ask! Xvfb stands for X Virtual Frame Buffer. It essentially acts as an X11 server that performs all graphical operations directly in memory without the need for a physical display. Here’s a link to the wiki entry about it that describes it in more detail if you so need it: Xvfb on Wikipedia. Xvfb is pretty powerful utility that can be used for all sorts of neat things. In this tutorial I’ll show you how to use it to run scripts that open physical windows on headless machines, in our case, Firefox!

Let’s get to it!

First thing’s first, if you’re running Ubuntu you can install Xvfb simply with:
sudo apt-get install xvfb xfonts-100dpi xfonts-75dpi xfonts-scalable xfonts-cyrillic

Installing the xfonts are optional and shouldn’t impact our scripts negatively. Though, if you choose not to install them, there’s a good chance you’ll get annoying warning messages like this:

[dix] Could not init font path element /usr/share/fonts/X11/cyrillic, removing from list!
[dix] Could not init font path element /usr/share/fonts/X11/100dpi/:unscaled, removing from list!
[dix] Could not init font path element /usr/share/fonts/X11/75dpi/:unscaled, removing from list!
[dix] Could not init font path element /usr/share/fonts/X11/100dpi, removing from list!
[dix] Could not init font path element /usr/share/fonts/X11/75dpi, removing from list!

If this output doesn’t bother you every time you run a new Xvfb session, it’s a couple less packages you need to install. No harm, no foul. As a side note, those error messages drove me borderline insane… You’re welcome…

Simple Example!

Now that we have Xvfb installed, I’ll show you a simple bash script that I use to automate a few web tasks for one of my clients:

#!/bin/bash

echo "Configuring screen parameters..."

#- Start an X Virtual Frame Buffer on screen 1, send any output to /dev/null
Xvfb :1 -screen 1 1024x768x24 2>&1 >/dev/null &

#- Get Xvfb PID, so we can kill it later
XVFB=$!

#- Export our display for this particular session to what we defined in the above command
export DISPLAY=:1

#- Give a couple seconds for things to warm up
sleep 2

#############################
#- Start Code
#############################
echo "Starting Selenium Server..."

#- Selenium opens up Firefox, and uses the browser to automate web tasks...
xterm -hold -e "java -jar ../software/selenium-server/selenium-server-2.4.0.jar -firefoxProfileTemplate '../software/selenium-server/firefox-profile/'" &

#- Get Selnium server PID, so we can kill it later
SELENIUM=$!

#- Allow our selenium server to startup, give it some time
sleep 10

#- Run our selenium scripts for each site/page we want to automate
perl start.pl 2>&1 | tee -a logs/log_`date +"%m-%d-%Y"` 
perl site1.pl 2>&1 | tee -a logs/log_`date +"%m-%d-%Y"`
perl site2.pl 2>&1 | tee -a logs/log_`date +"%m-%d-%Y"`
perl site3.pl 2>&1 | tee -a logs/log_`date +"%m-%d-%Y"`
perl site4.pl 2>&1 | tee -a logs/log_`date +"%m-%d-%Y"`
perl cleanup.pl 2>&1 | tee -a logs/log_`date +"%m-%d-%Y"`

echo "Shutting down Selenium/Xvfb Server in 5 Seconds..."
sleep 5
kill -9 $SELENIUM
#############################
#End code
#############################

kill -9 $XVFB

Now, I can run this on my headless server in a CRON job and not have to worry about dealing with a window manager. So simple even a n00b can do it.

2 comments

  1. Eric

    This is pretty cool man, not sure where I’d have the chance to use it but more knowledge of more tools is always better.

    Once you start Firefox inside of the XVFB instance is there any way to view the gui of the running app? Or is that directly counter-intuitive to the goal? I’m thinking about it more like the program “screen” where you have a program running in the background that you can view and jump out of, at will. Also how can you tell Firefox to instantiate to the XVFB instance instead of an existing X-session if you’re also running a desktop environment of some kind?

    1. Ron DeMara

      Yeah, it’s pretty simple, though I wouldn’t recommend it because not all windows will render properly. You’ll get weird looking windows and icons and shapes. I think there are a few more packages you can install to remedy this, but I haven’t checked because I don’t use it for that.

      First download the package x11vnc, and setup a vnc server to to run on the display that you set up Xvfb on. In our example case:

      x11vnc -display :1

      You’ll see output like this:
      ******************
      The VNC desktop is: vm-mint-demara:0
      PORT=5900
      ******************

      You’ll see that x11vnc will start up and allow the desktop to be viewable via vm-mint-demara:0, you can now use vncviewer, or some other vnc client to connect to it:

      vncviewer vm-mint-demara:0

      As for your second question, you can do one of two things. By using the export DISPLAY command, you essentially force all programs you start in the current terminal to use that display to render on:

      export DISPLAY=:1

      This will force programs to run on X session :1, which is where Xvfb sits. You can also force a different display by using the command line argument –display=:

      firefox –display=:1 ##Forces firefox onto display :1
      gedit –display=:2 ##Forces gedit onto display:2

      Both of these methods will work on a desktop environment.

Leave a Reply

Your email address will not be published. Required fields are marked *


*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>