Setting up Pelican on PythonAnywhere
This is a tutorial to help you set up a Pelican powered blog on PythonAnywhere. The steps outlined here will work anywhere you have access to a command line with Python and webhosting but small changes to the examples might be needed.
Pelican is a static site generator written in Python. If you have access to Python and a command line you can use Pelican to generate your site and upload it to your webhost.
Pelican lets you write your blog posts in a plaintext format and then generates your site by processing those files. This makes the process of writing your blog articles really easy and removes all the hassles of generating the HTML for your site. With out of the box features like syntax highlighting for code and the ability to render mathematics content it's a good choice for technical blogging. Pelican supports a few formats for the content, I personally use the reStructuredText format but I know other people use markdown. If you are new to both I'd suggest going with reStructuredText because it is more stable in my experience and there's fewer dialects of it out there. A good introduction can be found here: https://sphinx-doc.org/rest.html
The nice thing about PythonAnywhere is that you have access to a Python environment from anywhere that you have a web connection. This means you can set up a blog with Pelican that you can edit from anywhere you have a computer with an internet connection. With a small effort you can separate your site into a live site and a development site. This allows you to put articles into the backend and work on drafts without having the whole world see it.
Installing packages
First make sure you have pip available. PythonAnywhere comes with pip and virtualenvwrapper already installed. If you only have easy install then use that to install pip. If you already have pip then skip this step.
easy-install pip
At this point you can get the virtual environment set up. While you could use virtualenv on it's own I much prefer virtualenvwrapper as it makes the whole process much easier.
pip install virtualenvwrapper
At this point if all has gone well with the install you can then set up your virtual environments. This will sandbox your environment so that your website development environment will remain consistent and won't change if your system changes. This is good for ensuring that the packages your site depends on don't get changed without your knowledge.
mkvirtualenv my_blog_name
This will then create a new virtual environment with this name. If all has gone well then you should see the environment name at the beginning of your shell prompt:
(my_blog_name)20:45 ~ $
You now want to check that it was created properly you can execute the following command:
which python
The which command shows you the location of the Python that is being used when you are in the virtual environment directory (note that this should not be the default /usr/bin/python location). If all has gone well this will be the Python that is installed in your virtual environment and not the one in the default operating system location.
You need to add a line to your shell startup file in order to make this virtual environment easily accessible. On PythonAnywhere edit the ~/.bashrc file, mine looks like this:
# Load up standard site-wide settings. source /etc/bashrc export WORKON_HOME=$HOME/.virtualenvs export PROJECT_HOME=$HOME/personalsite source virtualenvwrapper.sh
On my home computer virtualenvwrapper.sh is located in a slightly different location which requires a different source command:
source /usr/local/bin/virtualenvwrapper.sh
This just loads up virtualenvwrapper with your shell. This allows you to easily switch between environments using the workon command. Now to resume working on your virtual environment later you just type the following:
workon my_blog_name
Now you can install Pelican and Fabric into your virtual environment:
pip install fabric pip install pelican
Pelican will ask you a bunch of questions to help you set your site up. Answer those the best you can.
If all has gone well you should now see these packages come up in the list of installed packages. You can check which packages have been installed into your virtualenv by running the following:
pip freeze
The pip freeze command tells you which packages you have installed at this point in time. This is useful when you are trying to ensure that you always have the correct dependencies installed for your project.
If you have version control set up then you should keep track of the dependencies by keeping them in a requirements.txt file within your repository:
pip freeze > requirements.txt
Then add requirements.txt to your repository.
Configuring PythonAnywhere to serve your site
Now that we have Pelican installed we need to get the files it creates hosted. To get the site to be properly hosted you need to point nginx/apache to serve the static files from wherever that directory is located.
By default PythonAnywhere expects to find a wsgi file to host your website. However Pelican isn't a Python web application, it's just a Python tool that makes static websites. Therefore there's no associated wsgi file for a pelican website. Serving a static site on PythonAnywhere is done by using the "static files" section on the web tab in your dashboard. It should look something like this:

