Easy Redirect Links Within Jekyll

These hacks are safe for all ages.
May 06, 2018

I am buttoning up the final touches on my new Jekyll-powered blog. One thing I wanted to attempt without having to spin up yet another app or service was short link redirects.

My goal was to be able to take http://johnathan.org/goto/something and have it redirect to a full URL of my choice. Jekyll is trigger happy with creating a page for everything. I knew I had to find some way to manage the data long term.

Forestry offers the ability to manage arbitrary data sets within Jekyll. Since I’m using it, I knew it was going to be a breeze so that’s the path I took.

I first started by creating a new file in the _data folder called shortlinks.yml. Anything I plug into this YAML file becomes an extension of the site object. My data file has three fields per entry: title, key, and destination. The title and destination are self-explanatory. The key is the short URL keyword. This is what we’ll use after /goto/ in the path.

Having these fields in mind, my shortlinks.yml would look something like this:

- title: A cool page
  key: coolpage
  destination: https://google.com
- title: A mediocre page
  key: mehpage
  destination: https://bing.com

This means I can now access my links under the site.shortlinks array by iterating over it. Unfortunately, we still have a bit of a roadblock. Since everything about Jekyll is static, I can’t create a dynamic page that would access the data. Wwll, I could, like something in PHP, but I don’t want to. Instead, we’ll have to use the data as a base for a set of pages we’ll create that act as redirects.

This is like how Jekyll Collections work, except we don’t want to create the pages ahead of time, only on jekyll build. This is where data_page_generator.rb comes into play. By placing it in_ _plugins and feeding it a few settings in config.yml, we can instruct it to build pages based on shortlinks.yml.

That code would look something like this:

page_gen:
  - data: shortlinks
    template: redirect
    name: key
    dir: goto

Seems easy enough. Let’s break it down. data is the data file we want to use. It makes assumptions about the file type. template directs the plugin what base template to use. What that template looks like is in the next section. name is the key from earlier. This is the file name that we create within the dir directory. In this example, the redirect files land as _site/goto/key.html_, provided the base directory is _site.

Now that we have the configuration squared away, we need to create an _includes/redirect.html template. Since we’re doing immediate redirects, it doesn’t need to be fancy, nor does it need to have style. This will do:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta http-equiv="refresh" content="0; url={{ page.destination }}" />
  <script type="text/javascript">
    window.location.href = "{{ page.destination }}"
  </script>
  <title>Redirecting...</title>
</head>
<body>
Redirecting to {{ page.destination }}. If it doesn't load, click <a href="{{ page.destination }}" />here</a>.
</body>
</html>

data_page_generator.rb will take each object in the data file and pump the values into this template. In our example, we’re only interested in destination.

With our template set, there’s one last thing we need to do.

