TL’DR: Dynamic blog publishing systems come with lots of security concerns. I implemented a simple setup using Jekyll, Git and Apache which relies on static sites and uses SSH for encryption. Here is how I did it.
Why Using a Static Site Blog
If you have your own root server and want to host a blog, there are dozens of solutions you can choose from - with Wordpress being one of the most (in-)famous. While those undisputedly powerful platforms allow you to create a nice, full-fledged blog/website in a couple of minutes, they also come with a range of dependencies and implications.
Being responsible for the security of your server yourself, you might wonder if a simple blog is worth running a database and a large amount of (possibly exploitable) PHP code on your server. Beyond basic concerns regarding Wordpress itself, most of Wordpress’s power comes from the sheer endless number of plugins. This year alone, several severe security leaks have been found in widely used plugins like WP-Slimstat, fancybox-for-wordpress, and even in some Wordpress themes.
If all you want is a simple blog, static site generators might be what you are looking for. Instead of hosting dynamic code, static site generators convert markup text into plain html sites. A common example for such a site generator is Jekyll. Still, using a static site generator might look tedious at first when compared to the web-based interfaces of Wordpress and the like. Also, Jekyll comes with its own little webserver, which is written in Ruby. You might wonder how much of the security advantage of static sites is left if they are served by something far less commonly used and reviewed as Apache.
This might sound unfair towards the developers of Jekyll, who do a tremendous job. But somehow I just feel better if the static sites on my own server are served by something more widely used. Call it superstition ;).
In order to adress these issues, I use Git to push my posts to the server via SSH, where Jekyll renders the static sites. The resulting sites are then served by a simple Apache configuration. Because this workflow is a little rough around the edges, I also created some Git aliases and shell-scripts which improve the experience a lot. Here is how I did it:
Hint: I did this on an Arch Linux machine (minimal setup), but the general approach also applies for most other distros.
Setting up a Jekyll Blog Using Git and Apache
At first we create a local version of our blog on our desktop machine, then we setup the server and publish our blog.
Start by installing RubyGems (which will also install Ruby). RubyGems is a simple package manager for Ruby.
sudo pacman -S rubygems
After that, you should add the following to your ~/.bashrc file:
PATH="$(ruby -e 'print Gem.user_dir')/bin:$PATH"
That line adds the Gem directory to your path and is required for RubyGems to work properly. Use
to apply the changes you made.
Now, install Jekyll and RDiscount (the markdown language support) using RubyGems:
gem install jekyll gem install rdiscount
Create a Basic Blog
If you do not have Git installed on your local machine do so now:
sudo pacman -S git
Some Jekyll themes can be installed from scratch (using Bundler or something similar). You can start with such a Jekyll theme if you like, but for the sake of simplicity, we will begin with the simple Jekyll-Base here. Run this on your local machine:
git clone https://github.com/danielmcgraw/Jekyll-Base
That command checks out a very simple scaffolding. This is everything you need to get a basic layout up and running.
Do not be fooled by the “jekyll –server” command mentioned on the Jekyll-Base Git page. That command is no longer valid. Instead, execute
inside your Jekyll-Base directory and open ‘localhost:4000’ in your favorite browser. If you see an ugly white page saying “Jekyll Base” then yay! Success!
It is a good idea to download a nice theme now (check jekyllthemes.org) and install it into your Jekyll-Base directory according. The theme pages usually tell you how to do so.
Once you have adjusted the theme to your preferences, it is time to configure your server.
##Configure the Server
Log on to your server as root. Then create two new groups on the server:
groupadd webspace groupadd gitspace
Those groups are used for giving our user write access of the server directories.
If you don’t have a (non-root) user account on your server yet, create one:
useradd -m -G wheel,webspace,gitspace -s /bin/bash bloguser
This assumes that the user is called ‘bloguser’. You can call him whatever you want. If you do not want to use a dedicated user for the blog, you can always use the same username as your local user. If your user already exists, make sure to add him to the newly created groups.
Set a password for the user:
Now create the directory you want to use for Git. Arch uses /srv/http for web hosting, so we create our git hosting directory alongside:
Now change the permission for those two folders like that:
chown root:webspace /srv/http chown root:gitspace /srv/git chmod 775 /srv/http chmod 775 /srv/git
755 is the default permission mode for /srv/http. We change it to 775 in order to allow write access by the owner group. That also allows that other users can read your Git directory. So if you intend to also use it for something else and other users have access to your server, you might want to choose somewhat more restrictive permissions.
Logout root and logon as your user.
Install Jekyll and Git on your server as described above.
Create a bare git repository for your blog:
git init /srv/git/blog --bare
A bare repository does not contain a checked-out copy but only the version control. This is what you get when you create a new GitHub repo. Having a bare repository allows you to push to that repository instead using pull-requests.
We will now add a Git hook, which automatically creates the static files in /srv/http when we push something to the repo. Add a file named “post-receive” to the directory /srv/git/blog/hooks with the following contents:
GIT_REPO=/srv/git/blog TMP_GIT_CLONE=/tmp/blog PUBLIC_WWW=/srv/http git clone $GIT_REPO $TMP_GIT_CLONE jekyll build -s $TMP_GIT_CLONE -d $PUBLIC_WWW rm -Rf $TMP_GIT_CLONE exit
Make that file runnable by executing:
chmod +x /srv/git/blog/hooks/post-receive
Install and start Apache, which will point to /srv/http by default (as long as you are using Arch):
sudo pacman -S apache sudo systemsctl enable httpd sudo systemsctl start httpd
We still need some way to push our blog posts from the local machine to the Git repo on the server. SSH provides an excellent way of doing so: It has a well proven encryption and is very simple to setup.
Install SSH on your server:
pacman -S ssh
It is usually a good idea to disable root access in your ssh configuration file (/etc/ssh/sshd_conf).
Setting up the Local Machine
Now let us setup the local machine. At first, create a SSH keypair using:
ssh-keygen -t rsa -b 4096 -C "$(whoami)@$(hostname)-$(date -I)"
Push that key to your server using:
with “remote-server.org” being your servers hostname.
You should now be able to connect to your remote server via ssh without using a password by calling:
Clone this repository to somewhere on your local machine
git clone remote-server.org:/srv/git/blog
and add the remote location for deployment:
git remote add deploy firstname.lastname@example.org:/srv/git/blog
Repeat these steps on any machine you want to write and commit posts from.
Since you now have an empty working copy of your blog, upload the blog you created earlier. You can simply push your blog to the server by staging all files, commiting and pushing. Copy the contents of your Jekyll-Base directory to the checked-out blog directory, then execute:
git add -A git commit -m `Adds initial blog content` git push deploy master
If things went well, you should see the static site on your server in /srv/http and the output of the commit hook on your console.
Congratulations, your blog should now be hosted on your server.
Some Additional Help
One Shot Deployment
Since I simply want to push changes to my blog by running a single command, I created the following Git alias inside blog/.git/config:
[alias] deploy = !sh -c 'git add . && git commit -m \"$1\" && git push deploy master' -
That lets me update my blog by running:
git deploy "Added new post about Jekyll"
If you have used Jekyll for a while, you might find yourself doing a lot of repetitive tasks which could easily be automated. Before you fire up vim and start hacking shell-scripts, take a look at Octopress.
Octopress is a quite powerful framework for Jekyll which brings its own theme and some handy commands. A simple
octopress new post "Post Title"
creates a new blog post and
octopress new page some-page/
creates a new page at some-page/index.md.