Authors: Wout Dillen and Joshua Schäuble
First published: 26 June 2019
Last update: 6 August 2019
(first published version) DOI: http://dx.doi.org/10.17613/6n9b-2n48
This tutorial was developed by Wout Dillen and Joshua Schäuble at the Centre for Manuscript Genetics (CMG), as part of the IIIF courses of the University of Antwerp‘s Summer School on Digital Humanities. This is a one-week summer school organized by the Antwerp Centre for Digital humanities and literary Criticism (ACDC).
The course was first taught in Antwerp in 2018 (3-7 September), and an adapted version was taught again in 2019 (1-5 July). In the course, students learn how to set up a IIIF-compatible image server (iipimage) on a local network of Raspberry Pi computers, to ultimately re-use and manipulate each other’s images using the IIIF protocol.
1. Double-Checking Your Raspberry Pi’s Setup
Developed as a classroom instrument, this tutorial assumes that you are a student, and that you have access to a Raspberry Pi (RPi) with the Raspbian Operating System pre-installed on it. While they were preparing your RPi for this course, your tutors will also have checked that they are set up correctly for the course. Still, it is important that we double-check some of their settings, because they are crucial for the rest of this course.
1.1 Make sure that SSH is enabled on your RPi
On your RPi, select the raspberry icon in the top left corner, and navigate to:
Preferences > Raspberry Pi Configuration. Here, select the tab
Interfaces and ensure, that SSH is
1.2 Ensure that the keyboard layout is set correctly
Up until the moment when we are able to SSH into our RPis, we will need to use the keyboard to control them. Go to
Preferences/Mouse and Keyboard Settings, select the tab
Keyboard and there the button
Keyboard Layout. Select the layout of the keyboard you are using, in our case (at the University of Antwerp) this would be
1.3 Ensure that the system language is set to
We want all RPis to be operated in English. Go to
Preferences > Raspberry Pi Configuration again, this time select the tab
Localisation. Click on
Set Locale and make sure the
Language is set to
English and the
Character Set is
1.4 Set the System Password
Although we are in a closed network for this course and do not expect any hacking attempts, it is always good practice to change your RPi’s password. Especially when SSH is enabled, changing the default password (
raspberry) will prevent others from accessing and controlling your computer without your knowledge. Go to
Preferences > Raspberry Pi Configuration again, this time select the tab
System and set the password to your own (unless your tutor provides you with one).
1.5 Reboot your RPi
Go to your terminal, and enter the following command:
sudo reboot now
2. Connect your RPi to the Internet
In the original setup for this tutorial, all RPis are connected to one another (and together to a local router, called
ethernet. But we need them to be connected to the actual Internet too – to download packages etc. For this connection we will use the WiFi. The problem here is, that your RPi will prioritise Ethernet over WiFi for its internet connection. This is not surprising, because ethernet connections are typically much faster and more reliable than WiFi connections. But so in our case, we’ll need to turn this around, so the RPi will always use WiFi for internet connections first, rather than trying to connect through our (local, unconnected) ethernet network.
2.1 Connect your RPi to the WiFi
WiFi network names and passwords will differ depending on where you are following this course, so listen to your tutors, and use the login information they provide.
2.2 Prioritise WiFi for web requests using
So now we want to make sure our RPi uses the WiFi to connect to the internet, rather than its ethernet connection. To change this, we will need to make changes in a configuration file. Open a terminal, and enter:
sudo nano /etc/dhcpcd.conf
This will tell the RPi to use the programme
nano, a shell text editor, to open a file located in the path
2.3 Assign metric values to your ports
arrow-down key to move to the end of the configuration file. There, add the following lines:
interface wlan0 metric 202 interface eth0 metric 303
Ctrl+o to save the file and confirm with
enter. These lines assign metric values to your WiFi and your ethernet ports. The lower the value, the higher its priority. So, since
202 is lower than
wlan0 (your WiFi port) will be rated higher than
eth0 (your ethernet port) and our system will send web requests via
wlan0 instead. Finally, hit
Ctrl+x to leave
2.4. Reboot your RPi
To allow these changes to take effect, you will now have to reboot your RPi again. We will do this using the terminal:
sudo reboot now
2.5 Connect the RPi to the WiFi network again
Open the browser. You should be directed to the university’s login page now. This means that assigning the metric values has worked! Each group has received credentials for an account on the guest network. Log in using these access data. Once you are logged in, visit any website to make sure your internet is connected.
2.6. Double-check the metric values
Open a terminal and enter the following command:
This command will show you your routing table: a list of all the system’s routing destinations (in the form of IP addresses), that tell the system where to send which data packages. Here you can double-check that the metric value of the
wlan0 interface is now lower than that of the
2.7 Note down your IP Address
As mentioned, we will need the IP address that our router has assigned to our RPi to SSH into the RPi via our laptops. We can find the IP address we need by running the following command:
This lists all your network settings. In the list, find the entry that starts with
eth0 (typically the first one), and note down the first IP address that you see, the one that directly follows the word
2.8. No more peeking!
Now that we have the IP addresses of our RPis, we can finally access them via SSH, using our laptops. That means we will no longer need to look at its desktop. Turn off the monitor that is connected to your RPi.
3. SSH into your RPi
We will now start to control our RPi from a different system (your laptop) using the command line. Since the rest of this tutorial assumes that you know some basic command line commands (and will even ask to write your own commands here and there), this is the point where your tutors will offer you a brief introduction to working in a Linux terminal. At a later point in time, a similar tutorial for training command line basics will be provided and linked here on this website.
3.1 SSH Connect
On your laptop (the one that is connected to the
IIIFarm WiFi) open a Command Line Interface. Here, enter:
and confirm with
On your first login to a new resource you will get a security warning. Confirm by typing
yes. You will be prompted for your RPi’s password. Type in the password that you’ve set up for your RPi, and confirm with
3.2 Creating Files and Directories
At this point, your tutors should have either already put a folder on your RPi’s
Desktop, or prepared a USB-stick that passes around while you complete this exercise. In the second case, when you get the USB, you can turn your RPi’s monitor on, plug the USB into the RPi, and copy the directory with your RPi’s name onto your
Desktop. (The whole directory, not just the files that are inside). When this is done, turn the monitor off again, and continue with the following exercise.
3.3 Command Line Exercise
- Navigate to the
- Create a new directory called
- Navigate into that directory
- Create a new document in that folder, called
- Also create a new directory in that folder, called
- Verify that your
htmldirectory now containes an
index.htmlfile and an
To continue beyond this point, you will need the folder provided by your tutors to be copied to your
Desktop. So wait for the USB if necessary.
- Check your Present Working Directory
- Navigate back to the
- Verify that the Desktop has two directories:
htmland one with
- Navigate into the directory with
- List the contents of this directory
As this list will show, the directory contains 2
.png images, and one
.jpg image. The
.png images are high-resolution facsimile images of random pages of the first draft of Mary Shelley’s Frankenstein. For this tutorial, they are your institution’s pieces of the Monster we are creating.
- Copy these contents into the following directory:
- Navigate into that directory, and verify that it indeed contains these three images
- Rename the
mv. Their new names should be
3.4 Create a HTML document in
First, navigate back to the
htmldirectory on your
Desktop. Now open the
index.html file with
Now you can use the command line text editor
nano to write the following code into the file:
<html> <head> <meta charset="utf-8" /> <title>My Institution's Page</title> </head> <body> <h1>Welcome to [your_RPi_name]</h1> <p>See our beautiful pieces of the Monster:</p> <img src="images/frankenstein.jpg" style="width:300px;" /> </body> </html>
3.5 Creating a HTML Document in
The code we just wrote in
nano is written in a language that your browser can read:
html. This means that if you open it in your browser, it will display the document as if it were an online web-page.
In the code, the following line will load an image from your
html/images directory, and resize it to a
300px in your browser:
<img src="images/frankenstein.jpg" style="width:300px;" />
When you’re satisfied that the file is copied correctly into your command line through
nano, save the file with
Ctrl+o, and quit
4. Set up a Web Server on Your RPi
Now that everything’s set up and we can connect to the internet, we’ll start with setting up a web server on your RPi. This will allow you to serve your content (the offline web page you’ve just built) with other users on your network (here, the IIIFarm) on an actual website.
4.1 Update APT Package List
Before we start downloading and installing packages on our RPi, it’s good practice to first update
apt-get‘s package list – the list of links to the public repositories that our operating system’s app store uses to know where the most up-to-date versions its software packages are hosted. To do that, enter:
sudo apt-get update
4.2 Install Apache 2 (with
Now it’s time to download our software! The web server that we’re going to use is the commonly used
Apache2 webserver. In addition, we also need to install one of
Apache2‘s modules (a kind of sub-software-package) called
apt-get install, you can line up a series of software packages to install them all with a single command. So go ahead and run:
sudo apt-get install apache2 libapache2-mod-fcgid
On running this command,
apt-get will inform you if the software has any dependencies (other software that needs to be downloaded), and tells you how much disk space these downloads will take up on your RPi. You’ll have to confirm with
y, and wait until your packages are downloaded and installed. As we’re all on the same network and the RPi’s aren’t very fast, this may take a while.
4.3 Start Web Server
Once the software is downloaded, we can start it up on the RPi. Run:
systemctl start apache2
Here, you will be asked which user you want to use to run the Apache2 service. Choose
1 (pi) and confirm with
enter. The command line will then prompt you for a password, so type in your RPi’s password and confirm by hitting
The command we’ve just run –
systemctl – is a utility to manage (start, stop, restart) services on your RPi (like the
Apache2 service we’ve just installed). We’ll be using it a lot in this tutorial, so make sure you remember your RPi password!
4.4. Test Apache
Before we do anything else, we’d like to make sure that our Apache webserver is actually running. On your computer, open a browser, enter your RPi’s IP Address into the browser’s address bar, and confirm with
enter. You should now see the Apache2 Debian Default Page. On the top of that page, in a red banner, you’ll read “It works!”
4.5. Viewing Your Website
By default only contents that are in the folder
/var/www/html/ are accessible. Although this folder could be changed (e.g. to your
Desktop, or a folder in your
Documents) doing so is not considered good practice. Instead of relocating the folder Apache points to, we move our content (those files we want to access via the browser) to the default folder.
html folder from the
sudo cp -r /home/pi/Desktop/html/ /var/www/
Now you can enter your IP address into the browser of your laptop. If everything went well, you can load the website from your RPi (which now functions as your server) on your laptop (which funtions as the client).
5. Install the IIPImage Server on Your RPi
In the previous step, we installed Apache – a web server that allows each of us to host web pages such as our own page in
html) and share them within our network. As we’ve seen, we can easily hard-code images into such
html web pages (by providing a link to the image in the
@src attribute of an
<img> tag) – but that is not enough for our purposes. Instead, we need to install a dedicated image server alongside our web server, to process the images on the fly. For that, we will install a IIIF-compliant image server called IIPImage.
5.1 Install the IIPImage-Server
Install the package
iipimage-server by entering the following command:
sudo apt-get install iipimage-server
You will have to download some dependencies (between 50-100MB), confirm with
y and wait until the image server is installed.
5.2 Change the image server’s data directory
By default, the data directory of the image server is under
/usr/lib/iipimage-server/. We want to change this to
/var/www/iipimage-server/. To do so, we have to copy the folder over to
/var/www/ and tell the image server where the data directory has moved. Copy the
iipimage-server directory from
sudo cp -r /usr/lib/iipimage-server/ /var/www/iipimage-server/
To use the image server in our website, we need to run it as an Apache module. Such modules are configured in the directory
/etc/apache2/mods-available/. Change to this directory. Once you are there, we need to open the image server’s config file with
nano so we can make some changes (don’t forget the
sudo!). the config file is called
sudo nano /etc/apache2/mods-available/iipsrv.conf
In this file change the following line:
ScriptAlias /iipsrv/ "/usr/lib/iipimage-server/"
ScriptAlias /iipsrv/ "/var/www/iipimage-server/"
Save the file with
Ctrl+o, and hit
enter to confirm) and close nano (
Ctrl+x). Now once we enable the module, apache knows where we put the image server’s data directory, and the two servers can work together.
5.3 Enable the necessary Apache modules for the image server
First, we want to double check that the
fcgid module is enabled. Since we installed it earlier, this should already have happened by default. Enter:
sudo a2enmod fcgid
You should now see a message that confirms that
fcgid was already enabled. Next, we need enable the
headers module. Enter:
sudo a2enmod headers
If one of these two modules was not enabled before, you will have to restart apache now. In that case, enter:
systemctl restart apache2
Finally, we’ll want to check if our image server’s module (
iipsrv) is enabled too. Enter:
sudo a2enmod iipsrv
Now that all three modules are definitely enabled, we need to restart Apache again. Enter:
systemctl restart apache2
5.4. Enable CORS
In the image servers configuration file we have to enable “cross origin resource sharing” (CORS). It is important to enable this setting to make sure the image server is IIIF-compliant, because it allows others to embed your images into their website. To enable CORS, open the apache configuration file with
sudo nano /etc/apache2/apache2.conf
Move down (arrow-down key
↓) to the end of the file and add the following line:
Header set Access-Control-Allow-Origin *
Make sure there are no spelling mistakes in this line! Save the file (
enter) and leave nano (
And, again, Apache needs to be restarted:
systemctl restart apache2
5.5 Check if your IIPImage Server is running
Finally, we’ll want to make sure that everything is working correctly, and that the image server we just configured is actually running. In your laptop’s browser go to:
If the IIPImage Server start screen appears, your server should run correctly. Well done!
6. Making Pyramid TIFFs for IIPImage
IIPImage needs a specific type of files to work its image serving magic. These are pyramid TIFFs – which are basically layered documents that contain multiple, mapped versions of the same image in different resolutions. This allows the image server to optimise its zoom function, as it switches to higher resolution images as the user zooms deeper and deeper into the document.
6.1. Install Image Processor: VIPS
To convert our high-resolution images into Pyramid TIFFs, we will first need to install another package on our RPi – this time we need an image processor. There are a couple of different options available for this, but we’ll use the software package VIPS. Use
apt-get to install the package
sudo apt-get install libvips-tools
6.2. Find Your Images
Change to the folder
/var/www/html/images/. At an earlier stage, we stored two Frankenstein facsimile images in this folder:
image2.png. Make sure they are still there using
6.3. Transform Your Images
To transform these
.png images into (tiled pyramid)
.tif images, run the following command:
sudo vips im_vips2tiff image1.png image1.tif:deflate,tile:256x256,pyramid
Once you’ve hit
enter, wait until the processing is done. This can take several minutes, because Pyramid TIFFs are huge files.
Once the first image is processed, move on to the second image. Afterwards make sure, both
.tif files (
image2.tif) are in the folder, alongside to the
.png files – which should still be there too.
6.4. Copy the Pyramid TIFFs to the Image Server’s Data Directory
Just like Apache stores the accessible documents in a specific data directory (
/var/www/html), our IIPImage server also has a directory where our images need to be stored. Earlier, we’ve set this directory to
/var/www/iipimage-server/. In order to make our images accessible via the image server module (and not only via apache) we have to copy (
cp) them into this folder.
sudo cp image*.tif ../../iipimage-server/.
../../ only works as long as you are in the
/var/www/html/images/ folder. It would not lead to the correct target from any other
pwd. An alternative would be to use an absolute path.
7. IIIF Parameters
Now that we have set up IIPImage, you can access all of the images in your
var/www/iipimage-server directory in any browser or IIIF-compliant image viewer – such as Mirador, Universal Viewer, OpenSeadragon, or Leaflet-IIIF.
7.1. Accessing Images in the Browser
When you call an image via an IIPImage server
URL, the image server will show you this image according to some parameters that you have set in the
URL. Let’s have a look at how this works.
Open your browser (on the laptop!) and go to:
Now, open another tab in your browser and go to:
URLs show you the same image, but not in the same way. Compare the
URLs above and try to find out how it influenced the server’s presentation of that image in your browser.
7.2 Experiment with the IIIF Image API
The IIIF consortium provides a detailed documentation of the IIIF Image API’s parameters here. Have a look at this documentation, and play with different settings for your images by manipulating the
URL in the following exercise:
Reading up on the IIIF parameters, find out how to:
- Rotate your image by `180` degrees
- Retrieve **only a section** of an image
- Retrieve an image with a width of `5000px` and a proportionally scaled height
- Retrieve an image with a `width` of `100px` and a `height` of `300px`
- Display your image in `greyscale`
7.3. Get the `info.json` from your image server
All the information you need to build tools that show your images work on the basis of a
info.json file, which is generated by the server for every image. To view this file for your own collection, enter the following
URL into your browser:
When no further IIIF
URL variables are specified, the IIPImage server will forward you to the
7.4 Accessing Each Other’s Images
So, each of us now has a fully functioning RPi with a web server and an image server that provide access to a couple of tiled pyramid TIFF images that we have learned to access and manipulate] with the IIIF URL parameters. And since all of our RPis are connected on the same network, we can use the same technology that allows us to view and manipulate the images on our own RPi in the browser of our own laptops allow us to do the same with each other’s images too.
Ask your neigbour to give you the information you need to build IIIF compliant URLs for their images. Then try to view and manipulate their images using the IIIF parameters
We will need
URLs like these going forward. So save some of these URLS on your laptop somewhere (like a
.doc file), so you will be able to copy and paste them.
8. Reusing IIIF Images
Now that we have a series of links to images (our own as well as our neighbours’), we can embed their
URLs into our
html page to incorporate them in our websites.
8.1. Include Images in your
html Web Page.
index.html file we created earlier with
sudo nano /var/www/html/index.html
In this file, add the following two lines after the
<br/><img src="your.ip.address/iipsrv/iipsrv.fcgi?IIIF=image1.tif/full/400,/0/default.jpg" /> <br/><img src="your.neighbours.ip.address/iipsrv/iipsrv.fcgi?IIIF=image1.tif/full/400,/0/default.jpg" />
Copy these links carefully – although you will of course have to to change the IP addresses in these
URLs with the ones you came up with earlier.
index.html file (hit
enter) and exit
Ctrl+x). Then enter your RPi’s IP address in your browser (on the laptop!) again, and look at the effect your changes had on your website.
8.2 IIIF Manifests
So wouldn’t it be nice if we could also embed additional metadata about each image (or even an entire collection of images) directly from the server of the image provider? In a computer readable, standardized format? This would allow us to give credit where credit is due. And if the original hosts have enriched their images in any way (with dates, transcriptions, annotations, etc.), we might want to reference those, or reuse them in our website in some way too. IIIF provides a solution for this: IIIF Manifests. This is a container file (in the
JSON format), that contains metadata about an image collection as well as the IIIF compliant
URLs to the contained images. For now, we will only look at a simple example, in detail we will learn about manifests and IIIF compliant image annotation later.
8.3 Download A Sample Manifest
Here again, you will need to follow your tutors’ instructions to download a sample manifest for your collection – or download the one we used in class here.
8.4. Adapt the Manifest to Your Needs
At this point, you don’t have to understand the file you’re reading in
nano. Instead, just replace all instances of the string
MY_IP_ADDRESS with your actual IP Address.
Warning: If you make a mistake here, your manifest will not work later. There should be 10 instances for you to replace. Go through slowly line by line.
When you are done double-checking, go through the file again, looking for the line
"label": "Team [PI Name]", (line 9). Now, replace the string
[PI NAME] by the name of your Raspberry Pi.]
Once you are done, save (hitting
enter) and exit nano (
8.5 Double Check that the File Loads
Check in the browser if your manifest is publically accessible. Open the laptop browser and enter:
JSON file should load in your browser.
This is the point where we’ll really start taking advantage of the interoperability features IIIF has to offer, as we’ll aggregate, mix and match each other’s images. You’ll effectively be assembling your own “Monster” out of the Frankenstein manuscript images you and your peers are hosting. To do so, we’ll be working more with IIIF Manifests, so depending on your (and your peers’) technical background, this would be a good point for your tutors to introduce the basics of the
JSON data format.
9.1 Loading Manifests in Mirador
On their laptop, that is also connected to our IIIFarm, your tutors will also has a version of Apache running, that should make data from his laptop accessible to you. In his web-shared folder he installed a version of Mirador, a IIIF compliant image viewer with a couple of nice features such as deep zooming. But one of this viewers coolest features is, that you can load IIIF manifests dynamically if you have the
URL of the manifest. Luckily, each team knows the
URL of their manifest, you have just entered it in your browser. Lets load them all – one by one – in Mirador.
Follow your tutor’s instructions to load their Mirador instance on your own IIIFarm-connected laptop and add your own manifest. Play with the viewer. Make yourself familiar with the functionality it provides. Then load some of the manifests of other teams into the viewer too.
9.2 Adding Metdata to the Manifest
At this point, your IIIF manifests do not yet provide a lot of metadata. Let’s first experiment by improving what is there already. Open your manifest (
nano and edit the existing
Warning: Try not to change the file’s structure and don’t change the
What you enter here does not have to make sense for now, but whenever you change something, save the file (hit
enter – but don’t exit nano!) and reload your manifest in the Mirador viewer.
Try to see how mirador views the
JSON data you changed. Which change is visualized where?
On the initial image folder we gave to you (
.png imagess still had individual names. Their name (a number) was the position of the image in the sequence of the entire notebook. Try to get this information into your canvas information. For example: if your files were called
024.png, make sure that your canvas for
“Page 23”, and
image2.tif would correspond to
“Page 24”, etc.]
9.3. Including Other Teams’ Manifests
- Study the canvas area of your manifest. Open another team’s manifest and look at their
JSON. Find their canvases.
- Figure out if their two images should come before or after your own images.
- Try to copy their canvases from their manifest into your manifest: find the right position to add their canvases (either before or after your own canvases) copy them there.
- Load your manifest again in mirador. Did it work? If not… debug!
- Add the canvases of at least two other teams at the correct position in the sequence.
9.4 Finding the Missing Information Online
Maybe you would be happy to have more real metadata in your manifest. Luckily, the Shelley Godwin Archive recently published the entire notebook in IIIF. Here is the corresponding blog post:
Can you find the manifest? You cannot load it in our instance of Mirador (because we don’t have internet) but you can load the
JSON manifest on your internet-connected laptop and use the given information to improve your own manifest to your heart’s content.
That’s it! You’ve now successfully installed a IIIF compliant image server on a RPi, shared images, and mixed, matched, and manipulated those of your peers. At this point, you should also be able to set up a similar environment for your own project on a Raspbian or Debian (Linux) system.
The summer school’s first edition was generously sponsored by the University of Antwerp’s Literature Department, the Antwerp Summer University, the Flemish Government’s Department of Economy, Science, and Innovation, Digital Humanities Flanders (DHu.F), and DARIAH-BE – the last of which provided us with the course’s hardware and the opportunity to develop these tutorials further. The development, teaching, and dissemination of this tutorial falls under the purview of the CLARIAH-VL project’s WP2 on Community Engagement, User Involvement and Training.
These tutorials are published under a Creative Commons Share Alike licence (CC-BY-SA 4.0). This means that you can re-use (share and adapt) these slides provided you provide sufficient attribution and publish and distribute the result under the same license.