Creating a kiosk with Linux and X11: 2011 edition

Back around 2006 our public library was in need of a cheap way for patrons to browse its web-based INNOPAC catalog. Thin clients running Windows CE had been purchased for this purpose, but they turned out to be buggy and limited. I was tasked with finding a solution to the problem “on the cheap”, and being a fairly new Linux fanatic at the time, I figured I’d see what I could do using free software. This led to my first kiosk project.

Since then, I’ve refined my approach time and again, deploying kiosks throughout my organization just about anywhere a web-browser kiosk can be put to use. The original library system has been completely rebuilt with newer hardware and software, but is fundamentally the same system I set up five years ago.

I often see people asking about how to set up a kiosk system with Linux, and like me they usually start out going about it the wrong way; so I thought I’d write this tutorial based on my years of experience to help those getting started.

Theory

Most people start working on a kiosk with the idea of taking some standard Linux desktop (like Unity or KDE) and trying to “lock it down” so users can only run a browser. I tried this too, originally (at the time, KDE 3 had a kiosk tool that let you set policies for all its 18 bajillion components); but I quickly found that locking down a fully-featured desktop environment was a pedantic, exhausting task that never ended satisfactorily. It occurred to me that I might have more luck building an environment from scratch with only the components required.

That isn’t nearly as hard as you’d think. To understand how it works, let’s look at how a typical X11 desktop system functions:

When you boot the system, it launches your X11 server (xorg) and the display manager, which is what gives you your graphical login screen.

In addition to letting you log in, the display manager also lets you choose a session (such as Gnome, openbox, XFCE, etc depending on what’s installed). Each session is just a script or program that can run in X11.

When you log in, the display manager run the session script/program under your account. The session script launches the programs that comprise your desktop and provides you with everything you see.

When you log out, your session script finishes execution and exits. Control of the display is returned to the display manager.

The key here is understanding that the session script (or program) is nothing magical. It’s just an executable that the display manager runs when you log in, and when it finishes you log out. In fact, there is a very simple mechanism to override the X session and create our own customized version. When a user logs in, if the ~/.xsession or ~/.xinitrc file is present and executable it will (usually, depending on the display manager) be executed instead of the default session.

Now, I’ve said that there’s nothing magical about the session script; but those who haven’t done much tinkering with X11 desktops might be surprised to find that many of the behaviors you take for granted on a graphical desktop don’t “just happen” — they require software to make them happen. For instance, you might assume that program windows are automatically movable about the screen, are re-sizable, or have title-bars across the top with (at least) maximize, minimize, and close buttons. None of this is provided by X11, though; it’s provided by a program called the window manager. You might also assume that graphical environments all have menus, desktop icons, or panels; again, these are provided by other programs which must be run either by the session script or one of the programs it starts.

Choosing the right components to launch in a session script can be subtly tricky depending on the software you need to run, the behavior you expect from it, and the need for tight security on the system. Fortunately, when it comes to desktop components the Linux world offers a lot of options, and with some persistence and a willingness to tinker you can nearly always get what you need. At the end, we’ll go through some “crash test” questions to see if your setup is really bullet-proof and ready for the road.

But first, let’s walk through setting up an actual kiosk.

Practice

In this tutorial, I’ll walk through how I set up a kiosk for use at my workplace, and why I choose the different components that I do.

Choose and install the OS

The first task is to get a basic OS install. You can do this with about any distribution of Linux you feel comfortable with, but I’d recommend taking the following aspects into consideration:

You want big repositories with a lot of selection. Since we’re going to be dealing with some less-than-ubiquitous software in constructing our custom environment, make sure you use a distro with a lot of these uncommon packages available.

Don’t use a rolling release or a distro that updates every few months. The idea is to put out a kiosk and not touch it for a few years if you don’t need to. Use something with a long release cycle, or a long-term support release.

Use a distribution that can be installed with a minimal command-line installation and built up from there.

Lightweight is good, since you might want to use this on old computers or thin clients.

Based on these criteria, I’ve found Debian Stable to be a prime choice over the years. Ubuntu can also work well if you stick to LTS releases and use the minimal install media. Centos might be a third choice, though it doesn’t have as much software readily available.

Once you’ve picked one, install a basic, command-line installation. The Debian installation manual can be found here.

Install the software

Once you have the basic install, we need to get a few software components on there:

Use aptitude on Debian to find and install these packages. Dependencies will, of course, be handled automatically. You might want to add the “–without-recommends” switch when installing gdm, so that you don’t pull in a lot of unnecessary GNOME packages. Also, if you prefer to do your administration parts in a GUI, you can of course install a minimal desktop like LXDE or just a simple window manager like jwm. Be aware that any other environment you install is going to show up on your login screen as a session option, so depending on the deployment situation that might be a problem.

