How and Why, I use Pelican

Posted on Sat 24 March 2018 in site

Coding for the Cloud

The purpose of this site is to produce and share content with others. I wanted something that was quick/easy to use, looked nice, had a low up front investment or CapEx, and low OpEx. All I needed was a way to put my words on the screen and a way for people to interact with their own words.

When I initially began writing web applications, I thought "Hey, I'll just build my own blog with ." A few ugly, unused blogs apps later, I realized that this route was too much up front investment. As of recently I've taken it more seriously because I see the value in releasing my content. At one point I had almost broke and said "I'll just toss WordPress into a container. It's got everything I need and a low CapEx." Luckly a co-worker slapped me back to reality, forcing apon me the gravity of what I was saying. Don't get me wrong, WordPress is great. /s For my scenario, the OpEx of running WordPress is too high, and that lowers my return on investment.

The same co-worker with the nasty backhand recommended checking out some of the newer static site generators. So I did, and I liked what I found. This pattern made sense to me, Git is my content database, I focus on the content, the platform builds to static HTML, and it deploys like a modern day web front end. I had looked at and tested a few including, Jekyll, Pelican and the like. I gravitated more towards Pelican because of it's application stack being Python and Jinja2 which I use regularly and feel comfortable hacking to my liking, so I went for it. After a few hours, mostly spent looking through theme options, I had a blog that looked nice, and built and deployed easily.

Choosing Static over Dynamic

I choose to use a static site generator for a number of reasons.

  1. I had a setup in minutes.
    • Pelican is extremely easy to set up, I'll show you in this blog.
    • Pelican is extremely easy to add content to, I write in markdown which feels native,
  2. Little to no maintenance.
    • There's no application server or database to maintain.
    • I build and maintain application and database servers as a profession, I don't need to spend my off hours doing the same.
  3. Performance.
    • Because it's static and behind a CDN, I'll never have performance problems.
    • Reddit Ready: A term I coined when working on large CMS deployments. Content sites need to be able to handle a huge sudden influx of requests and not fall over. If one of your posts finds it's way to the front page of the Internet and the site can't handle the load you'll organically fall off that front page pretty quickly.
  4. Cheap hosting.
    • The blog is hosted out of AWS S3, served with AWS CloudFront. I only incur costs when my site is being used, and at that it's minimal. I don't pay for an active server running 24/7.
  5. High Availability.
    • As the site is ran out of S3, and cached by CloudFront, my site is highly distributed without a single point of failure for the cheapest way possible.
  6. Security.
    • It's a flat HTML site, no puts, no posts, no wordpress/drupal/joomla/(insert other cms) vulnerabilities.
  7. The content isn't dynamic
    • In modern day web application architectures you serve all static content, as static content.
    • When I need something dynamic I'll use this static HTML and JavaScript to fetch it.

Choosing Pelican

Coding for the Cloud is a static site built using pelican. Pelican is a static site generator powered by Python. I'm not sure that I'll always be using Pelican but for now it's working well. In this section, I'll explain how I got setup with Pelican.

Installing Pelican

I installed Pelican through pip. For this you'll need python and pip installed.

pip install pelican

Setup a Pelican Project

The python module you installed when installing pelican created some command line entry points. One of those is a quickstart tool to initiate a project. Use this tool and it's command line based wizard to start your first blog.

pelican-quickstart

You'll be prompted with a number of questions, fill those out as appropriate. You will be prompted for your deployment mechinism to enable an easy way to deploy changes to your blog. Below is an example of what the quickstart will prompt you with.

Welcome to pelican-quickstart v3.7.1.

This script will help you create a new Pelican-based website.

Please answer the following questions so this script can generate the files
needed by Pelican.

> Where do you want to create your new web site? [.]
> What will be the title of this web site?
> Who will be the author of this web site?
> What will be the default language of this web site? [en]
> Do you want to specify a URL prefix? e.g., http://example.com  (Y/n)
> Do you want to enable article pagination? (Y/n)  
> How many articles per page do you want? [10]
> What is your time zone? [Europe/Paris]
> Do you want to generate a Fabfile/Makefile to automate generation and publishing? (Y/n)  
> Do you want an auto-reload & simpleHTTP script to assist with theme and site development? (Y/n)
> Do you want to upload your website using FTP? (y/N)
> Do you want to upload your website using SSH? (y/N)
> Do you want to upload your website using Dropbox? (y/N)
> Do you want to upload your website using S3? (y/N)
> Do you want to upload your website using Rackspace Cloud Files? (y/N)
> Do you want to upload your website using GitHub Pages? (y/N)
Done. Your new project is available at ...

After you've completed these questions you'll have a blog setup at the given directory.

Generate Content

You'll first want to add some portion of content. All content lives in a directory named content. Start by creating a file in that directory. ./content/first-entry.md

Title: First Entry
Date: 2018-03-24 09:35
Category: site blog
Tags: generic
Slug: first-entry
Authors: Derek DeJonghe
Summary: This is a test article

# My First Header

Info about my blog!

The first few lines are used by pelican to describe the article. This is a good set of them but not all of them. After that you can start your content. This example is in markdown. Pelican takes markdown, and restructured text. Pick your flavor, if you're used to something else and want to use that you can use a toold called pandoc to convert most plaintext formating standards to another.

