This article was written in 2014. It might or it might not be outdated. And it could be that the layout breaks. If that’s the case please let me know.

About Voto, my self hosted IndieWeb photo gallery

A few months ago — inspired by the Indie Web Camp movement — I decided to create my own photo-site. I’ve tried many self-hosted gallery scripts before, but they never did what I wanted them to do. Many of these script have a bad case of feature creep, while others lack some essential features. And all of them are slow. During a two week period between jobs I wrote my own script. I’ve been using it since and I’ve posted more than 320 pictures on it. It’s not open source — I’m not a good programmer so I don’t think it’s safe to share this code. But I guess sharing my ideas might help others in creating something similar.

Basic architecture

Uploading and viewing are two separate parts of the application. I did this because I know nothing about security. The upload script is hosted at an unrelated URL. You can’t guess it from looking at the URL when you’re browsing through my site.

The image viewing part of the site is an almost static site. Most of the documents are static HTML pages, but the image-pages themselves have one small dynamic function: I created a simple responsive images solution with client side and server side cookies.


I wanted to be able to upload a photo from any computer. In my case this will mostly be my own phone and my own laptop. So I have this URL where I can pick a photo and upload it to my server. Once it’s uploaded a screen appears where I see the image. I’m then forced to give the image a title, a caption, some keywords, and to choose a category from a list. All images are published under a CC-BY licence, but if I want to I can overwrite that option with a checkbox. There are no other options. That’s all. It’s not possible to upload a bulk of images at once, since I think every single image needs a bit of attention. This metadata is then published inside the image, in the so called IPTC tags.

Publishing the images

After uploading the image a lot of things happen.

  1. First of all images of different sizes are generated. Sixteen different sizes to be exact. All IPTC data is saved inside of all of these images.
  2. The HTML for the homepage is generated
  3. If necessary, paged archives are generated too.
  4. All cached HTML for detail pages is deleted, because next and previous links need to be updated.

Naming the images

The name of an image consist of two parts: First a string representing the date, and after that the title of the image: 140513132524-tierlantijntjes.jpg. This way I’m sure each image name is unique, even if the title is the same. The URL to a detail page is the other way around: first the title, then the date string: tierlantijntjes/140513132524/

Generating detail pages

The HTML for the detail pages, the pages on which the individual images are shown, is generated when somebody visits that page. So if you are the first person to visit a page after the cache is purged, it will be a fraction of a second slower. I haven’t been able to notice the difference. The default image size on this generated page is 1024px. This can be overwritten by the cookie I set every time you visit a page. This cookie stores your viewport size. This means that the first time you visit my site you’ll see an image of the default size. The image will be optimised if you keep browsing.

Generating the home page

There are at least 40 images on the homepage, and at most 79. On each paged archive page there are 40 images. More than 80 images could make the homepage too slow on crappy network connections. Most images have a longest side of 320px. This is usually good enough for the multicolumn layout I chose. In case of extremely high images, a bigger image is chosen. What you see on the homepage is a series of links with a background image, with the background-size set to cover. Most links will show the center part of the image in a cropped square. Extremely wide images have a max-height set on the server. Otherwise they would become too pixelated.

Generating paged archive pages

Most blogs make a mess of paged archive pages. If you go to /page/2/ on any active blog on one day, and come back a few days later all content will be different, which doesn’t make any sense. Not on this site. All images on page 5 will always be there. I wrote about how to create logical paginated archives a while ago. If you’re interested you should read it.


Apart from the necessary HTML pages an RSS feed is created. This enables people to stay up to date if they want to, but it also enables me to publish my images to services like Flickr. And since all metadata is saved inside the images, it’s also shown on Flickr. If people feel the urge to leave a comment, they can do so over there. There is a link back to the canonical URL at the end of the description in the RSS feed.

Viewing the site

There are some things I think are important when viewing a gallery. It should be easy to browse through the images, you need to be able to read the caption, and it should be nice to look at. Of course this will be changed whenever I change my mind.

The homepage

I used a multicolumn layout for my homepage. A simple columns: 15em; does the trick. And I like the trick a lot. A long list of images is usually presented in a simple linear way, just like text. From left to right, with rows added at the bottom. Multi column layout goes from top to bottom, with columns added to the right. What I like about it is that older pictures resurface every now and then. In the classic linear layout the disappear forever.

The detail pages

The images have a max-height: 90vh;. This means you will always be able to see that there’s a caption below it. The background colour of the page is the average colour of the image. As I wrote in the Publishing the images section I generate 16 different image sizes. One of these sizes is a 1×1 pixel image, which is the average colour of the image. It’s pretty easy to pick this colour with PHP. I also use this colour to set the background-colour of all links on the homepage. This looks beautiful when you load the page on a slow connection.


When you’re on a detail page you can go to previous and next page by clicking on the left and right 10% of the viewport. These areas are invisible. I know this is not optimal but I dislike arrows or other visual clutter. On every detail page there’s a so called hamburger icon — its size is related to the viewport height. If you click on it you’ll find an explanation of the basic navigational patterns on the site, and you’ll find a link to the homepage. I also explain a few keyboard shortcuts you can use to easily navigate the site. I like these shortcuts so much, and I use them so often that I miss them on the rest of the web. Most of these shortcuts work on the homepage as well, but I chose not to show the hamburger there. By pressing the letter q you’ll see all the shortcuts.

Editing and deleting

After a while I needed to change an image. This was hard to do so I created a bookmarklet. When I use this bookmarklet while I look at the page I want to edit, the original image is uploaded to the upload script. I can now edit the meta-data.

I created a separate page where I can delete individual images. It looks exactly like the home page. But here, if I click on an image I’m asked if I really want to delete it. I should probably change the background to red, because I’m always confused if I’m on the homepage of the deletion page.


  1. Nice write-up, some lovely little features. Great also to hear of your reasoning behind certain choices. By the way the Voto homepage is the first place where I’ve noticed that Chrome seems to wrap the block-level hyperlinks differently than Fx.

    At first I thought it broke up the images just as it would do with text. But then I realized the images are backgrounds :) For some reason, however, Firefox moves the whole 15em heigh block-level link to the next column. Interesting stuffz :P