Here is how I set up the snek blog you are reading now.
Site overview
www.snekbot.com leads to a Python Flask app, directing users to log in via Discord to access the functions of the snek bot (or taking them straight to the functions if they are already logged in). So the blog, which is just a bunch of static files to be served by nginx directly, needs to be hosted in a subdirectory (/static/blog). Nginx normally serves everything from /var/www/html at the site root, but I changed the location block in the nginx config file so that URLs starting with /static/ are served out of /var/www/html, reserving the actual site root for the Flask app:
location / {
proxy_pass http://localhost:8001/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
...
location /static/ {
alias /var/www/html/;
index index.html;
try_files $uri $uri/ $uri.html =404;
}
The site root is directed to a port on localhost, where the Flask app is served by Gunicorn. /static/ serves everything out of the /var/www/html folder. The combination of an index directive and a try_files directive tells nginx to first try and serve the URL directly, then to look if there’s a directory containing index.html that matches the page, then finally to see if there is simply an html file not in a nested directory that matches the URL. All these directives are needed because there are certain static pages not part of this blog, like the aquarium stream page at www.snekbot.com/static/tank .
Generating the static site
I followed the quick start guide at https://gohugo.io/getting-started/quick-start/ , with some modifications. Rather than install a theme as a submodule, I just pulled the repo from https://github.com/wd/hugo-classic and manually copied the files across.
It was important to properly configure the baseURL parameter in the hugo.toml config file, to reflect the fact that the site is in a subdirectory.
baseURL = 'https://www.snekbot.com/static/blog/'
languageCode = 'en-us'
title = 'snek dev blog'
theme = 'classic'
# Enable this for tailwind in markdown files
[markup.goldmark.renderer]
unsafe=true
# Add menu links to things from /content/ here (eg. markdown.md)
[[menu.main]]
name = "posts"
url = "/posts/"
weight = 1
[[menu.main]]
name = "about"
url = "/about/"
weight = 1
Rather than having images associated with “page bundles”, where each image is in the directory corresponding to the page, I wanted images in a centralised location. This is accomplished by storing the images in static/images in the Hugo site folder. So in the markdown document, specifying the path like this:
![Test Image](/static/blog/images/moco.jpg)
ensures that the path to the image is constructed appropriately. The image below is served out of the images folder, rather than the folder that contains the markdown file of this post:
On retrospect, this was more trouble than it was worth, but it does keep all image files together in one place. The main motivation for this was to avoid uploading images to this page’s git repo. The .gitignore for the site repo is set to ignore all image files.
Editing the site
I installed Hugo on Ubuntu, which runs inside WSL2 on my Windows PC. By creating the repo for the website in the Windows file system, which is accessible from WSL2 via /mnt/c/etc… , Hugo can access the files to build the static site, but I can edit them and view them in Windows using Notepad++, and it’s more ergonomic to relocate files, add images, etc. The only drawback of this is that the Hugo development server doesn’t seem to be able to monitor files for reloading when they are in the Windows filesystem, so it needs to be manually restarted to reflect site changes in development mode.
Deploying the site
Cloning the repo for the site onto the snekbot server wouldn’t transfer the images, which I specifically do not upload to github. In fact, the server does not need to run Hugo at all, it only needs to serve the static files that I generate locally. Deploying the site from within WSL2 can be done easily using rsync:
rsync -avz -e ssh public/ snekhaus:/var/www/html/blog
By default, Hugo outputs the site to a directory called “public”. This command synchronises the “public” directory with the directory on the server from which the site is served. Note the trailing slash after public means rsync copies the contents of that directory into the /blog directory on the server.
Explanation of rsync command line options:
- -a: Archive mode to preserve permissions, timestamps, symbolic links, etc.
- -v: Verbose mode to show detailed output.
- -z: Compress the data during the transfer for faster transmission.
- -e: Specifies the ssh command
In this case, rather than specifying the details of how to connect to the server in the command, I added an entry in my ssh config file.
Host snekhaus
HostName snekbot.com
User [my username]
Port [my ssh port]
IdentityFile ~/.ssh/[my private key]
In this way, I can just specify “snekhaus” when I want to connect to the snekbot web server. For some reason, I needed to specify my private key explicitly - it’s not picked up automatically. I normally access the server using PuTTY from Windows, so it was necessary to use PuTTYgen to convert the .ppk format of my private key to a format suitable for use with ssh. Then I copied it to the relevant place in my Ubuntu WSL2 installation, to be used by rsync.
>> Home