18

We are assembling some lightweight machines with the express purpose of displaying a single web page over a large screen. I need the machine to essentially boot up as lightweight and as quickly as possible and essentially have it run a browser (WebKit?) in full screen, loading one page which will be controlled dynamically by JavaScript. I'll be using an Intel D525 dual-core processor with integrated GPU, so I shouldn't need to set up any proprietary graphics drivers. Once I get one of these machines set up properly, I should just be able to dd the hard drive onto my computer and then dump it onto each new machine.

I have the following questions:

  1. How can I create a "distribution" which includes only what I need? I suppose I'll need the kernel (;]), X, and a web browser of some sort, but not really too much else. Could I take something like Ubuntu Server and simply install X Server and find a way to have the machine automatically log in, start X, and start the web browser, no questions asked? Is there a book I can read or an article or something?

  2. What can I use for a nice, stripped-down web browser that essentially runs a "chromeless Chromium?" These machines won't be accepting user input at all. If I need to manage them, I'll use SSH.

Rui F Ribeiro
  • 56,709
  • 26
  • 150
  • 232
Naftuli Kay
  • 39,676

9 Answers9

12

Many distributions have some facility for a minimal install; essentially where you manually select only those packages that you explicitly wish to install. Debian has this ability and would be a better choice, in your situation, than the other obvious minimal contender, Arch Linux.

Arch's rolling release status may provide a level of ongoing complexity that you wish to eschew. Debian would provide the simple, minimal base you are looking for plus offer stability. There is a blog post on using Debian as a kiosk that may offer some helpful tips.

For a browser, as beav_35 suggests, Uzbl is a good choice. My recommendation would be Vimprobable, a WebKit browser that is scriptable, keyboard driven and can be controlled effectively over SSH.

As a window manager, I would recommend dwm: at less than 2000 SLOC, it is extremely lightweight and can be easily configured for a kiosk-type setup.

jasonwryan
  • 73,126
  • dwm looks great for this purpose, and I'm much more familiar with Debian-based systems anyway, so I'll probably use Debian. How small do you think I can get the OS down to? And how can I build a Debian distribution? – Naftuli Kay Aug 01 '11 at 17:56
  • As you proceed through the installation, when you reach the select packages step, instead of Laptop, Standard, etc, choose "Manual" and only select those packages (like X) you need for a bare minimium: start here http://www.debian.org/CD/netinst/#businesscard-stable – jasonwryan Aug 01 '11 at 18:29
5

First of all, you might not want to reinvent the wheel... There are several kiosk-focused distributions. One of those might save you a lot of work.

Second, if you are familiar with Kickstart on Fedora and RHEL(or CentOS or Scientific Linux), you can use the Fedora tools to make your own spin of any of those distributions. The documentation is a bit scattered, but start here.

4

Start with a minimal distro such as Arch Linux, then install the packages you need. For a simple web browser try Uzbl.

beav_35
  • 141
  • 2
3

This is a pretty involved question, and since your project isn't entirely clear some of these suggestions may be off-mark, but consider them things to evaluate.

  • You may not need a web browser on ever computer that is part of the display array. If you are trying to show one single page across many screens, chances are you are going to want to use some kind of mass display technology. There are several variants of Xorg that specialize in generating one large display out of video devices on several machines.

  • Even if you use separate X servers on each machine, you can use X-forwarding to send display data from one or more other computers, so the browsers still wouldn't have to run locally.

  • You will want to either use no window manager at all and use geometry specifications to launch your app full screen, or use a configurable tile or framework window manager (such as awesome) to manage the windows on each X display. These make it easy to sort and control full screen windows and are highly scriptable.

  • As for a browser, I think uzbl is likely the clear choice.

  • This might be a good application for network booting. You can setup server with a netbook kernel available via TFTP and a file system available via nfs. All your clients need to do is use a netboot capable NIC to contact this server, download their kernel and go. No hard drive involved! And easy maintenance. All the machines can potentially boot the same image.

  • Your "distro" should probably consist of two things. 1) A package set and 2) a set of configuration files. The package set is a list of packages that need to be installed. This can usually be assembled in a text file and then you can use most distro's package managers to install this list of packages to a target (either a hard drive or a directory that will be your nfs mount point). The configuration files should probably be kept in git or another source control system and contain a few scripts and whatever config mods need to be made to the base system installed with the package set. Building a new system then becomes:

    • Mount drive or target directory
    • package_manager --install-distro --package-set=/path/packagelist.txt --target=/path
    • cd /target/path
    • git clone /path/to/repo (or otherwise checkout your config code to the system root)
    • Install bootloader if drive or add PXE config if netboot
    • boot.