We’re using Chromium here as an example kiosk application, though if you have a custom application or prefer a different web browser substitute that instead. I originally used Firefox for these, but unfortunately Firefox has become increasingly unsuited for kiosk work since version 2 (I actually ended up writing my own browser in python, but I’m assuming you’re not that deep into this yet).

I chose matchbox-window-manager here because it’s simple and stays out of the way. In the past, I’ve used flwm, ion, openbox, or xfwm. I ended up switching to matchbox because it does pretty much what you want on a kiosk without any configuration.

User Accounts:

If you’re logged in as root at this point, make sure you’ve made a second account for administration purposes — you really don’t want to be ssh’ing around as root, it’s bad practice. You also need to make the account which the kiosk will run under; I usually just call this “kiosk”, though feel free to call it whatever seems natural to you.

In Debian, the “adduser” command will step you through setting up a new user account. Try “adduser kiosk” and follow the prompts.

Configuring the session script

Time for the most important part: writing the session script. First, run these commands as root:

What these commands do is copy the kiosk user’s home directory to /opt, move there, make the directory world-readable, and then create an empty but executable .xinitrc file (see note at the end of the section about .xinitrc vs .xsession). You want /opt/kiosk to be readable by the kiosk user, but not writable.

This is our session script; it’s what will be run when the kiosk user is logged in, so let’s go through it one line at a time.

The “xset” lines take care of an important detail: disabling screen blanking and monitor power saving. You might not want this, but most users approaching a kiosk with a black screen tend to assume it’s out of order.

Next, we launch our window manager, matchbox-window-manager. Note the ampersand here: without it, matchbox would be run and nothing else would happen, because the script would be waiting on matchbox to end before running the next commands. You do need one part of the script to run indefinitely, because once the script ends the user is logged out; but you want only one part of the script to do this. The ampersand forks matchbox’s execution to the background and continues down the script.

The “while true; do” line starts an infinite loop, which is later closed by the “done” line. There’s really no way out of this script other than to kill the whole display or reboot the system, and that’s what we want.

The “rsync” command bears some explanation. Rsync is a special copy command that, by default, only copies files that are different between the source and destination. The switches and arguments do the following:

q makes the output quiet, so we don’t bother writing to a log file that is probably going to be overwritten anyway

r makes the copy recurse into subdirectories (without it, no directories will be copied)

delete means that any files in the destination that aren’t in the source will be deleted. This is will wipe out any files the last user may have downloaded or created, either inadvertently or maliciously.

exclude means it won’t touch the listed file. “.Xauthority” is a file created automatically by xorg, and overwriting or deleting it during a running session could potentially crash the session.

/opt/kiosk is our source for copying. The “/” on the end is important, don’t omit it!

$HOME is an environment variable that points to the logged-in user’s home directory. Being the last argument, it’s the destination for our copying. Again, the “/” on the end is critical to make sure things get copied to the right place.

Every time the rsync runs, the kiosk user will get a completely fresh home directory; this will reset anything a previous user might have tinkered with. Since it’s in an infinite loop with the actual kiosk application, resetting everything is as simple as closing the application.

Finally, we run our kiosk application. I’m using chromium-browser with the “–app” switch to put it in kiosk mode (replace the URL with one of your choosing). You can, of course, run any application here, but note that it’s critical the application not fork into the background when run. Some applications (OpenOffice, for one) fork when run, and return control to the command line. If your application does this, you’ll end up with a few hundred copies before the system runs out of memory and dies. You’ll have to work out how to “block” the session some other way if your application is like this.

Once this file is saved, copy it to /home/kiosk. Reboot the system, and log in to GDM as the kiosk user. Ta-dah! You should be looking at a full-screen chromium with whatever URL you specified.

NOTE: as one reader discovered, apparently newer versions of GDM in Ubuntudon’t recognize “~/.xinitrc”, but do recognize “~/.xsession”. If you’re having trouble with GDM recognizing your session script, rename it to “.xsession”.

The lockdown

Already this is a pretty secure setup that will keep the vast majority of people from doing anything destructive, but there are a few more things we might want to do depending on where you’re deploying the kiosk and what you think people might do (for space reasons, I can’t detail all these, but I’ll tell you where to find information):

Lock GRUB: By default, GRUB allows any user to edit boot options from the GRUB prompt, giving knowledgeable users a potential avenue to gain root access. Section 15 of the GRUB manual (type “info grub” at the console for the manual) describes how to password-protect boot options and editing.

Lock the BIOS: Most computers allow a BIOS password to be set for editing BIOS. You probably want to set this, and disable any sort of boot-device menu features. Of course, you also need to physically secure the cpu if you’re worried about people booting to other devices.

Remove sudo/su access: In the event that a user finds a way to get a terminal, you don’t want them being able to run su or sudo (even if they don’t know the password, they can spend a long time guessing on a public kiosk). Check out the files /etc/pam.d/su and /etc/pam.d/sudo on Debian, and read carefully to learn how to disable these commands for your public user. On Ubuntu, you might find apparmor to be useful here as well.