You might need to make a tweak to convince it that /goto/something and /goto/something.html are alike and not return a `404 (dependent on your Webserver configuration). In my case with Nginx, all I had to do was swap:

location / {
    try_files $uri $uri/ =404;
}

with

location / {
    try_files $uri $uri.html $uri/ =404;
}

For those following along at home, all I added was $uri.html. What we’re doing is instructing Nginx to take the presented URI–in the case of /goto/something, the URI is something and try it against something by itself, then something.html (this is what we’ve added), and finally something/ before giving up and looking for a 404 page. If it matches something, try to render it no matter what.

Now, we can push everything and give it a go. In my real-world example, I have a couple links already set up as I write this. My new favorite air purifier/filtration system is Molekule so clicking that link will take you straight there.

Long-term, I’m uncertain about this solution’s long-term scalability. This will be fine on the scale of a few hundred links as Jekyll can turn through a few hundred pages in a matter of seconds (especially when paired with Ruby >= 2.5.x). How well this works long term will come down to a couple things:

  • The effort required to manage the data file
  • The tools in place to automate the building of the Jekyll site

For the latter, I use Circle CI so I’m fine with it taking a handful of seconds or even a half-minute longer to update. For the former, I use Forestry. I haven’t pushed it to the point where it has several hundred items in the shortlinks.yml data file. The limits of its capability are unknown in this regard.

My alternative plans were to move to Bit.ly (using a short domain of some sort) or setting up Polr on the server. I’ll have to spend some time thinking about how I can track clickthroughs. As I wrapped this up, I pondered plopping Google Analytics on the redirect page. This allows me to measure the movements into /goto pages as clicks.

I’m happy with how this turned out. Like all things I do, there’ll be persistent tweaking involved.

more about:forestry / jekyll / nginx / ruby

An Auto-deploying Static Site with Backend

On a journey to simplify things
May 05, 2018

I have some nostalgia for static sites. I first learned to write any kind of code with HTML on a Packard Bell 486. I was hooked.

Fast forward a couple years and I was creating HTML sites in Allaire HomeSite (which became Adobe HomeSite and eventually Dreamweaver… R.I.P. HomeSite). It wasn’t long before I discovered CMSes–PostNuke, PHPNuke, TextPattern, MovableType, WordPress–I loved them all. Over the last half-decade though, WordPress was where I settled. The thought of going back to a static site was intriguing and I even tried it once, but I just couldn’t get it to stick.

Fast forward to now, where I’ve thrown WordPress to the side for a static option. I wrote this post to discuss my motivations behind it, especially after talking about–at length–why I left Ghost.org for WordPress.

Moving Parts

Beyond all else my primary motivator was complexity. As much as I’d like to think this would change, I don’t blog often, nor do I have a highly complex blog that requires a lot of input by multiple people. Naturally, one might think about going to a hosted solution like WordPress.com or Squarespace. Both were options I toyed with in the past and turned down as serious options.

WordPress.com costs more money than I think it’s worth and Squarespace isn’t blog-centric. It’s a great product and you can build awesome sites that have blogs as a component, but it just doesn’t have that “this is your place to share your thoughts” vibe I’m looking for. Beyond that, I have almost 300 posts (it used to be closed to 340, but I purged a bunch that were so out-dated and broken it wasn’t worth saving them) and I didn’t feel like that much imported content is something SquareSpace could handle well.

This led me to self-host WordPress. I enjoy setting up and maintaining servers as much as the next person, but my bill was higher than it was worth. I had deployed two DigitalOcean droplets, one for the database and one for the web server. At $20 each, (4GB ram, 80GB SSD) it was getting pretty pricey. I could have scaled down and even put both functions into one server, but even then I wouldn’t have felt comfortable spending any less than $20.

I would vouch for Digital Ocean all day long, though. They’re great people to work with–I know at least one of them personally–and their UI is prefect for my needs.<div class="alert alert-success" role="alert"><div class="far fa-thumbs-up alert-icon"></div><div class="alert-message"><p>Side note: use that link and you’ll get $10 in credit when you sign up. That’s 2 months of their entry VPS (1GB RAM) for free.</p> </div></div>I had to really think about my plan. If I was going to go back to static, I needed to pick a tool that I wouldn’t end up hating six months from now. My answer was actually several tools.

The Toolkit

I came up with three pieces to complete my static site solution:

  • Jekyll: it’s Well-known and something I’m very familiar with.
  • Circle CI: making sure what I’m pushing is legit and let me auto-deploy… no more git hooks)
  • Forestry.io: I like using editors as much as the next guy but if I have something I want to write about, taking the extra steps to push it up to GitHub isn’t going to cut it for me.

Jekyll

Jekyll seemed like a no-brainer. Hugo was out of the question because I didn’t want to learn something new and others just weren’t full-featured enough. With my passable ruby and liquid knowledge, I could manipulate Jekyll to do what I want and not want to give up and throw it all away.

Circle CI

Circle CI came late in the game. I was originally going to use Netlify to deploy and host my site but I didn’t like how little control I had. Yes, it’s free as in beer, but I didn’t have any kind of insight as to the performance or overall control. Beyond that, deployment took longer than I wanted, primarily because it spends time at the final stages checking the HTML for forms it needs to process and understand. Given that I have over 300 pages–probably more than 400, actually–that was a non-starter. I’d probably use Netlify at work, but not for this project.

By having an CI tool at the ready, I could have it build the Jekyll-based site for me, check the HTML for obvious problems, then push it to my server (in fact that’s what it does–minus the HTML checking part, that’s not ready).

Forestry.io

Forestry.io is a tool I never heard of until a few weeks ago. It syncs with the GitHub repo that stores my site and allows me to create posts and pages, manipulate front matter templates, and do some basic media uploading. It’s not perfect, and on rare occasions it trips GitHub’s API rate limiting, but it’s been pretty solid overall. Support is good, and the free tier does exactly what I need it to, nothing more.

Performance

With these three tools in play, I have what amounts to a static site-CMS hybrid. When I click Publish on this post, Forestry will push it into my GitHub repo. From there, Circle CI will trigger when it sees a change and run my build script. The last step of that script is to rsync the built HTML site over to my server.

On my server, I have Nginx serving the pages with some effective caching and it’s smooth. By extracting WordPress and it’s PHP+MySQL clusterfest, I’ve also been able to improve load times both in the context of first-byte and the entire page.

My PageSpeed and YSlow scores are better than they used to be when running WordPress. There’s room for improvement but overall, it’s turning out pretty well when I consider the fact that I haven’t gone out of my way to make them great.

One thing I really need to work on, though, is my Lighthouse performance. This is what I would say is going to be the successor to PageSpeed. It’s really tough on sites and my performance as it’s measuring is dismal. Some of that might be the extensions Chrome is running and removing them speeds things up a bit, but I definitely have some front-loading I need to do of critical CSS and moving the rest to the back.

Overall, though, I’m happy with how things are operating. Forestry is fast, the whole thing can be done for $5, and I can feel good knowing that my site can’t be taken over thanks to a vulnerability in WordPress.

more about:circle ci / forestry.io / jekyll / static sites

Yet Another Re-design

I couldn't help myself.
April 25, 2018

If you had asked me a few weeks ago if I would be re-doing my blog again, I’d think you’re nuts.

You’d be right, though.

Through the process of making this version happen, there were several occasions where I pondered if I even wanted to do this. WordPress is working fine, I kept telling myself. That’s not an untrue statement.

I wasn’t happy with the overall look and feel, though, and I dreaded the idea of spinning up another development environment to re-create the theme. I hated creating the last one. It was always so complicated and PHP is a shitbox.

Recent professional experiences suggested I give Jekyll another go. It’s been a couple years since I attempted to shovel my blog content through it. Over that time period, Jekyll got faster and Ruby as well. Last time I was running this blog through Jekyll, I had to set up git hooks to do stuff after I made changes. ~~Now, I can consider the likes of Netlify to take care of the heavy lifting for me.~~ I added auto-deployment functionality by way of Circle CI so every time I push a change, the rendered site is rsynced to my DigitalOcean server.

Heroku was on the table as I’ve had more experience with them and they’re good people, but they have a hard limit on app size of 500MB. I have a lot of images and I haven’t figured out how to offload those to S3 exclusively so they’re out of the running.

I could probably trim down the image quantity and size, but where’s the fun in that? Not to mention I’d always have the looming 500MB limit over my head. Netlify doesn’t seem to have that.

The final decision hasn’t been made yet as to whether I use Netlify or if I take another crack at self-hosting. What makes the decision hard(er) is that also since I last tried all this, Forestry became a thing. I love the concept of a static site/GUI combination and Forestry handles the GUI content creation piece wonderfully. It’s snappy, clean, and does one thing well.

I’ll have some contemplations in which to engage and some testing to do, but I suspect I already know where things are at least heading… and that’s away from WordPress… and PHP… and that terrible templating system. Viva la Liquid.

more about:cms / forestry / heroku / jekyll / netlify / static site generator

Hi friend. What's your email address?

...or follow the RSS feed.