What distro you use as a base should depend on what you are most comfortable with. I would use PLD-Linux for myself, but probably recommend ArchLinux as a similar but better documented system for a newbie to work with. There is no reason Debian, Fedora, or Gentoo would not work for this.

Caleb
  • 70,105
  • on net booting: that sounds AWESOME and would make things so much easier to maintain. However, each machine needs to load a different URL, as they'll be fetching information unique to the machine. Is that doable? Everything else would ostensibly stay the same, though I might configure each machine to use a different user/password for HTTP-Basic authentication as a little means of security. – Naftuli Kay Aug 01 '11 at 18:02
  • on "You may not need a web browser on every computer that is part of the display array": I think I will, actually. Each one of these machines will be in a different location, driving one display over VGA or HDMI, displaying a unique webpage for that machine. (although we could serve a single URL which varies content on user/password). – Naftuli Kay Aug 01 '11 at 18:07
  • on window managers: I'd probably just use a really lightweight one like dwm or awesome. How can I tell a window manager to start an application without the title-bar in full screen mode? – Naftuli Kay Aug 01 '11 at 18:08
  • on what distro should consist of: so all I'd really need is to create a git repo, keep a package list and configuration files, and then create an ISO somehow. How do I get the tiniest Debian distro and then work up from there? How do I take these config files and make a burnable ISO? I'd be using apt-get or aptitude on Debian. – Naftuli Kay Aug 01 '11 at 18:11
  • on X-forwarding: it shouldn't really be necessary, as I'll be driving one display per machine. I'll probably have to find a way to have the machine issue a reverse SSH connection so my computer would be able to connect to it, but there might be a way to automate this. Is there a way to have a computer A open a TCP connection to computer B and then have computer B connect over that connection to computer A via SSH? Otherwise, I'd have to get dynamic DNS names for each router: not fun/easy. – Naftuli Kay Aug 01 '11 at 18:14
  • @TKKocheran: Your question sounded more like you were making a big display matrix rather than kiosks, so disregards the X stuff. Of course it's possible to load different URL's on each machine, even if you use the same root file system. If you ask a separate question for either awesome about how to configure an auto-full screen layout and I'll jump in with an answer. – Caleb Aug 01 '11 at 18:18
  • @TKKocheran: Please don't ask new questions in comments! Yes you can make chained or reverse connections over SSH using tunneling, but please ask that separately. – Caleb Aug 01 '11 at 18:21
  • @TKKocheran: I think you're on the wrong track with "generating an ISO" -- you don't need to do that, you just need a custom install config and you can use the normal install tools with your config/package set/install script. – Caleb Aug 01 '11 at 18:22
  • Migrated netboot questions here. – Naftuli Kay Aug 01 '11 at 18:46
  • Migrated SSH questions here – Naftuli Kay Aug 01 '11 at 18:52
2

Buildroot 2016.05 + Midori

Buildroot is a great tool to build minimal distros:

  • you give it a .config file
  • it downloads and compiles all the required software and dependencies, and produces an image

Midori a minimalistic WebKit-based browser, and Buildroot has a built-in Midori package.

.config file used: https://github.com/cirosantilli/buildroot-configs/blob/32d1174e0bf8d00b92323eebe8901af3f8c389d3/2016.05/qemu_x86_64_x11_midori_defconfig

How to generate that config file:

  1. Follow: How to install X11 on my own Linux Buildroot system? | Unix & Linux Stack Exchange to create an image with X11.
  2. make menuconfig
    1. Toolchain
      1. C library
        1. glibc (for midori)
    2. Target packages
      1. Graphic libraries and applications
        1. mesa3d
          1. select all Gallium and DRI drivers since I don't understand which one is needed (for OpenGL EGL)
          2. OpenGL EGL (for libgtk3)
      2. Libraries
        1. Graphics 1. libgtk3 (for midori)

Clean the build because we changed the toolchain and build again:

rm -rf output
make BR2_JLEVEL=$(nproc)

Wait hours. Then the usual:

qemu-system-x86_64 \
    -enable-kvm \
    -M pc \
    -m 512 \
    -kernel output/images/bzImage \
    -drive file=output/images/rootfs.ext2,if=virtio,format=raw \
    -append root=/dev/vda \
    -net nic,model=virtio \
    -net user