Be careful with the URL bar: It’s easy to forget that most web browsers, including chromium, can browse the filesystem just as well as they can browse the web. This can potentially allow a user to inspect system files or even run commands. In our example, the “–app” switch makes the URL bar inaccessible, but there may be ways around this. Make sure you check for things like this and take measures to limit access to the filesystem.

Disable TTYs: By default, most Linux systems will spawn six TTY terminals in addition to the X11 display, which can be accessed with the keys ctrl-alt-F1 through ctrl-alt-F6. You probably want to disable these for the same reason you want to disable su and sudo — no sense in giving someone the opportunity to try root passwords. In Debian, edit (as root) the /etc/inittab file and comment out these lines:

Prevent root login to GDM: Again, you don’t want to have people testing root passwords at the GDM login prompt. Edit /etc/gdm/gdm.conf and under the “[security]” section add “AllowRoot=False”.

Not all of these are strictly necessary, but as the voice of experience let me advise you not to underestimate the public’s ability to cause mischief on an unsecured computer!

Tweaks

At this point your system is workable and secure, but depending on the situation there are some optional features we might want to add.

GDM autologin

If you want the system to be a “turnkey” style system that doesn’t require login, configure GDM for auto-login. You just need to edit /etc/gdm/gdm.conf, and add the following under the “[daemon]” section:

[daemon]
AutomaticLoginEnable=true
AutomaticLogin=kiosk

Reset on Timeout

So your kiosk user is looking up information about an embarrassing rash, then gets a phone call and has to step away. You don’t want the next person walking up to see information about embarrassing rashes. You also want to protect your users by removing web history between users when possible.

In my own kiosks, I built a timer into the application to wipe the history and return to the home page after so many minutes of inactivity. With the chromium-browser kiosk, you don’t have that option. But you can get it with a little help from xautolock.

Xautolock is a utility that monitors the session for inactivity, and locks the screen after so many minutes. It doesn’t actually have to lock the screen, though; you can tell it to run any command you want after the inactivity period has timed out.

Looking at our session script, all we need to do to reset the whole thing is close chromium. So the solution is simple:

Create a script to kill chromium; probably it just needs to contain “pkill chromium-browser”. Save it to /usr/local/bin/kill_chromium.sh.

Install xautolock and add this line to your session script, beforethe loop starts:

xautolock -secure -time 15 -locker /usr/local/bin/kill_chromium.sh

This runs xautolock in secure mode (so it can’t be turned off), sets the inactivity timeout to 15 minutes, and runs your chromium-killing script when the timeout hits.

Auto update

Chances are, you don’t want to mess with keeping these systems up-to-date manually, and you certainly can’t expect users to launch an updater for you! So, this is the simple way to set up automatic updates on your Debian system (I wouldn’t recommend doing auto-updates on a distro that’s prone to major changes, or you might have a broken kiosk on your hands!).

First, install cron-apt from the repositories.

By default, cron-apt will update the package lists daily, but won’t upgrade the system. So:

Go to /etc/cron-apt/action.d

create a file called “9-dist-upgrade”

Put in it this line: “dist-upgrade -y -V -o Dpkg::Options::=–force-confold”

Save the file and exit.

If you have the capability to relay mail from your systems, you can configure cron-apt to email you when it upgrades or has a problem upgrading, but I’ll leave that for your homework.

Printing

If you want your users to be able to print, you’ll need to install cups. Mercifully, cups comes with its own web-based configuration utility, so if you’re a little tired of hacking config files, rejoice! After installing cups, point the web browser to “http://localhost:631” to configure printing.

Testing the system

Now that your system is set up, test it extensively. If possible, have some other people try to mess it up. Here is a list of some non-obvious things to try:

Window Manager

Does the WM offer keyboard shortcuts or a menu? Are you able to use them to launch other applications, or get to a terminal?

Can you minimize windows? Once you do, is it obvious how to restore them?

Is it possible to log out with your setup? What happens?

What happens when dialogs pop up? Or different file types are downloaded? Is it obvious how to close windows that might need to be closed, or find them if they lose focus?

What happens when the user hits the “magic sysrq” combinations? Try alt-sysrq-K, for example.

Application

Can your kiosk application be put in an broken or messed up state with no obvious way to restore it?

Can your application be used to launch system utilities or browse system files?

Does your application have problems if closed improperly?

Is there an obvious way for users to “reset” the program if they’re stuck, or if they want to delete their history?

Is it possible to browse unwanted URLs from the browser? Do you need to apply a proxy filter or firewall?

System

Watch carefully at boot; is any sensitive information exposed on the screen? Are there places where a user could stop the boot process and get an interactive prompt?

Scan your system from another system on its network using nmap. What ports are open? Do you need to firewall those ports, or remove the services listening on those ports?

Are login prompts exposed on the system, so that a user could try passwords for root?

