My frontend experience is very limited. For a long time, I was resistant to tools and frameworks. I would prefer vanilla JavaScript, HTML, and CSS over React, Vue, or Angular. I picked up just enough ops experience to clumsily make updates to websites, but I’ve recently found a much better system using Hugo and GitHub Actions.
Hugo ๐
Even though I’m comfortable editing HTML, I much prefer writing in markdown. Thus, I set out looking for a way to convert markdown to HTML. Some options I found include Gatsby, Hugo, and Next.
Gatsby and Next are very popular, but written in JavaScript and require Node be setup on any dev’s machine. Hugo stood out to me because it could run directly on the dev’s system. It’s written in go, but available via standard package managers - homebrew, chocolatey, apt-get, etc. It seems like Gatsby and Next are very feature-rich, but Hugo was right for my simple usecase.
To setup a Hugo site, use the command hugo new site $SITE_NAME
. This sets up some folders for static web content for things like css and images. It also generates a config.yaml
(or config.toml
), which is the source of your control over Hugo.
The next step is to include a theme. Hugo’s site has a list of themes to browse, but these can be found, shared, or developed. Git submodules are the standard way of integrating themes. The config can be altered to have variations in the theme.
Adding new content is then as simple as running hugo new posts/$NAME_OF_POST.md
. This creates a new markdown file in a content
folder under posts/
. Running hugo -D
will then output HTML files in the public
folder, which can be distributed as a website.
GitHub Actions ๐
By hosting my code on GitHub I get access to their CI/CD. My goals for the GitHub Actions workflow are simple:
- build a distributable website
- deploy it to my Digital Ocean droplet
I found a Hugo action that can easily achieve step 1:
- name: Setup Hugo
uses: peaceiris/actions-hugo@v2.5.0
with:
hugo-version: '0.101.0'
- name: Prepare Hugo
run: |
git submodule sync && git submodule update --init
- name: Build
run: hugo -D
And I found an scp action for step 2:
- name: Copy file via scp
uses: appleboy/scp-action@v0.1.3
with:
host: ${{ secrets.HOST }}
username: ${{ secrets.USERNAME }}
password: ${{ secrets.PASSWORD }}
port: ${{ secrets.PORT }}
source: "public/"
target: "/var/www/gioandjake.com/html/blog/"
strip_components: 1
Infrastructure ๐
I have been using Digital Ocean for my hosting needs since I was a student (and got that sweet student discount ๐). I already have a domain and partial site setup, so I don’t want to create anything new, but mount this new blog to my existing site.
There were some updates I needed to make to my nginx configuration on my Ubuntu droplet. Specifically, adding a location block in /etc/nginx/sites-available/gioandjake.com.conf
.
location /blog/ {
autoindex on;
}
Because of this specific configuration, it was necessary to include strip_components: 1
in my scp action. It is also important to not include ./
in your source
if you don’t want it included in the final target output.
Updating the Blog ๐
This setup has made updating the blog very simple. All I need to do is create a new markdown file in content/posts
(or update an existing markdown file) and open a PR with the change to main
. The workflow is triggered on PR’s, so it will build and deploy the new changes automatically.