And from inside QEMU:

root
startx

and from the X11 GUI click an xterm window and run:

midori

Outcome:

enter image description here

Image size: 220M! Compare that to the 28M of a bare X11 system How to install X11 on my own Linux Buildroot system? - Unix & Linux Stack Exchange . Likely because of WebKit + GTK3 dependencies.

Tested on Ubuntu 16.04 host, QEMU 2.5.0.

NetSurf

Written in SDL, which supports the fbdev: http://www.netsurf-browser.org/about/screenshots/#framebuffer

fbdev is a lower level interface offered by a Linux kernel module that does not go through X11 (I think X11 can optionally use it as backend). You basically just write to memory and it shows on screen.

To use fbdev on Ubuntu, you have to be on a TTY (e.g. Ctrl + Alt + F1).

So you can probably get away with an image way smaller than that of Midori.

Buildroot 2016.05 has a package netsurf-buildsystem which should provide it, but I haven't tested. If someone manages to get it running, please edit in a link to a .config, screenshot and image size.

Ciro Santilli OurBigBook.com
  • 18,092
  • 4
  • 117
  • 102
1

I have written a little bash script once that takes an Arch Linux ISO and generates a new ISO with a modified root image which does a fully automated install. This includes partitioning as well as setting up and configuring the system with Xorg, FVWM, and Chromium. The installed system will login automatically and start Chromium. Just put the new ISO on a USB flash drive and lean back. ;-)

Disclaimer: the script is provided as-is, no warranty given. I haven’t used it in a while, so it might need a tweak here or there. Modify as needed.

#!/bin/bash
# Helpful pages:
#
#   * [ArchWiki topic][1] that explains the options of an AIF configuration
#     file.
#
#   * [Status of automated installation][2], a topic in the Arch Linux Forums
#     that contains the original basic install script by *mhertz*.
#
# [1]: https://wiki.archlinux.org/index.php/AIF_Configuration_File
# [2]: https://bbs.archlinux.org/viewtopic.php?id=111925

TMP_DIR=/tmp/arch-install

# Read command line parameters for input and output ISO files.
if [ -z "$1" ]; then
    echo 'No input file specified, aborting.'
    exit 1
elif [ ! -f "$1" ]; then
    echo 'Input file "'$INPUT_ISO'" not found, aborting.'
    exit 1
elif [ -z "$2" ]; then
    echo 'No output file specified, aborting.'
    exit 1
elif [ -f "$2" ]; then
    echo 'Output file "'$OUTPUT_ISO'" already exists, aborting.'
    exit 1
fi

# Determine full paths to input and output ISO files.
INPUT_ISO=$(readlink -f "$1")
OUTPUT_ISO=$(readlink -f "$2")

# Set some variables for convenience.
SOURCE_DIR=$TMP_DIR/source
DEST_DIR=$TMP_DIR/dest
ROOT_DIR=$TMP_DIR/squashfs-root
BOOT_CFG=$DEST_DIR/boot/isolinux/isolinux.cfg

# Extract ISO image and root image.
mkdir -p $SOURCE_DIR
mount -o loop "$INPUT_ISO" $SOURCE_DIR
cp -a $SOURCE_DIR $DEST_DIR
umount $SOURCE_DIR
rmdir $SOURCE_DIR
unsquashfs -d $ROOT_DIR $DEST_DIR/root-image.sqfs
rm $DEST_DIR/root-image.sqfs

# Modify the root image as needed.
cat >> $ROOT_DIR/etc/aif.conf <<EOF
SOURCE=cd
FILE_URL=file:///src/core/pkg
SYNC_URL=http://ftp.tu-chemnitz.de/pub/linux/archlinux/\$repo/os/\$arch
HARDWARECLOCK=UpTC
TIMEZONE=Europe/Vienna
RUNTIME_REPOSITORIES=
RUNTIME_PACKAGES=
TARGET_GROUPS=base
TARGET_PACKAGES_EXCLUDE=
TARGET_PACKAGES='openssh xorg xcursor-vanilla-dmz-aa'

worker_runtime_network () {
    dhcpcd eth0
}