Hardware

Is there a way to secure your case? Mouse? Keyboard?

Does the keyboard or mouse have “special keys” like multimedia or Internet buttons, scroll wheel buttons, etc. What do these do when pressed?

Are USB ports exposed on any of the peripherals? Have you secured the system against booting from USB?

Obviously, your need for security and bullet-proof operation may vary depending on where and how you intend to deploy this system; but spend some time trying to think like a hoodlum with Unix experience, and see what you can do to secure the system against tampering.

Just the beginning

This is just the start of what you can do with Linux and kiosk setups. Now that you understand how to use the .xinitrc, the sky’s the limit! If you’ve created Linux kiosks, or if you’re unsure how to solve a particular problem you’re having, leave a comment and tell me all about it.

2012 Update: Some additional resources

This article has proven to be somewhat popular as a resource for setting up Kiosk systems on Linux, so I’m including some links to additional resources that I’ve posted on this blog since I wrote this article:

WCGBrowser — this is the browser I ended up writing to replace Firefox on my kiosks. It’s built in Python, QT, and WebKit, and it’s fully configurable through a plain text YAML config file. I released the code since writing this article, and continue to develop it into a general-purpose solution for kiosks. It’s Free under the GPL v3, and the code is on my github page.

KiLauncher — a full-screen launcher menu, also built with Python and QT and configurable through a YAML config file. It’s also theme-able using QT stylesheets ( a subset of CSS). Also Free under the GPL v3, and the code is on my github page.

2013 Update

It’s late 2013, Wheezy is among us; as some commenters have mentioned, gdm (version 2) is no longer an option if you’re building a kiosk on Debian stable. For wheezy, I’m recommending you use lightdm instead.

Simply replace “gdm” with “lightdm” in your installation procedure. To setup auto-login, run the following command:

Apart from that, my kiosks are still running happily using this procedure on Debian Wheezy, so nothing really needs to change. If you’re using Ubuntu, with all this Mir and Xmir business, you’re really on your own there. If you manage to get it working on Ubuntu 13.10 or higher, let us know what you did.

Love your tutorial but I am having trouble getting it working. I am trying to install a minimal version of Ubuntu 12.04 (64 bit) on a 4 GB USB stick. I am thinking that this would be a cheaper and probably more reliable solution than a traditional hard drive. I think I followed your instructions exactly but when I reboot the computer and try to login to the kiosk account I get the following error message: Failed to load session “gnome”

NOTE: When I installed gdm I did use the –without-recommends option. Any ideas on how to fix this?

GDM has changed a lot over the last few years, I haven’t tried this on Ubuntu 12.04 so I’m not sure what the current GDM on there is doing. But basically, it’s trying to launch GNOME rather than your ~/.xsession or ~/.xinitrc. I remember this being an issue a couple years ago, but I figured it was fixed by now. Apparently not.

See this post on Ubuntu forums and try the recommended solution. It might help. You might also see if GDM is creating a ~/.dmrc file and what it contains.

If that’s still not working, you can try another display manager like lightdm (default for Ubuntu). I know it can do autologin, though I don’t know if it will handle a local session script any better.

UPDATE: I got insanely curious, and found that in fact GDM DOES come with a user xsession, but your script has to be called ~/.xsession, NOT ~/.xinitrc. So simply rename your script and it should be fine. Also, make sure ~/.xsession is executable.

Thanks for your help. Login now works perfectly! I have been trying to figure out how to modify GDM to enable auto login of the kiosk account. There is a gdm.conf file, but I have no idea where to the lines you suggest in your blog post. I have tried a few different places but it would always boot me to a command prompt.

GDM3 may have different configuration parameters. If all else fails, log in to some kind of conventional desktop and run “gdmsetup” to configure the auto/timed login. Or you can attempt the advice given in these comments by Omari and just circumvent the display manager.

This is why my tutorials always include a healthy dose of theory, because more than likely the exact steps become obsolete in a few years or with a different distro.

I tried the inittab approach, and some other non-display manager approaches before (e.g., “su -c kiosk startx” in /etc/rc.local”). I had mixed results, and sometimes just plain strange side effects. Probably with more time I could sort those out, but using a DM seems to take care of things without introducing much overhead. If it works for you, though, awesome. Definitely worth checking out, especially on hardware with limited storage or low power.

I’ve tried several window managers, I found matchbox worked best for me, even with zero configuration. But there are pros and cons to each. I’m not sure I’d recommend FVWM to anyone but an experienced FVWM user.

First, if ACPI is working correctly, you should be able to power it off cleanly with a quick click of the power button.

If that doesn’t work, and you haven’t axed the TTYs, you can always switch to a TTY, login as root, and power down. Or just hit ctrl-alt-delete (in a TTY) to reboot, then power it off once the disks are unmounted (ie, once you see the BIOS screen).

Another option is to set up GDM for a timed login, and provide some kind of logout facility in your kiosk configuration. Then you can logout back to a GDM screen and shut down from there.

Finally, there are always the “magic sysrq” sequences which should work on anything running a linux kernel. alt-sysrq-REISUO should cleanly power off the system.

Of course, there’s precious little being written to the drive on a kiosk, and if you’re using a journaling fileystem, probably little chance of important data being lost if you just hard-power it off.

I should add, all of my kiosk systems are running openssh-server, and I usually manage them remotely. So if I need to power on off, I ssh in and do it from the terminal.

Maybe I can specify my question:
I’m setting up a cafe for a meeting space at a social center. Visitors should be able to switch on and off the machine themselves. I also would like it to shutdown automatically after being idle for 30 minutes.

Well, if they are going to switch the system on, then they will have to have access to the power switch; as I said before, if ACPI is working correctly, this could be a viable solution for turning it off too.

However, it sounds like you’d rather have a clean, software-oriented solution.

First thing is, on most distributions shutting down requires administrative privileges. So you’ll want to set up sudo and configure it to allow the kiosk user to run shutdown (and only shutdown) with no password prompt. The sudoers man page should give you some assistance here.

Once that’s configured, it’s just a matter of giving them a button or shortcut that would execute “sudo shutdown -P now”. Many possible ways to do this:

– Run a standalone panel (tint2, ltpanel, perlpanel, etc.) from the .xsession/.xinitrc script and add this shutdown command as an icon on the panel.
– Run a desktop environment of some kind and put this as a desktop shortcut (kind of defeats the purpose of a kiosk, but it depends on what you want)
– Use a launcher menu like my KiLauncher and add this command as a launcher button
– bind it to a simpler keyboard shortcut using xbindkeys

For xautolock, you can use the same command. I would advise maybe putting it in a script, and maybe adding a call to a dialog of some kind (using zenity, dialog, xcowsay, etc) to warn them that the system is about to shut down.

There may also be some simple applications out there for dealing with this stuff in a graphical way; a quick search of the Ubuntu repositories turned up “qshutdown”, which may be applicable to your situation.

Great blog!
I managed to get the kiosk up and running using Chrome.
However, I have the problem that Chrome forgets all its settings when it closes. This means that each time the kiosk fires up, I get message boxes asking if I want Chrome to be the default browser. Any help to fix this?

Well, normally you *want* Chrome to forget its settings when it closes. That’s what the rsync script does. If you want to change something (like telling it not to ask you about being a default browser), then you need to do this:

Very good article and very well written. I’d just like to add for the assistance of others in a similar situation to mine:

1. If you use matchbox-window-manager and get the annoying title bar that you probably don’t want, then revise the .xinitrc or .xsession file with one slight addition:

matchbox-window-manager -use_titlebar no &

2. If you don’t use mouse interaction much, are using a touch screen, or are using this as an almost RSS feeder style television, then you have 2 options: you can go through the complicated theme change to make it transparent, OR much easier, just install the X11 extension called unclutter. It simply hides the cursor after about a half second (adjustable) period of inactivity. If using Ubuntu (probably Debian too if it’s in their repository – I chose Ubuntu server for it’s vast graphical resources and of course Debian heritage):

Update: If you install the unclutter extension, you have to use .xsession and not .xinitrc.

I discovered this when I symlinked .xinitrc to .xsession and the mouse started showing back up. The .xinitrc took priority and the mouse unclutter stopped working. Based on the comments above it seems that .xsession is pretty much always the better choice.

Also, another cool trick: if you have x11-common configured to allow “anybody” in /etc/X11/Xwrapper.config then you can have /etc/rc.local and completely bypass the need for GDM/KDM/lightDM.

When I first started messing with kiosks, I used .xsession, but somehow along the way I got the impression .xinitrc was the “right way” to do it. Seems more and more that I was right in the first place and .xsession is the way to go.

As for the no-display manager thing, it seems to work for some people, but every time I revisit that kind of setup I have weird issues with font sizes, or obscure window manager variables not being set, or whatnot. It may just be the hardware I end up using (typically off-brand thin clients or dusty old ruggedized laptops), but I can’t seem to ever make it work reliably. YMMV.

Offhand, this sounds like a situation where matchbox wouldn’t be a good choice. You can use any window manager you wish, I chose matchbox for the tutorial mainly because it worked well for a single application window with the occasional pop-up or dialog. Maybe openbox would work better?

Then again, there are some tricky aspects to having two respawning apps in your session, and window management might not be the real issue. Not sure if this would work, but offhand I’d suggest putting your infinite chromium loops in individual scripts, backgrounding the scripts in your session script, and maybe using the window manager or another application to block the session script from ending.

As for application switching, take a look at tint2. It’s a customizable panel/taskbar; it’s nice for kiosks because (a) the customization is strictly config-file-editing (so there’s no configuration dialog to lock down), and it doesn’t have a “start menu”. I’ve used it in a situation where I wanted to allow users to switch programs without being able to launch new ones.