You just need to decide on which URL directory you are hosting your blog from and tell PythonAnywhere to reroute requests to those URL's to your Pelican directory.
Start making your content!
Now that you have everything set up you just need to add the content.
There's 3 types of content:
- Blog posts
- put these in: ./content/
- Static pages
- put these in: ./content/pages/
- Other static content (such as images and javascript)
- explanation to follow below
Blog posts:
A hello-world equivalent for a first post might look something like this:
Filename: ./content/first_post.rst
First post ############## :date: 2014-05-24 13:37 :tags: blogging :slug: first-post :author: My Name :summary: first blog post This is my first blog post!!!!!!!!!
Static pages:
An about me page might look something like this:
Filename: ./content/pages/about_me.rst
About me ######## :date: 2014-05-24 17:47 :author: My Name here's some info about me...
Then elsewhere to link to that page you just need to do the following:
here's a link to my `about me page`_ .. _about me page: {filename}/pages/about-me.rst
Note that this is a path to the location of the .rst file within the content folder and not the path of the processed .html file.
Other static content:
In order to get Pelican to correctly host your static content you need to create subfolders within your content folder.
content ├── images │ └── my_image.jpg └── js └── my_script.js
Now in order to get pelican to just copy these directories over to the output folder you have to tell Pelican which directories are for static content. In this case we would add the following to the setting file:
STATIC_PATHS = ['images', 'js']
Now those folders will get copied over to the output folder.
For example if you now wanted to add an image to the about me page you would upload your image to the images folder and change the about_me page as follows:
About me ######## :date: 2014-05-24 17:47 :author: My Name Here's some info about me... Here's my photo: .. image:: {filename}/images/my_photo.png :alt: my awesome photo!
Note that there's a gotcha here if you are using the {filename} syntax but a Pelican version before 3.3 , so I wrote a blog post about this.
Once you have the pages together then you can just use the makefile to get Pelican to generate your site and place it in the output folder:
make html
Then you just need to open up your browser and point it at your site!
Drafts and pelican
One thing I find I do a lot when blogging is writing up some drafts and working on a few things at once. When ideas start getting more finalized I post them up, but in the interim I don't want to have all those posts be live, at all. Many blogging platforms have a way of letting you decide what is published and what is not.
Pelican does have a draft option that creates your pages, just add this to your post:
:status: draft
This just publishes your article without generating links to it anywhere. Therefore to view the output you need to know the exact html address. The drafts will be accessible to anyone that has the link, so if you want to share the link with friends just give them the full URL.
For most people this is probably entirely sufficient for draft content.
But what if you want to have some sort of access control on your drafts? Pelican doesn't support access control, which is to be expected given that it is just a static site generation tool. But with a bit of ingenuity we can still have drafts that aren't visible to anyone. There's 2 ways of doing it:
- The quick and dirty way
- Using version control software
The rest of this tutorial is explaining both these approaches to access control for drafts. If you aren't wanting access control on your drafts then you have completed this tutorial, enjoy making your Pelican powered blog!
The quick and dirty way
Pelican processes your content files and outputs them to an output folder location that you define via the settings in pelicanconf.py. When you run "make html" the web pages are generated from the files found in the content folder and then are placed in the output folder.
What you can do is have 2 separate folders that you serve your content from. For example draft_output/ and live_site/
The web serving software (nginx, apache, etc) on your webhost hosts the live_site/ folder. The draft_output/ folder is either hosted on your own computer or on your webhost in a folder that has some form of access control.
On PythonAnywhere probably the best way is to create a subdomain for development for any site you are working on. You can host the draft content from there and just add a password to that particular web app. [1] So for example if your sitename is www.example.com you might want requests to / to be redirected to /path/to/live_site/ and dev.example.com to be hosted at /path/to/draft_output.
When you make a few changes and you end up liking what you see at dev.example.com then just open up your shell and copy the folder across:
cp -r /path/to/draft_output/* /path/to/live_site/
Now any changes that you made on the development site will be visible on the live site.
[1] | PythonAnywhere is set up in such a way that you have to put password protection at the root directory of a web application. So you pretty much have to go with a subdomain like dev.mysite.com in order to have the password protection work. |
The version control way
Pelican only processes plain text files as input. Because are the content is stored in plain text formats version control software (VCS) excels at keeping track of it. Because of the power of version control I like to store all my content/blog posts within a git repository. You don't have to use version control to use pelican but I'd strongly recommend it. [2]
I like using a VCS workflow where a specific branch contains the exact content that will appear on the live site (I often call this branch master or live). This way any work on this branch gets directly reflected on the live site. When I'm working on making some private changes such as drafts that I'm not going to immediately publish I do that work on a different branch.
By using branching we can keep our drafts in a non-publicly accessible location so we can review the content before publishing it. Possibly the simplest way is just to have a single branch for unpublished drafts:
git checkout -b unplublished-drafts
If you wanted to do it on a per-article basis you could do something like this:
git checkout -b draft-my-article-name
The key conceptual idea is that every time you work on a branch the working directory reflects the state of that branch. This means you can make changes to the content contained in a branch without impacting the other branches. When you are working on drafts you usually are only working on changing that draft in isolation of the other content. By keeping each draft in its own branch you automatically keep the drafts separate and then updating your site is as simple as just merging the branches that correspond to drafts over to the live-site branch.
Because Pelican just processes the files it finds in the content folder if your version control system only places the files in the working directory that you want then Pelican will only process the files that are present in that branch. This way anything not on the branch never gets processed and therefore never gets published to the live site.
This ability to work on content in an orthogonal manner lets you see how the entire site looks when you make some changes. If you review the changes and like what you see you can then merge those changes to the master branch and then deploy the changes to the main site. For the most part this is a fairly straightforward task so it's a prime candidate to automate with a deployment tool. The Pelican developers had the same idea so to simplify the publishing process Pelican comes with a handy Makefile and Fabfile. Both these were not made with branching in mind so you have to make a few changes to get the process to be as smooth as possible.
Specifically there's a makefile directive called make html which takes all the items located in the content folder and puts them in the output folder
When I'm working on PythonAnywhere I add a makefile directive to copy over the content from the development site to the live site folder. It will look something like this:
live_folder: cd ~/$(LIVEDIR)/ && rm -r ./* cp -r $(OUTPUTDIR)/* ~/$(LIVEDIR)/
Now whenever I'm happy with my changes as seen on the development site I just run the following command to put it on the live site:
make live_folder
[2] | If you are technically savvy enough to be using Pelican to power your blog then it's likely you would do really well to know how to use version control at least on a rudimentary level. If you are new to version control I would recommend looking into Mercurial (or git if you are up for a challenge). These are extremely powerful tools but you only need a very small subset of them for making a blog so don't be intimidated. |
Comments and future work
It occurs to me that there might be a substantial number of people who want to write unpublished draft content without needing to know about branching in a version control system. While version control systems are incredibly powerful I can appreciate that this a very heavyweight way to deal with just making drafts not publicly viewable.
Possibly a better approach would be to change the Pelican code around so that there could then be 2 separate locations for processed files to go into depending on the :draft: flag:
- The live site
- only non-draft content
- The development site
- all content
The settings file could then contain the path to these two separate locations. The main site, as before, just serves the files out of the live site folder. For the development site you could just password protect the access to the development site files.
There could then be 2 makefile directives that you could use depending on the task:
make html make draft-html
Thanks to Giles from PythonAnywhere for taking the time to review this and give feedback.