Personal website: travel blog, photo gallery, projects

screenshots of the different website sections
Screenshots of the different sections of my personal website. Clockwise from top left: Homepage, Making Trails, Photo Gallery, Projects

This Projects site is but one section of my personal website, I built this entire website using the static site generator Jekyll, then figured out how to host the site online.

Source code for my travel blog, Making Trails, is hosted on GitHub. Source code for the rest is not yet publicly viewable.


I traveled extensively last year and wrote many blog posts about my adventures. I used a Blogspot blog as a platform for my travel notes, but I became increasingly frustrated with its limitations. Blogspot was good for being able to publish posts from anywhere in the world (a hostel in Bangkok, or a remote village in northern Vietnam), and I could easily add and update content through the web interface. However, there were so many ways I wanted to customize the site—so many ways I wanted to modify the fonts, the colors, the landing page, the links. My solution to these problems was to teach myself to build a website from scratch, and port all my blog content to a new self-hosted platform.

I created my personal travel blog using Jekyll, a static site generator. In the process, I taught myself to write easy-to-maintain CSS and HTML, learned about SSL certificates, and figured out how to configure a web server.

After finishing the travel blog, I decided I liked my photos enough to publish a photo gallery, and then decided to move those into subdirectories and make a landing page for the site. Two weeks ago, I decided I needed a place to write about my various projects—I created the Projects site that you’re looking at now.

What is a static site?

A static site is the simplest type of website, consisting of static (not modified during runtime) pages of HTML. With a static site, there is no option for customizing web pages for different viewers, and there is no stored user state. Every visitor to the site receives the exact same content as all other visitors.

Static sites are generally fast to interact with and easy to setup. Unlike dynamic sites where the server needs to compute runtime-specific information before sending a page to the viewer, all possible pages in a static site are precompiled. When a visitor to the site requests a particular page, the web server simply returns the file located at the requested URL. Because of this, the server can be incredibly basic, as it only needs to know how to serve static files.

For a static site, the website URL matches the server-side folder structure. For example, the URL of this page,, reveals that this page is in the folder /personal-website/, which is filed under two layers of date-related folders, which is located in a folder called /projects/ in the site’s root folder.

Static site generators

A static site generator does exactly as the name suggests: it is a tool for creating static HTML pages. A generator is run once to create a folder structure of web pages that represents a website. Those compiled web pages then need to be copied onto a web server.

I built my websites using Jekyll, which is a Ruby-based static site generator designed for building blogs. However, there are a million other generators that are written in other programming languages, optimized for different types of sites, or designed with different opinions on input data types.

Jekyll defines layouts, or web page templates, such that a developer can use a single template file to apply uniform formatting across multiple web pages. Templates eliminate the need for code redundancy; this greatly improves maintainability and eliminates the chance that, when publishing new content, you forget to include the site logo at the top of the page.

Here is a basic HTML page template:

<!DOCTYPE html>
    {% include meta.html %}
      {% include header.html %}
    {{ content }}
      {% include footer.html %}

When a page is generated using this template, Jekyll inserts the contents of external files titled meta.html, header.html, and footer.html. The unique content of a page that is rendered with this template, for example the text of a blog post, is inserted in place of {{ content }}. When the content of header.html changes, those changes are immediately applied to all HTML pages generated with this template (and pages rendered with other templates that use header.html).

Implementation notes

Jekyll config acts like a single website, but is actually generated using four different Jekyll sites (the drastically different color/font/layout schemes should be a dead giveaway *). The generated output of the four projects is copied onto the webserver and placed in the appropriate subdirectories. For example, the generated file structure of the Making Trails site are copied into the server folder srv/www/making-trails/.

* The website taken as a whole is not a paragon of cohesive design. However, I believe that the individual sub-sites are examples of intuitive and thoughtful design. From a technical perspective, I appreciated having multiple opportunities to design a complete site without needing to conform to old design decisions; my technical skills improved dramatically throughout the process. I learned so much more about good layouts (in terms of both user interface and code structure) than if I’d made one site to serve all my needs.


I used Jekyll purely for its templating abilities. The generated site consists of only three pages: home, contact, and contact success page.

Making Trails:

The travel site is built like a typical Jekyll blog, with the added ability to see lists of all posts from a particular country (implemented using Jekyll tags).

Images are processed in and exported from Lightroom. Image layout is accomplished using the JavaScript library ChoosyGallery, which allows the writer to specify per-image display size preferences.

This site is built around the concept of Jekyll collections; every picture is part of a single collection, and the site will eventually contain multiple photography collections. A Rake script iterates over every picture. For each picture, the script generates an ASCII file containing YAML front-matter with extracted EXIF information, and generates copies of the image at smaller resolutions. The height and width information from the EXIF data is used to preserve image aspect ratio in the tiled lists of image previews. EXIF date, location, and camera details are displayed on individual image pages.

All images are processed in and exported from Lightroom.


This site ignores the Jekyll concept of posts. Instead, all projects are part of a collection, which allows me to bypass Jekyll’s opinions about input file locations. Collections enable me to put all unique content for a single project (text, images, etc.) in a single folder.

I wrote Ruby plugins to generate pages for individual tag lists and to process the tags for each project. I wanted a nested hierarchy of tags, and I wanted parent tags to list all projects matching their children tags. For example, in the following tag hierarchy, I wanted /web-dev/ to list all projects tagged Web Development, Rails, or Static Sites. Navigating to /rails/ though would only list projects tagged Rails. I also only wanted to tag each project once, for example with the tag Rails, but not with the tags Rails, Web Development, and Programming.

My plugins accomplish all my desired tasks. I also wrote a Ruby plugin to automatically generate the tree of tag links on the homepage.

Other notes:

Hosting details

There are existing solutions, such as GitHub pages and Netlify, that will host your static website. Remember what I said about static sites requiring fewer server-side resources? It’s economical for some companies to offer free (or very very cheap) hosting solutions. However, I wanted to figure out how to host my website using my own (rented) cloud-based solution.

Contact form

I wanted to allow readers to contact me. I wrote a Python CGI script that generates an email from the contact form, and sends the email to me via Mailgun.

Indispensable web development resources

A Google search will turn up Stack Overflow questions, GitHub projects, and random developer blogs. All three can contain useful information.

Where’s the site?

You’re looking at it! Click on the “LN” logo (at the top of the page or below) to see the homepage, and explore some of the other links.