mirror of
https://github.com/jbowdre/runtimeterror.git
synced 2024-11-26 08:52:18 +00:00
update draft
This commit is contained in:
parent
d1f2ac7536
commit
1ecdc884b0
2 changed files with 102 additions and 17 deletions
|
@ -1,13 +1,13 @@
|
||||||
---
|
---
|
||||||
title: "Configuring a Custom Font in Hugo"
|
title: "Using a Custom Font with Hugo"
|
||||||
date: 2024-04-23
|
date: 2024-04-23
|
||||||
# lastmod: 2024-04-23
|
# lastmod: 2024-04-23
|
||||||
draft: true
|
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
|
featured: false
|
||||||
toc: true
|
toc: true
|
||||||
comments: true
|
comments: true
|
||||||
categories: Tips # Backstage, ChromeOS, Code, Self-Hosting, VMware
|
categories: Backstage
|
||||||
tags:
|
tags:
|
||||||
- bunny
|
- bunny
|
||||||
- cloudflare
|
- 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.
|
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
|
### 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
|
```css
|
||||||
/* torchlight! {"lineNumbers":true} */
|
/* 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
|
```css
|
||||||
/* font overrides */
|
/* 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
|
#### 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:
|
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-family: 'Berkeley Mono';
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
|
/* use the installed font with this name if it's there... */
|
||||||
src: local('Berkeley Mono'),
|
src: local('Berkeley Mono'),
|
||||||
|
/* otherwise look at these paths */
|
||||||
url('/fonts/BerkeleyMono.woff2') format('woff2'),
|
url('/fonts/BerkeleyMono.woff2') format('woff2'),
|
||||||
url('/fonts/BerkeleyMono.woff') format('woff')
|
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" %}}
|
{{% 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 %}}
|
{{% /notice %}}
|
||||||
|
|
||||||
#### Cloudflare R2
|
#### Cloudflare R2
|
||||||
|
@ -125,9 +127,9 @@ I *eventually* discovered that sometimes you need to clear Cloudflare's cache so
|
||||||
### Bunny Storage
|
### 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.
|
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)
|
![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.
|
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
|
### 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
|
#### 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:
|
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
|
|-- 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
|
```json
|
||||||
"acls": [
|
"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 }}
|
{{ $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
|
```jinja-html
|
||||||
{{ $img := resources.Get "og_base.png" }}
|
{{ $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 ] -->
|
{{ $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
|
#### 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.
|
BIN
content/posts/using-custom-font-hugo/og-sample.png
Normal file
BIN
content/posts/using-custom-font-hugo/og-sample.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 27 KiB |
Loading…
Reference in a new issue