Thanks for the reply. I’ve had some fun playing around with the session script and I set up two more scripts as you suggested which are called as background scripts from the session script. The only issue I’m having with those currently is that I can’t get them to wait for the previous instance of chromium to close before starting a new one (not having an & at the end of the line doesn’t seem to work in this instance – presumably because the script itself is a background process).

The other problem I’ve been having is with the GDM autologin. For some reason, when I edit the config file to contain AutomaticLoginEnable=true and Automaticlogin=kiosk (my user is called kiosk), it hangs on the splash screen. This suggests to me that it is not starting the session. One of my thoughts on why it is doing this is that it might be trying to load the wrong session but I’m not sure how you change the default session for a user, nor how you change what session the autologin uses. Interestingly, the gdm config file is called custom.conf for me (probably because I’m using Ubuntu 12.04 rather than Debian) and it works fine using a timed login as opposed to an automatic login. Obviously, its not absolutely essential to have an automatic login rather than a timed one, but it would certainly be a lot better for what I need it for.

Concerning tint2, if I get these other issues sorted then I will probably have a look into it if I have time to spare. Ultimately though I feel people ought to be able to understand that to switch windows you have to press alt-tab, especially if there is a notice next to the monitor telling them to do so.

You might want to check out Tiny Core Linux. It works extremely well as a super small image that also works very well with flash drives by loading completely into memory and only writing when you tell it to save configs. With a web browser, it ends up being around 40-60 megs. So far, it’s been very actively updated, and has about 4,000 packages you can choose from. You can also remove any local physical disks and pxeboot your image from a central server making it easy to manage lots of kiosk style terminals. If someone actually manages to break something, it just takes about a minute to reboot and pxeboot the kernel+tinycore+packages+custom configs back to default. If someone steals it, there’s no hard drive, and therefore no sensitive information could be contained within either.

I also use fluxbox as a window manager because it’s very lightweight, very easy to customize and lockdown, and I’m already very familier with it. I tried going without the window manager, but some apps just don’t play well without.

I’ll have to take a look at your custom browser when I get a chance because that’s one place that is extremely lacking for kiosk style use on linux.

It’s hard to say without more information, but two possibilities occur to me:

– Your TV is not getting full resolution, and maybe it’s only 1024×768 or something. Check xrandr, maybe from a tty, like this: “DISPLAY=:0 xrandr”.
– The window manager is screwing up fullscreen somehow. Try a different one.

Any ISO of debian (assuming it runs on your hardware) should work fine. The only difference between the business card and the others is that you have to download more from the internet during install. As long as bandwidth isn’t a problem, it’s probably a better choice, since you get the latest versions of everything directly.

You can leave “base system” installed, but you don’t need the desktop environment. You can install it if you wish, it won’t really hurt anything; except you won’t need what it installs, and you’ll be wasting disk space and bandwidth keeping them updated.

Finally, just a minor note, on Debian you really should use aptitude, not apt-get.

Unfortunately I have no experience with xtensoftphone or x-lite, I’ve never heard of them before your comment. My guess is that they depend on some desktop service (dbus? alsa?) that isn’t running, but you’ll want to start by checking ~/.xsession-errors (in the kiosk user’s home. Note that you need to read this from another login).

– First, the reason only chromium is running is because your script is waiting for chromium-browser to exit before running the next command. Running three applications in a loop like this is tricky, because there are some questions you need to answer about how exactly you want it to behave. Do you want each application to respawn when closed, or only when a certain one is closed, or is it the user’s problem if he closes one of the applications, etc?

Most likely what you want to do here is put each program in it’s own infinite loop, and then background each loop, like so:
while true; do chromium-browser -app=blah ; done &
while true; do /opt/kiosk/xtensoftphone; done &
while true; do /opt/kiosk/whatever; done &

Then you need to just put something at the end of the script to keep it alive and running. You could put your window manager command here, or a background service, or whatever. Just make sure it doesn’t have an ampersand at the end.

– Second, you probably want to look into using a window manager that supports alt+tab switching out of the box. Try openbox, maybe. I don’t know for sure if matchbox does this, maybe it does.

– Finally, if you have multiple apps running, you might try a panel like tint2 to make it easier to switch applications using the mouse. You’d need to run this with an ampersand, and somewhere before the infinite loop.

Thank you for this fantastic tutorial.
After many many tests to have virtual keyboard “onboard” running in a Ubuntu kiosk with tactile screen, I had success with the help of your contribution, really usefull !

Slim is very lightweight and works great, but only if you can get a version with autologin. When I wrote this the version of slim available in many distros lacked this feature, and I think slim may have even been removed from Debian squeeze for security problems. Looks like it’s back in wheezy, so maybe all that’s been shored up.