worker_configure_system () {
    prefill_configs
    sed -i '/^HOSTNAME/ s/"myhost"/"arch"/' \$var_TARGET_DIR/etc/rc.conf
    sed -i '/^password/ s/pam_permit\.so/pam_unix.so md5 shadow/' \$var_TARGET_DIR/etc/pam.d/chpasswd
    sed -i '\|Server = http://ftp\.tu-chemnitz\.de/| s/^#//' \$var_TARGET_DIR/etc/pacman.d/mirrorlist
    sed -i '/id:3:initdefault:/ s/^/#/' \$var_TARGET_DIR/etc/inittab
    sed -i '/id:5:initdefault:/ s/^#//' \$var_TARGET_DIR/etc/inittab
    sed -i '\|x:5:respawn:/usr/bin/xdm| s/^/#/' \$var_TARGET_DIR/etc/inittab
    echo "x:5:respawn:/bin/su -l -c '/usr/bin/startx </dev/null >/dev/null 2>&1' myuser" >> \$var_TARGET_DIR/etc/inittab
    sed -i 's/^timeout .*$/timeout 0/' \$var_TARGET_DIR/boot/grub/menu.lst
    cp /etc/rc.local.firstboot \$var_TARGET_DIR/etc/rc.local
}

# Mandatory variables.
GRUB_DEVICE=/dev/sda
PARTITIONS='/dev/sda 20:ext2:+ 512:swap 2500:xfs *:xfs'
BLOCKDATA='/dev/sda1 raw no_label ext2;yes;/boot;target;no_opts;no_label;no_params
/dev/sda2 raw no_label swap;yes;no_mountpoint;target;no_opts;no_label;no_params
/dev/sda3 raw no_label xfs;yes;/;target;no_opts;no_label;no_params
/dev/sda4 raw no_label xfs;yes;/home;target;no_opts;no_label;no_params'
EOF

cat >> $ROOT_DIR/etc/rc.local <<EOF
aif -p automatic -c /etc/aif.conf
reboot
EOF

cat >> $ROOT_DIR/etc/rc.local.firstboot <<EOF
echo root:rootpassword | chpasswd
useradd -m myuser
echo myuser:myuser | chpasswd
cat >> /home/myuser/.xinitrc <<EOT
#!/bin/sh
exec fvwm2
EOT
cat >> /home/myuser/.Xdefaults <<EOT
Xcursor.theme: Vanilla-DMZ-AA
EOT
mkdir -p /home/myuser/.fvwm
cat >> /home/myuser/.fvwm/config <<EOT
DeskTopSize 1x1
DesktopName 0 Main
DestroyFunc StartFunction
AddToFunc StartFunction
 + I Test (Init) Exec exec xsetroot -solid '#303030'
 + I Test (Init) Exec exec chromium 'http://www.stackoverflow.com'
DestroyMenu RootMenu
AddToMenu RootMenu "Menu" Title
 + "Terminal" Exec exec xterm
 + "Browser" Exec exec chromium 'https://www.stackoverflow.com'
 + "" Nop
 + "Log off" Quit
 + "Reboot" Exec exec sudo /sbin/reboot
 + "Shutdown" Exec exec sudo /sbin/halt
OpaqueMoveSize unlimited
Style * ClickToFocus, ResizeOpaque
Style chromium !Title, !Border, !Handles
CursorStyle root top_left_arrow
CursorStyle stroke hand2
IgnoreModifiers L25
Key Help R A -
Key F1 R A -
Key Tab A M -
Key Escape A MC -
Mouse 1 R A -
Mouse 1 T A Move
Mouse 1 FS A Resize
Mouse 1 I A Iconify Off
Mouse 2 FST A -
Mouse 3 R A Menu RootMenu Nop
EOT
mkdir -p /home/myuser/.config/chromium/Default
touch /home/myuser/.config/chromium/First\ Run
cat >> /home/myuser/.config/chromium/Default/Preferences <<EOT
{
   "alternate_error_pages": {
      "enabled": false
   },
   "autofill": {
      "enabled": false
   },
   "browser": {
      "custom_chrome_frame": true,
      "enable_spellchecking": false
   },
   "default_search_provider": {
       "enabled": true,
       "encodings": "UTF-8",
       "icon_url": "about:blank",
       "id": "2",
       "instant_url": "",
       "keyword": "google.com",
       "name": "Google",
       "prepopulate_id": "1",
       "search_url": "{google:baseURL}search?ie={inputEncoding}&q={searchTerms}",
       "suggest_url": ""
   },
   "devtools": {
      "disabled": true
   },
   "dns_prefetching": {
      "enabled": false
   },
   "download": {
      "directory_upgrade": true
   },
   "extensions": {
      "chrome_url_overrides": {
         "bookmarks": [ "chrome-extension://eemcgdkfndhakfknompkggombfjjjeno/main.html" ]
      }
   },
   "geolocation": {
      "default_content_setting": 2
   },
   "google": {
      "services": {
         "username": ""
      }
   },
   "homepage": "https://www.stackoverflow.com",
   "homepage_is_newtabpage": false,
   "intl": {
      "accept_languages": "en",
      "charset_default": "ISO-8859-1"
   },
   "ntp": {
      "pref_version": 3
   },
   "profile": {
      "clear_site_data_on_exit": true,
      "content_settings": {
         "pref_version": 1
      },
      "default_content_settings": {
         "plugins": 1
      },
      "exited_cleanly": true,
      "notifications_default_content_setting": 2,
      "password_manager_enabled": false
   },
   "safebrowsing": {
      "enabled": false
   },
   "search": {
      "suggest_enabled": false
   },
   "tabs": {
      "use_vertical_tabs": false
   },
   "translate": {
      "enabled": false
   }
}
EOT
chown -R myuser:myuser /home/myuser
pacman -Sy
pacman -S --noconfirm pacman
pacman -S --noconfirm fvwm-devel chromium sudo
echo 'myuser arch=NOPASSWD: /sbin/halt,/sbin/reboot' > /etc/sudoers.d/start_stop
chmod 0440 /etc/sudoers.d/start_stop
rm /etc/rc.local
EOF

