Introducing a Static Site Blog with Pelican
I started this blog on WordPress. After testing it out I realized that WordPress is overkill and all the WordPress hosting options and backups and security configurations were going to cost a small fortune. I also found all the WordPress features just got in the way of doing some really simple things. It has all the bells and whistles and too many buttons to push.
A few years ago I had played around with static site generators. A static site generator doesn’t use a database and complex server technology like WordPress. They are good for simple sites that are a few pages, a feed of posts and some categories and tags. My ambitions are modest so it seemed perfect. In goes content as plain text files that I can edit with any editor and out comes a bunch of plain HTML files I can put anywhere. I can host a static site for super cheap (and even free) on any basic server.
There are many static site generators.
I settled on Pelican because it is in my favorite programming language, Python. I revisited Pelican and I was impressed with the new version. This post will be a simple introduction to site generators and some tips for using Pelican that may apply to other generators. There are tons of great articles on Pelican and site generators in general, but if you are “static site generator curious” this might be a good starting point.
What You’ll Need
- Some basic technical skills:
- Be comfortable with command line tools like the Mac or Linux terminal, or the Windows shell
- Be comfortable editing configuration files using a text editor
- Be able to read and understand technical documentation
- Some basic knowledge
- Static site generators require knowing some simple markup like MarkDown or reStructured Text for creating content. These are easy to pick up (Markdown Guide)
- Beginner knowledge of HTML and CSS will be helpful for doing more than the basics in your posts (this is true of most blog publishing platforms).
- Understanding web technology on the level of what is a browser and what is a server
- How to install software on your platform of choice. Knowledge of package managers is extremely helpful.
- Nice to have:
- Version control knowledge, like Git
- Familiarity with template languages, like Jinja (Pelican’s choice) or Handlebars (some other generators).
- A chunk of time. This is a process and you won’t get your site up and running in “just a few minutes” like some people claim. You can generate a site in a few minutes but you’ll want to customize it.
Setting Up Pelican
Pelican has a great quick start introduction.
Once I had Pelican installed (I highly recommend using a virtual environment in Python to manage all the packages and to make upgrading Pelican later easier) then I created a basic site with the default template just by running:
pelican-quickstart
This will set up a site outline where I can put content in /content for blog posts and /content/pages for static pages. The generated site files will be put in the /output directory.
I generate the site by running:
pelican content
I won’t rehash all the options here. What I will point out are some things I had to figure out on my own.
Adding a Theme
Pelican supports “themes” or different looks and feels for a site. There are some examples on the Pelican Themes site.
Out of the box, Pelican will generate a servicable site with a few configuration options.
To change the look of my site, I could choose a pre-built theme or build my own.
I played around with some pre-built themes. To choose a pre-built theme, I installed it with the pelican-themes
command.
Then I could simply set the name of an installed theme in my pelicanconf.py file.
THEME = “/path/to/theme”
But building my own turned out to be surprisingly simple.
- I used the simple theme to start. It is in the site-packages directory of where I installed Pelican but I could download it from Github
- The simple theme is a very well organized project. Everything inherits from the base.html template so I found I can customize the whole site by editing one file.
- The simple theme generates a pure and plain (no CSS or inline styles) HTML semantic site with some navigation and basic elements.
- Then I found I could copy the simple templates somewhere and edit away.
I was interested in using an out of the box style sheet so this was perfect. I didn’t want to do a bunch of custom styling.
Adding some style
Next I looked around for some helpful starter style sheets for making my site look more than “simple”. I found Pico, which is a “semantic HTML” style sheet. I like the clean design and even the default styles are pretty attractive. The default things like spacing between elements is a nice balance of compact and readable.
If a site uses semantic HTML (e.g. it tags things as what they are instead of using generic tags like a <div>
for everything) then Pico requires almost no work to style the site. Fortunately, the simple theme uses semantic markup, e.g. it uses <header>
for the top of the page, <article>
for blog posts and <footer>
for the bottom of the page.
I just picked the Pico color scheme I liked. Pico provides a “classless” version of the stylesheet so I didn’t even have to add classes to all my HTML. Pico just uses the type of HTML element to style it. No markup needed. Then I edited the base.html file in the templates directory and copied the CSS file into the /css directory.
I added the link to the Pico stylesheet in the <head>
element of base.html:
<link rel="stylesheet" type="text/css" href="{{ SITEURL }}/theme/css/pico.classless.cyan.css" />
That’s it. I created a whole new theme by editing one file and adding one file.
Granted this site is not fancy but it is (a) clean and readable and (b) really easy to update and maintain. I think default Pico is a great choice for a starter look and feel.
If I want to get fancier, I can customize Pico a bit or edit the theme templates to add more features.
I wanted to add some process
By default, Pelican converts Markdown or restructuredText or HTML pages in the /content directory to the static site (in /output). I added a /content/pages directory to add some static pages to the site. Pelican supports static pages out of the box and will add them to the site navigation automatically.
But this doesn’t support a typical workflow for me, like generating ideas, editing drafts, and publishing content. It isn’t easy to see what is in draft or what is published already.
So I added a drafts folder, an ideas folder etc. to the content folder. If I want to keep my published content in a separate folder I can do that, too.
I needed to add the new source paths to pelicanconf.py
. For example:
ARTICLE_PATHS = ['published', 'drafts']
For now, I am actually using a built in feature of Pelican. If I add a Status: drafts
line to the top of an article file it won’t publish it but it will include it in a /drafts folder so I can share links for review, etc. Note Status: hidden
will publish it to the site but will not add any links to it from the rest of the site. Adding Status: published
will do the expected thing.
If I get fancy, I might use more subfolders. But I think it complicates editing the Markdown if I want to use my editor’s ability to link between files and I want the generated files to link to each other. For example, if I had a file in the drafts folder and I wanted my editor to link to a file in the published folder, then when I publish the draft article I would need to update my links. Pelican does support a link syntax for static file links between posts and static assets, like attached files and images. However, if I use that non-standard Markdown syntax my Markdown editor will not understand the links and it’s previews will not work!
Update: I find myself using the {filename} and {static} link extensions despite the fact that my Markdown editor preview doesn’t support these links. For example, I can add a link to a published piece of content like:
[some link text]({filename}/content/published/some-file.md)
This generates a link in the output file to output/some-file.html. Then I preview the output content in my browser by running:
pelican content --listen
Publish
Since I used the pelican-quickstart
set up, when my content is ready, I want to change some the default settings I used for development. I want to generate the final published version of the site with absolute URLs, for example.
These publication settings are found in publishconf.py
, which inherits all the settings from pelicanconf.py
so I just need to change a few things.
The main things to change are SITEURL and RELATIVE_URLS. I set the latter to False so the generated site has all the links pointing to the SITEURL.
Then, to generate a site ready to publish I run:
pelican content -s publishconf.py
To really publish to the web, I needed to have hosting set up, connected to some sort of repository online or available via FTP.
Conclusion
Setting up and using Pelican is more technical than using WordPress. But WordPress is bloated with features! It is a full-blown Content Management System, and doing some basic stuff seems over complicated. I just wanted to edit some files and publish them online. Now that I have Pelican configured, I can do that with a few simple commands.
It is also nice to have a complete copy of my site in one place on my computer instead of on someone else’s system in a database somewhere. I can tweak it, move it somewhere else, even work completely offline. And it is in a very portable format. Because the content for my blog is just plain text files I am not locked into any system or publishing platform.
I’ll write a future blog post about how to publish a static site to a hosting provider. There are tons of web hosting companies but not all have a basic static site tier. I tried both kinsta.com and AWS and ultimately went with AWS Amplify Hosting even though it is more complicated to set up than Kinsta.