Creating a Dynamic Public Folder With Apache

What a mouthful for a blog title, right? I wasn’t sure what to call this, but basically, it’s a small post which tells you how to dynamically create public HTML folders, so that you can instantly switch between them when deploying on Linux with Apache. Zero-downtime, if you like…or almost zero.

Let’s expand on that a little with what my old process was. Imagine this: I have just finished my latest can of Pepsi Max and have decided to write a new blog post and publish it. Skipping all the creative, finger tapping and Git related parts, I log on to the server, and run my build script.

It’s quite fast to be fair, but it can take anything up to a minute whilst it removes the public folder and regenerates all the static files. Meanwhile, Doris, my loyal reader from somewhere in Scotland, tries to go to my website and it seems like it’s down. Well, naturally, it is down because there is no public folder and nothing to see. Or worse, it’s in a kind of limbo state, partially created, whilst the build script chugs away. That’s why zero-downtime seems so appealing.

Wouldn’t it be good if we could leave our current site alone whilst we mosey-on-around, taking our time to generate the new version of the site, and once complete, switch them over, like magic? Instantly swapping and achieving that desirable (almost) zero-downtime - lovely. Well, here’s how you can do it.

For this, I am using an Ubuntu system running Apache, with Hexo as my static site generator, but the process can easily be adapted for for other systems and configurations. Also, it’s worth pointing out that I haven’t made any effort to remove the old folders that were deployed (you’ll see what I mean in a minute). That’s deliberate because for now, I quite like the idea of being able to switch back to an old version, at will. When I find I have hundreds of them, I am sure I will feel rather differently!

To begin, let’s chop this post into four pieces - you can use just the bits you need:

  1. Finding out what your public folder is
  2. Changing the generated output folder in Hexo
  3. Generating a new dated folder to store your public HTML files
  4. Hotlinking your website’s named folder, to your dated folder

Your Public Folder

Let’s see what the currently served folder is for your website in Apache. For me, that was the public folder. In my case, the configuration for this is in the file:

1
/etc/apache2/sites-enabled/logicalmoon.com.conf

You may very well have named your configuration file something differently. Poking inside, though, we can see the name of my final public folder and again, yours may be something else:

1
2
3
DocumentRoot /var/www/logicalmoon.com/public/

<Directory /var/www/logicalmoon.com/public/>

OK, so public it is; remember that because we’ll need it.

Changing the Hexo Output Folder

Back to my website’s folder, I can see that I already have a folder in there named public which also happens to be the default output folder in Hexo.

1
2
3
$ ls -ld public
drwxrwxr-x 2 stephen stephen 4096 Apr 30 22:18 public
$ rm -fr public

Let’s alter that destination folder using Hexo’s configuration file. We’re going to use another name - publichtml instead. The name can be what you prefer, and of course, you’d swap this step with whatever method for altering your destination folder/generator.

Open up the configuration file for editing:

1
$ nano _config.yml

and change this line into the name you want:

1
public_dir: publichtml

Hang on! Why don’t I just leave things going into public and use an alternative named folder in the Apache configuration? You could, of course, but I quite like using public so want to keep it, that’s all.

Time to take stock of where we’re up to. Till now, we’ve knackered our website (sorry, Doris) and changed the output folder in Hexo. We’d better move quickly to actually create a new set of static files!

In a flash, we re-generate our output files from static data:

1
2
3
4
5
$ hexo clean
$ echo "{}" > db.json
$ hexo generate
$ ls -l publichtml
drwxrwxr-x 3 stephen stephen 4096 Apr 30 22:28 publichtml

We now have a new folder named publichtml, ready to use.

Generating a Dated Folder

Next, let’s work out what we will call our new (dated) folder. We’ll use the current date and to handle cases where we might run it more than once a day, we’ll add in the epoch time. That’s just a fancy phrase meaning the number of seconds since the 1st of January, 1970. What’s good about it though is that it will be really hard (though not impossible) for us to create two folders with the same name because, as you know, time keeps ticking. Note: I could also just use the epoch time alone but it’s really handy seeing a human readable date, too. Enough chit-chat - let’s generate it.

1
2
3
$ filename="hexo"`date +"%Y%m%d.%s"`
$ echo "Using" $filename "as new directory name"
Using hexo20210501.1619855276 as new directory name

We’re making progress, but how are we going to actually use a folder with that name? Well, firstly, let’s rename publichtml to be that calculated name, to make space for another build later but also keep our historical output separated.

1
$ mv publichtml $filename

Hotlinking Our Public Folder

But what about the public folder we mentioned earlier in our Apache configuration file? The trick here is that it won’t actually be a folder, but instead, a symbolic link to the real folder, and just named public.

In code, let’s make sure it doesn’t already exist because if it does, we want to remove it.

1
2
3
4
$ if [ -L public ]; then
echo "'public' symlink exists. Removing it"
rm public
fi

Woosh! Gone. The -L option is testing for the existence of a symbolic link, and in the case, obviously that being public. If we find it, we echo something to the screen and remove it.

We just need to create the final (new) symbolic link, now.

1
$ ln -s $filename public

Here’s what our directory listing looks like once we have run all of these commands:

1
2
3
4
$ ls -l
total 5584
drwxrwxr-x 25 stephen stephen 4096 May 01 21:44 hexo20210501.1619855276
lrwxrwxrwx 1 stephen stephen 23 May 01 21:44 public -> hexo20210501.1619855276

A quick visit to my website confirms all is well. Phew!

Finishing Off

The only thing left to do is to put all of this into one build script and run it each time we deploy. Here’s that script to save you a little effort which you can paste into a file named something like build.sh:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#! /bin/bash
#
# rebuild blog using hot links

# rebuild the html for the blog
hexo clean
echo "{}" > db.json
hexo generate

# calculate our new html folder name
# will create folders named: YYYYMMDD.EPOCH
filename="hexo"`date +"%Y%m%d.%s"`
echo "Using" $filename "as new directory name"

# rename new hexo html dir to a dated version
mv publichtml $filename

# remove public symlink if it is there
if [ -L public ]; then
echo "'public' symlink exists. Removing it"
rm public
fi

# relink symlink
ln -s $filename public

If you wanted to improve it more, you could use absolute path names instead of the relative ones, I have (/var/www/... rather than just public) and also add something in to remove old folders, if you like.

Right - I have a new blog post to deploy!


Hi! Did you find this useful or interesting? I have an email list coming soon, but in the meantime, if you ready anything you fancy chatting about, I would love to hear from you. You can contact me here or at stephen ‘at’ logicalmoon.com