update draft

This commit is contained in:
John Bowdre 2024-04-28 21:53:26 -05:00
parent d1f2ac7536
commit 1ecdc884b0
2 changed files with 102 additions and 17 deletions

View file

@ -1,13 +1,13 @@
---
title: "Configuring a Custom Font in Hugo"
title: "Using a Custom Font with Hugo"
date: 2024-04-23
# lastmod: 2024-04-23
draft: true
description: "This is a new post about..."
description: "Installing a custom font on a Hugo site, and taking steps to protect the paid font files from unauthorized distribution. Plus a brief exploration of a pair of storage CDNs, and using Tailscale in a GitHub Actions workflow."
featured: false
toc: true
comments: true
categories: Tips # Backstage, ChromeOS, Code, Self-Hosting, VMware
categories: Backstage
tags:
- bunny
- cloudflare
@ -17,10 +17,10 @@ tags:
---
Last week, I came across and immediately fell in love with a delightfully-retro monospace font called [Berkeley Mono](https://berkeleygraphics.com/typefaces/berkeley-mono/). I promptly purchased a "personal developer" license and set to work [applying the font in my IDE and terminal](https://scribbles.jbowdre.lol/post/trying-tabby-terminal). I didn't want to stop there, though; the license also permits me to use the font on my personal site, and Berkeley Mono will fit in beautifully with the whole runtimeterror aesthetic.
Long story short, you're looking at a slick new font here. Long story long: I'm about to tell you how I added the font both to the site and to the [dynamically-generated OpenGraph share images](/dynamic-opengraph-images-with-hugo/) setup. It wasn't terribly hard to implement, but the Hugo documentation is a bit light on how to do it (and I'm kind of inept at this whole web development thing).
Well, you're looking at the slick new font here, and I'm about to tell you how I added the font both to the site itself and to the [dynamically-generated OpenGraph share images](/dynamic-opengraph-images-with-hugo/) setup. It wasn't terribly hard to implement, but the Hugo documentation is a bit light on how to do it (and I'm kind of inept at this whole web development thing).
### Web Font
The [risotto theme for Hugo](https://github.com/joeroe/risotto/tree/main) upon which this site is based defines the default font face(s) as the variable `--font-monospace` in `themes/risotto/static/css/typography.css`, and then that variable is inserted wherever the font may need to be set:
This site's styling is based on the [risotto theme for Hugo](https://github.com/joeroe/risotto/tree/main). Risotto uses the CSS variable `--font-monospace` in `themes/risotto/static/css/typography.css` to define the font face, and then that variable is inserted wherever the font may need to be set:
```css
/* torchlight! {"lineNumbers":true} */
@ -36,7 +36,7 @@ body {
}
```
This makes it easy to override the theme's font by referencing my preferred font in `static/custom.css`:
This makes it easy to override the theme's font by inserting my preferred font in `static/custom.css`:
```css
/* font overrides */
@ -54,7 +54,7 @@ And that would be the end of things if I could expect that everyone who visited
}
```
That gives me a few more fallback fonts to fall back to if my preferred font isn't available. But let's see about making that font available.
That provides a few more options to fall back to if the preferred font isn't available. But let's see about making that font available.
#### Hosted Locally
I can use a `@font-face` rule to tell the browser how to find the `.woff2`/`.woff` files for my preferred web font, and I could just set the `src: url` parameter to point to a local path in my Hugo environment:
@ -65,18 +65,20 @@ I can use a `@font-face` rule to tell the browser how to find the `.woff2`/`.wof
font-family: 'Berkeley Mono';
font-style: normal;
font-weight: 400;
/* use the installed font with this name if it's there... */
src: local('Berkeley Mono'),
/* otherwise look at these paths */
url('/fonts/BerkeleyMono.woff2') format('woff2'),
url('/fonts/BerkeleyMono.woff') format('woff')
}
```
And that would work just fine... but it *would* require storing those web font files in the GitHub repo which powers my site, and I'd rather not host any paid font files in such a way.
And that would work just fine... but it *would* require storing those web font files in the (public) [GitHub repo](https://github.com/jbowdre/runtimeterror) which powers my site, and I'd rather not store any paid font files there.
So instead, I opted to store the web font files in a CDN, where I could exercise some degree of access control, learn more about a web technology I haven't played with a whole lot, and make use of a cool `cdn.runtimeterror.dev` subdomain in the process.
So instead, I opted to try using a [Content Delivery Network (CDN)](https://en.wikipedia.org/wiki/Content_delivery_network) to host the font files. This would allow for some degree of access control, help me learn more about a web technology I hadn't played with much, and make use of a cool `cdn.*` subdomain in the process.
{{% notice note "Double the CDN, double the fun" %}}
Of course, while writing this post I gave in to my impulsive nature and [migrated the site from Cloudflare to Bunny.net](https://scribbles.jbowdre.lol/post/i-just-hopped-to-bunny-net). So I'm going to briefly describe how I set this up first on [Cloudflare R2](https://www.cloudflare.com/developer-platform/r2/) and later on [Bunny Storage](https://bunny.net/storage/).
Of course, while writing this post I gave in to my impulsive nature and [migrated the site from Cloudflare to Bunny.net](https://scribbles.jbowdre.lol/post/i-just-hopped-to-bunny-net). Rather than scrap the content I'd already written, I'll go ahead and describe how I set this up first on [Cloudflare R2](https://www.cloudflare.com/developer-platform/r2/) and later on [Bunny Storage](https://bunny.net/storage/).
{{% /notice %}}
#### Cloudflare R2
@ -125,9 +127,9 @@ I *eventually* discovered that sometimes you need to clear Cloudflare's cache so
### Bunny Storage
After migrating my domain to Bunny.net, the CDN font setup was pretty similar - but also different enough that it's worth mentioning. I started by creating a new Storage Zone named `runtimeterror-storage`, and selecting an appropriate-seeming set of replication regions. I then uploaded the same `fonts/` folder as before.
To be able to access the files in Bunny Storage, I then connected a new Pull Zone (called `runtimeterror-pull`) and linked that Pull Zone with the `cdn.runtimeterror.dev` hostname. I also made sure to enable the option to automatically generate a certificate for this host.
To be able to access the files in Bunny Storage, I connected a new Pull Zone (called `runtimeterror-pull`) and linked that Pull Zone with the `cdn.runtimeterror.dev` hostname. I also made sure to enable the option to automatically generate a certificate for this host.
Rather than needing me to understand CORS and craft a viable policy file, Bunny provides a clean UI with easy-to-understand options for configuring the pull zone security. I enabled the options to block root path access, block `POST` requests, and block direct file access, and also added the same trusted referrers as before:
Rather than needing me to understand CORS and craft a viable policy file, Bunny provides a clean UI with easy-to-understand options for configuring the pull zone security. I enabled the options to block root path access, block `POST` requests, block direct file access, and also added the same trusted referrers as before:
![Bunny CDN security configuration](bunny-cdn-security.png)
@ -146,12 +148,14 @@ I made sure to use the same paths as I had on Cloudflare so I didn't need to upd
}
```
I again tested locally with `hugo server` and confirmed that the font loaded from Bunny CDN without any CORS or other errors.
So that's the web font for the web site sorted (twice); now let's tackle the font in the OpenGraph share images.
### Image Filter Text
My [setup for generating the share images](/dynamic-opengraph-images-with-hugo/) leverages the Hugo [images.Text](https://gohugo.io/functions/images/text/) function to overlay text onto a background image, and it needs a TrueType font in order to work. I was previously just storing the required font directly in my GitHub repo so that it would be available during the site build, but I definitely don't want to do that with a paid font file. So I needed to come up with some way to provide the TTF file to the builder without making it publicly available.
My [setup for generating the share images](/dynamic-opengraph-images-with-hugo/) leverages the Hugo [images.Text](https://gohugo.io/functions/images/text/) function to overlay text onto a background image, and it needs a TrueType font in order to work. I was previously just storing the required font directly in my GitHub repo so that it would be available during the site build, but I definitely don't want to do that with a paid TrueType font file. So I needed to come up with some way to provide the TTF file to the GitHub runner without making it publicly available.
I recently figured out how I could [use a GitHub Action to easily connect the builder to my Tailscale environment](/gemini-capsule-gempost-github-actions/#publish-github-actions:~:text=name%3A%20Connect%20to%20Tailscale), and I figured I could re-use that idea here - only instead of pushing something to my tailnet, I'll need to pull something out.
I recently figured out how I could [use a GitHub Action to easily connect the runner to my Tailscale environment](/gemini-capsule-gempost-github-actions/#publish-github-actions:~:text=name%3A%20Connect%20to%20Tailscale), and I figured I could re-use that idea here - only instead of pushing something to my tailnet, I'll be pulling something out.
#### Tailscale Setup
So I SSH'd to the cloud server I'm already using for hosting my Gemini capsule, created a folder to hold the font file (`/opt/fonts/`), and copied the TTF file into there. And then I used [Tailscale Serve](/tailscale-ssh-serve-funnel/#tailscale-serve) to publish that folder internally to my tailnet:
@ -165,7 +169,9 @@ https://node.tailnet-name.ts.net/fonts/
|-- path /opt/fonts
```
Last time, I set up the Tailscale ACL so that the GitHub Runner (`tag:gh-bld`) could talk to my server (`tag:gh-srv`) over SSH:
The `--bg` flag will run the share in the background and automatically start it with the system (like a daemon-mode setup).
When I set up Tailscale for the Gemini capsule workflow, I configured the Tailscale ACL so that the GitHub runner (`tag:gh-bld`) could talk to my server (`tag:gh-srv`) over SSH:
```json
"acls": [
@ -234,7 +240,11 @@ Here's the image-related code that I was previously using in `layouts/partials/o
{{ $img = resources.Copy (path.Join $.Page.RelPermalink "og.png") $img }}
```
All I need to do is get it to pull the font resource from a web address rather than the local file system, and I'll do that by loading an environment variable instead of hardcoding the path here:
All I need to do is get it to pull the font resource from a web address rather than the local file system, and I'll do that by loading an environment variable instead of hardcoding the path here.
{{% notice note "Hugo Environent Variable Access" %}}
By default, Hugo's `os.Getenv` function only has access to environment variables which start with `HUGO_`. You can [adjust the security configuration](https://gohugo.io/functions/os/getenv/#security) to alter this restriction if needed, but I figured I could work just fine within the provided constraints.
{{% /notice %}}
```jinja-html
{{ $img := resources.Get "og_base.png" }}
@ -279,5 +289,80 @@ All I need to do is get it to pull the font resource from a web address rather t
{{ $img = resources.Copy (path.Join $.Page.RelPermalink "og.png") $img }} <!-- [tl! collapse:end ] -->
```
I can test that this works by running a build locally from a system with access to my tailnet. I'm not going to start a web server with this build; I'll just review the contents of the `public/` folder once it's complete to see if the OpenGraph images got rendered correctly.
```shell
HUGO_REMOTE_FONT_PATH=https://node.tailnet-name.ts.net/fonts/BerkeleyMono.ttf hugo
```
Neat, it worked!
![OpenGraph share image for this post](og-sample.png)
#### GitHub Action
All that's left is to update the GitHub Action to handle the build for me.
All that's left is to update the GitHub Actions workflow I use for [building and deploying my site to Neocities](/deploy-hugo-neocities-github-actions/) to automate things:
```yaml
# torchlight! {"lineNumbers": true}
# .github/workflows/deploy-to-neocities.yml
name: Deploy to Neocities
# [tl! collapse:start]
on:
schedule:
- cron: 0 13 * * *
push:
branches:
- main
concurrency:
group: deploy-to-neocities
cancel-in-progress: true
defaults:
run:
shell: bash
# [tl! collapse:end]
jobs:
deploy:
name: Build and deploy Hugo site
runs-on: ubuntu-latest
steps:
- name: Hugo setup
uses: peaceiris/actions-hugo@v2.6.0
with:
hugo-version: '0.121.1'
extended: true
- name: Checkout
uses: actions/checkout@v4
with:
submodules: recursive
- name: Connect to Tailscale # [tl! ++:10 **:10]
uses: tailscale/github-action@v2
with:
oauth-client-id: ${{ secrets.TS_API_CLIENT_ID }}
oauth-secret: ${{ secrets.TS_API_CLIENT_SECRET }}
tags: ${{ secrets.TS_TAG }}
- name: Build with Hugo
run: hugo --minify # [tl! -- **]
run: HUGO_REMOTE_FONT_PATH=${{ secrets.REMOTE_FONT_PATH }} hugo --minify # [tl! ++ ** reindex(-1) ]
- name: Insert 404 page
run: |
cp public/404/index.html public/not_found.html
- name: Highlight with Torchlight
run: |
npm i @torchlight-api/torchlight-cli
npx torchlight
- name: Deploy to Neocities
uses: bcomnes/deploy-to-neocities@v1
with:
api_token: ${{ secrets.NEOCITIES_API_TOKEN }}
cleanup: true
dist_dir: public
```
This uses the [Tailscale GitHub Action](https://github.com/tailscale/github-action) to connect the runner to my tailnet using the credentials I created earlier, and passes the `REMOTE_FONT_PATH` secret as an environment variable to the Hugo command line. Hugo will then be able to retrieve and use the TTF font during the build process.
### Conclusion
Configuring and using a custom font in my Hugo-generated site wasn't hard to do, but I had to figure some things out on my own to get started in the right direction. I learned a lot about how fonts are managed in CSS along the way, and I love the way the new font looks on this site!
This little project also gave me an excuse to play with first Cloudflare R2 and then Bunny Storage, and I came away seriously impressed by Bunny (and have since moved more of my domains to bunny.net). Expect me to write more about cool Bunny stuff in the future.

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB