How I Make This Site
2nd Jan 2020
Built using Hugo
It’s extremely fast and straightforward, has great documentation, and is capable in most areas you’d need it to be (comes with SCSS and image compression support, webpack/ES6 can be integrated)
Using the Ezhil theme as a base
It’s a good theme, the code is clean, it has dark mode support.
I stripped out the feather.js
since it’s slow and heavy, instead I checked out the Feather icons repo to the directly themes/feather/layouts/partials/
, added "feather"
to the themes
array in config, and now I can use hugo partials to include the SVG files inline, like this:
{{ partial "icons/award.svg" }}
The icons render instantly since they’re inline to the page and no longer blocked on a DNS lookup
Two sites, one theme
Since this theme powers both this site and chillidonut.com, we want to be able to customise small aspects of each site. With hugo it’s easy to override certain partials. For example, when a “layout” file such as themes/2019/layouts/_default/index.html
includes partial "footer.html"
, hugo will start looking in the project root for it, so we can override the theme’s footer file by creating a file named layouts/partials/footer.html
.
In practise this allows us to include additonal scripts such as this page’s “flock” animation or chillidonut.com’s page transitions in the footer or header to give each site its own features and flair.
Deployment
My websites are built on a self-hosted service called Drone CI and hosted using Google Cloud Storage. Drone uses docker containers to make the building and pushing of the site files simple. I’ve included the drone config below, as it’s illustrative of a typical way you might do this with any CI service.
View .drone.yml
# .drone.yml
kind: pipeline
name: deploy
trigger:
branch:
- master
steps:
- name: submodules
# we use submodules for the shared theme and the feather icons repo.
# this checks out the code in a container with git available
image: alpine/git
commands:
- git submodule init
- git submodule update --recursive --remote
- name: hugo
# build using hugo. this image also includes the bells and whistles
# needed to compress images
image: monachus/hugo:v0.58.3
commands:
- hugo --gc --minify
- name: upload
# upload to public GCS bucket
image: plugins/gcs
settings:
source: public/
target: tommckenzie.dev/
gzip: js,css,html
cache_control: public,max-age=3600
token:
from_secret: deploy-token
Google Cloud Storage hosts the website
In Google Cloud Platform you want the “Storage” service, and to create a bucket which matches your domain exactly (i.e. tommckenzie.dev
is the bucket name). You’ll have to verify you own the domain – I pointed my domain nameservers to cloudflare and added a DNS TXT record, which only took a few minutes.
Once you’ve created the bucket itself, from the bucket list view (of all your buckets) click the “dot-dot-dot menu”, select “Edit website configuration” and enter index.html
and 404.html
as the filenames. Don’t forget to do this, or the hosting won’t work and visitors will get an XML response instead of your website.
You’ll now want add a CNAME record pointing to your bucket — google explains how to do it well — but there are caveats which I’ll explain below.
a note on Google Cloud Storage, HTTPS, and CNAMEs
Since GCS doesn’t support HTTPS at all, you need to put something in front of it which does. I use cloudflare since a) they support adding CNAME
s to the apex domain (your domain without any subdomain), and b) they will handle HTTPS for you, for free.
Remember to set your site’s “SSL/TLS” setting to “Flexible”, and otherwise follow google’s instructions above.
redirecting www to your bare domain or vice versa (optional)
You only want one domain, usually the apex domain (yoursite.dev
), but you might want www.yoursite.dev
to redirect to this apex domain. Unfortunately, this is the trickiest part. You can probably use cloudflare workers to do it, or if you have a server with nginx or apache on it, you can use that, some people use lambda functions on AWS, I use a Kubernetes Ingress which simply redirects all www
requests to the apex domain. Depending on your solution you may also need to set up HTTPS for it, too.
Again, if this is a new site, you might not need to bother. For chillidonut.com I have old links pointing to the www.
domain so I want those links to return real redirect codes.
View www-chillidonut.ingress.yml
# just an ingress to redirect www.chillidonut.com traffic to chillidonut.com
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: www-chillidonut
annotations:
traefik.ingress.kubernetes.io/redirect-permanent: "true"
traefik.ingress.kubernetes.io/redirect-regex: ^https?://www.chillidonut.com/(.*)
traefik.ingress.kubernetes.io/redirect-replacement: https://chillidonut.com/$1
spec:
rules:
- host: www.chillidonut.com
http:
paths:
- path: /
backend:
serviceName: default
servicePort: 3000
tls:
- hosts:
- www.chillidonut.com
such simple, much wow
This set up works great for me, especially the automated deployments, since I can edit or add content from any device, push it up via git, and have it live within minutes — but it does quickly get complex to set up. You can just as easily build with hugo
on your machine and use gsutil cp . gs://mywebsite.com
to deploy.
I hope you’ve found this helpful if you’re setting up a static website of your own!