Found your how-to and read it, re-read it then re-re-read it. Building a kiosk OS based openSUSE for my employer. Thanks for the great start and I will post back with more info as we continue our development.

hi Alan thanks for the brilliant guide i have been using for a while, i was wondering if i wanted to use the kiosk with a timer for say a cyber cafe how would i go about it.Can the xsession be timed or would i have to decode the browser to act as a timer.by the way i tried installing a cyber cafe timing software called mkahawa but it hasn’t worked.Any ideas how i would go about it.Thanks

Depends on what you need; if you just want the session to reset after a certain period of inactivity, you can do that with something like wcgbrowser, or xautolock in combination with some scripts to reset the session.

On the other hand, if you’re wanting to, say, limit a session to a certain time period, that’s another matter. I have to admit I have little experience with a cyber cafe environment; the closest I’ve come are the public computers at our library, which run a (windows-only) time management system which allows patrons to reserve computers and limits the amount of time they can spend on a computer. I don’t know of a comparable system for Linux, but mostly that’s for lack of research.

hello there! thank you so much for this tutorial has helped immensly. however for what ever reason once i run the login for the kiosk and then log out and back into my admin account i do not see my .xsession file searched the whole system and its just gone… show hidden files is on so im just at a loss. any thoughts? any help is greatly appreciated hope to hear from you soon!

thank you!! 1st problem solved haha. If you have any thoughts on to why I am unable to play flash videos in the Wgcbrowser kiosk I am all ears… I have flash plugin installed(not sure if i need the GNU Gnash player as well?) and i have the .yaml file set to True for plugins.

That I don’t know. I can tell you it works just fine for me using Adobe flashplugin, so it is possible to make it work. Maybe try running with the debug switch and make sure your config file is being parse properly.

Alright got all problems solved that ive asked so far… However for what ever reason when i try to play a .mp4 file or .webm file from my server i get a network error. I even tried making the file where the .mp4 file is found, the start url(http://groupxondemand.com/groupx/video-bin/totallytabata.mp4) still no luck. Whats weird though is that if i change the start url to a .jpg image it goes there with no issue, therefore i know its looking to the right directory but just doesnot want to play. Anythoughts are greatly appreciated!!! and if you need more details please let me know, Thank you!

I haven’t tried, but I suspect if you just point wcgbrowser straight to an mp4 file it will want to download the file; and if downloading is disabled (it is by default), you’ll just get a 404. Unlike jpeg (or png/gif/bmp/etc) files, browsers don’t handle mp4 natively; typically an mp4 file would either be downloaded or handed off to a media player plugin. I haven’t tried using a media player plugin (e.g. mplayer, vlc) with wcgbrowser, but I suppose if flash works other plugins ought to as well.

What would probably be better in this case is pointing WCGbrowser to an HTML file that contains HTML5 video tags pointing to the file.

Finally, you have to remember that wcgbrowser is basically a Python wrapper around a QtWebkit widget that provides configuration and a few other helpful features. HTML rendering, plugin support, javascript issues, etc are all in the QtWebKit domain and not something I’ve implemented. If something doesn’t work in Wcgbrowser, the next step is to test it in another QtWebKit browser like rekonq or arora (*not* Chrome/Chromium, btw — they use a different implementation of webkit, a different javascript engine, different plugin interface, etc. Also not gtkWebKit browsers like Midori, uzbl, luakit, jumanji; again, different implementation).

Thanks a lot! You’ve made my day, resp. week :). Tried several pre-made solutions, but as I needed to add CUPS and I’m a beginner, this step by step was really helping – and also helping to understand how things work, so I could customize it.. Thanks!!

Hi Alan. Looking at setting up a kiosk type system. It’ll mostly just go through the same set of html pages depending on what you select, basically behaving a bit like a smartphone app would. I’m not not going to use a keyboard, just a touchscreen. The limited options available can just be clicked on screen.
The web browser would need to stay open at all times and effectively the system desktop would be the web browser. Any thoughts on this? Can a web browser be ’embedded’ as the desktop? No idea how best to approach this so your advice would be much appreciated.

Unless I misunderstand your question, that’s basically what this blog post describes. Or do you mean that the browser would be sort of a “background” and selected links would open in new, floating windows on top of it?

Hi Alan. Thanks for the reply. I’m new to this so forgive me if I’m misunderstanding. I took it to do what I wanted I’d need something like this… https://code.google.com/p/chromiumembedded/
I don’t want any way that the browser can be quit or minimized, I only want the html pages to load on boot and nothing else. That the browser is the desktop. Does that make sense?

I think I understand; my kilauncher application does something similar. If memory serves, I was able to do this by making the application full-screen and setting some X11 window properties to make X treat it like a root window.

The relevant lines from kilauncher, starting at line 234 in the current code , are:
self.setWindowState(Qt.WindowFullScreen) self.setWindowFlags(self.windowFlags()|Qt.WindowStaysOnBottomHint|Qt.FramelessWindowHint)
self.setAttribute(Qt.WA_X11NetWmWindowTypeMenu, True)