# Create the new root image.
mksquashfs $TMP_DIR/squashfs-root $TMP_DIR/dest/root-image.sqfs
rm -rf $TMP_DIR/squashfs-root

# Configure the boot loader.
sed -i 's/TIMEOUT 3000/TIMEOUT 100/' $BOOT_CFG
sed -i '/APPEND hd0 0/d' $BOOT_CFG
sed -i 's/archisolabel=[^ ]*/archisolabel=ARCH/' $BOOT_CFG

# Create the new ISO image.
genisoimage -l -R -b boot/isolinux/isolinux.bin -c boot/isolinux/boot.cat \
    -no-emul-boot -boot-load-size 4 -boot-info-table -V ARCH \
    -o "$OUTPUT_ISO" $DEST_DIR
rm -rf $TMP_DIR
isohybrid "$OUTPUT_ISO"
igor
  • 807
0

For a system like this I'd recommend Puppy.

While you can build you distro using any version of Linux, Puppy makes it very easy to build custom bootable images, is designed to be compact and has great overlay file system support.

I should just be able to dd the hard drive

No - I'd recommand building a bootable image which you can sensibly maintain - the approach you suggest will come back and bite you.

symcbean
  • 5,540
  • The thing is, I'll be running the operating system on a thumb drive. I won't even potentially have a disk drive with which to install the OS. – Naftuli Kay Aug 01 '11 at 18:35
0
  • Several people mentioned uzbl and I agree it is a nice choice - but you might find luakit even better.

  • As Caleb already mentioned, you do not really need any window manager. Here's an example script that I crafted to run a WM-less Xorg server with maximized luakit browser:

    #!/bin/sh
    XDCMD="xdotool search --class luakit windowsize %3 100% 100%"
    while [ 1 ]
    do
        ( sleep 0.5; $XDCMD || sleep 0.2 && $XDCMD || sleep 5 && $XDCMD ) &
        /usr/bin/luakit $@
    done
    

    It uses the xdotool to maximize the window just after luakit has started. Maybe there is a better solution to that though...

  • For the base of such system, I'd definitely recommend Gentoo. That's not only because I know it best ;) but also because it uses a rather unique approach of globally managing the build-time options of all the installed software. I mean the USE flags. Using those, you determine the set of features/libraries/standards that are used by all programs that support them - so, for instance, if you want your programs to use ALSA and not need additional audio backends like esd, jack or pulseaudio, you put alsa -jack -esd -pulseaudio amongst your USE flags. After that, each piece of software you build that can use additional audio backends apart from ALSA will be built without the support for those. Since this happens at configuration/build level, you end up with significantly thiner software. So this is a philosophy of building up (while respecting all the dependencies) instead of stripping down (which can end up being buggy and very hard to maintain).

0

I'll mention this because I'm surprised no one else has.

Linux from Scratch is a book (pdf) that walks you through the creation of your own Linux distribution. It might be overkill for what you're trying to accomplish (actually, it is seeing as you already have the tools you need), but it can prove to be an invaluable tool in understanding how a system works. It's really not that hard and there's no programming involved.

nopcorn
  • 9,559