Build and View

To build your fresh content into an HTML site, use the make file created by the quickstart. There are many commands you can pass to make, for building the HTML we'll use the html command.

make html

This command will build your project and by default output the static site to a directory named output.

Note: This would be a good time to add output/* to your .gitignore

To view your blog you can either open the files with a web browser, or use the make file to run a small web server. Either way is a good way to preview, but beware that going forward any full path links and or images will render as so.

$ make serve

Now visit http://localhost:8000/ to see your new blog. Probably looks pretty pain, and that's alright, next we'll add a theme.

Adding a Theme

To add a theme you'll first need to pick one. Check out the offical Pelican-Themes repo. I started out with Flex by Alexandre Vicenzi.

The general workflow of installing a theme is as follows:

  1. Pick a theme.
  2. Fork/Clone the repository.
    • If you like, make it a submodule of your project, this will help if you use a build server.
  3. Edit your pelicanconf.py file.
    • Add a new line anywhere to tell pelican where to find your theme. THEME = '/path/to/the/theme/base'
  4. Rebuild the blog.

Utilize Other Settings

There's a whole list of settings that change the outcome of your blog build. Checkout the documentation for a full list Here. Each theme will document how they utilize different settings on the page, and which plugins they support.

Some that I found useful were the following.

SITESUBTITLE = 'Code, Ideas, Architecture'
SITEDESCRIPTION = 'Blogs and snippets from the Cloud'
ROBOTS = 'index, follow'
GITHUB_CORNER_URL = 'https://github.com/dejonghe'
DISQUS_SITENAME = 'codingforthecloud'

I thought that the Disqus integration was really neat. I already had a Disqus login from commenting on NGINX's website, I was able to get a free Disqus page set up in just a couple minutes and added to my page by simply adding the one setting line. This provides me a free way people to interact with me over the articles I post.

Checkout Plugins

I setup and use the table of contents, and sitemap plugins. Here's a repo full of Pelican Plugins. I followed their instructions on installing their plugin set.

For these to work I had to modify my pelicanconf.py with the following:

PLUGIN_PATHS = ['/path/to/my/pelican-plugins']
PLUGINS = ['sitemap', 'extract_toc' ]

SITEMAP = { 'format': 'xml' }

MARKDOWN = {
    'extension_configs': {
        'markdown.extensions.codehilite': {'css_class': 'highlight'},
        'markdown.extensions.extra': {},
        'markdown.extensions.meta': {},
        'markdown.extensions.toc': {},
    },
    'output_format': 'html5',
}

I ran into a problem here, I tried to enable the markdown.extensions.toc but did not realize there was more enabled by default. This broke my codehilight Markdown exstension. Using the object above for extension_configs should make it so you don't run into the same issue.

After enabling the table of contents plugin, I simply added [TOC] to the top of my blog article and edited the Flux Theme to enable TOC in the theme.

Hosting

As mentioned above I choose to host on Amazon Web Services. I know that you can host flat websites on github, and every other pelican blog will teach you how to do this. I choose to host this site just as I would any other production web front end, through S3 and CloudFront.

While this might not be the most frugal decision, it's the one I'm most comfortable with. I have extensive knowledge about hosting in AWS, and know exactly how to use it to serve exactly the way I want my clients consuming. This provides me all of the flexibility with just a slight cost if this blog gets a lot of traffic.

Architecture Diagram

Architecture Diagram

Architecture Stack

  1. Route53 hosts my DNS.
    • Route53 is globally distributed, configurable by API, and is all I could want in DNS.
  2. CloudFront is used for a CDN.
    • My primary reasoning for using CloudFront is for custom SSL/TLS cert on my static S3 site.
    • CloudFront does cache and globally distribute my content, this will be nice for my readers.
    • Do I need encryption on my static site? No. However, I was working for a client whose VPN would not allow me view sites that were not over HTTPS. It would infuriate me when I could not access a blog with great content that was HTTP only. So HTTP(S) and HTTP/2 all you want!
  3. S3 hosts my content.
    • S3 is a blob storage that can be used for static site hosting. After putting CloudFront in front of my S3 bucket, my bucket no longer serves as a static site host, and only as blob storage.
  4. I generate content, build and deploy.
  5. S3 objects being Put or Posted to my bucket fire a Lambda that makes a request to invalidate the CloudFront cache.

Deployment Edits

I updated the Makefile to change the command ran for updating S3. It was using s3cmd and that um... not what I wanted to use. I switched it to use AWS CLI. The following is how I updated my Makefile to change the s3_upload command to be just s3 and set it to run the command I wanted to use.

s3: publish
    aws s3 sync $(OUTPUTDIR)/ s3://$(S3_BUCKET) --profile MyProfile --delete

Closing Thoughts

This blog has gone through some major points here, I explained what I wanted out of a blog, why I choose to use a static site over dynamic content, how I set up with pelican, and how I host the site. In all I've been extremely pleased with static site generators, and pelican. I did have to make some alterations to the Flex theme, if you'd like to check out my edits, view my Fork of Flex. I love the fact that I'm able to get comments and discussion going for free with Disqus, and it's natively built into the platform. This gives me pretty much all I could ask for in a cheap to build, cheap to maintain blog platform.