You can probably set the same flags using a utility like wmctrl, or wcgbrowser could be modified to behave like this.

But really, if they have no mouse or keyboard access and the window decorations are hidden, I’m not sure all that is even necessary. How would a user close or minimize the browser in that scenario?

Hi
Thanks for this, using some of this info I was able to replace my Libraries opacs with raspberry pi’s. I have them running raspbian and window maker. I am running chromium in –app mode so it behaves like a kiosk (as I only want one page displayed) so chromium runs in a loop, if someone does an Alt +f4 chrome just opens right back up again.

there are a couple options you can get into using a right click, so I used a squid proxy to disable all URL’s except the one I want access to.

pretty decent setup for a public library and Rpi’s are so cheap to run the power savings alone are excellent!

Thanks for the great tutorial. I’m a newbie to linux so please excuse me for my obvious questions. I’m trying to create a kiosk for the manager to playback video for quality assurance purposes. So I need the webrowser to run flash. So my question is, if i install Chromium, what steps do i need to have it run flash? Install flash plugins and does Chromium auto enable plugins when it runs or there are flags we have to set in the script? Your browser has all the functionalities that i want out of a kiosk and it also supports flash but how to configure for flash?

If you install flashplugin from the repositories, it should automatically work in all browsers without extra tweaking.
For WCGBrowser, you need to enable plugins in the configuration, but otherwise it should “just work”.

Thanks for the great tutorial; I am able to get my pi in kiosk mode with a touchscreen. But I have a acute problem, whenever the user tries to login into a website using his username/password. The keyboard pops-up when he wishes to enter the username but losses focus when password needs to be entered. Somehow the virtual keyboard doesn’t pop up when password field is clicked.

Any pointer will be helpful as this is the only thing which is blocking my kiosk from its field test

Hi Alan, thanks for posting this.I am new to Linux. I am trying to run chromium in full screen from the command prompt. I type: “xinit chromium –app=http://www.google.com”. It tries to load chromium but then it exits and says something to the effect of: “xterm: “–app=http://www.google.com” is a bad command. Will this only work from inside a script? thank you.

I haven’t tried that way, but my guess is that you’ll either need to put your chromium command in a script, put it in .xinitrc, or maybe just put it in quotes so its seen as a single argument to xinit. Complications like this are why I just eventually decided to use a display manager.

– Putting everything in /opt/kiosk is fine, but obviously you’ll need a .x[something] in /home/kiosk to do the first rsync. And if a hacker has write-access to /home/kiosk then that restore phase can be disabled (although the copies in /opt will hopefully be safe).

– I couldn’t get .xsession or .xinitrc to work from Xubuntu’s session manager, so I just modded the GRUB config. to do a text boot. I’m guessing I can just put startx into .bashrc (which will find .xinitrc).

– For my full-screen app, I don’t need a window manager at all. Is there a reason why a full-screen Chromium needs one?

– I just usually copy it over manually during the initial setup. You’re correct about write access, but if you’re only exposing a browser, there’s only so much he can do (download and overwrite?). I’ve generally kept the session and programs locked down to prevent this. You could make .xsession owned by root, but you won’t be able to make changes without manually copying it.

– Don’t know which version of Xubuntu you’re using, but in the past with GDM I’ve had to create an Xsession script in /usr/share/xsessions for using the default Xsession (which launches ~/.xsession); I can’t remember having this problem with lightdm, though. You have to make sure .xsession is executable too. Some of the other comments here detail some ways to get around having a display manager, if you want to try that.

– If your application full-screens correctly without one (some applications don’t), and you will never have pop-ups, dialogs, or multiple windows, then you’re probably safe. Such is not necessarily the case with a full-screen Chromium (e.g., print dialog, opening a PDF, popup windows, HTTP authentication dialogs), depending on your content. A window manager adds very little to the overhead, and takes care of those little issues.

Ah, OK. I think I’m happy with text bootup, so will keep it that way. Yes, our kiosk app is full-screen Java+JOGL, with simple geometric point-and-click, so no widgets needed. Will keep matchbox in mind for future requirements, though.

Another observation about the .xinitrc/.xsession copying: since this is done within the init itself, if that ever changes then you need two logins before it takes affect. Unlikely, I know (although I was running a JAR file with version number in the filename, and wondering why I was getting the old one…!).

sorry for my ignorance…i am trying to do it with cubieboard wich is armhf so there is no minimal instalation of debian or any other around, i’ll try to follow your tutorial based on wheesy hf version and wil let you know. i need my app running in kiosk mode. thanks in advance for your futue help

i did all the steps described in the tutorial, as i said previously, i am running cubieboard cubieez. at starup it does not works at all, if i run .xinitrc manually it execute the script, any help? obviously xinitrc is not being called at boot but i don’t have any clue