Compare commits
20 Commits
0fce11557a
...
20251118
| Author | SHA1 | Date | |
|---|---|---|---|
|
6d54cbef61
|
|||
|
3062cba541
|
|||
|
f0810eb8e5
|
|||
|
c8684d2d96
|
|||
|
550524cb1a
|
|||
|
4918cef5e6
|
|||
|
bbb21b34dd
|
|||
|
24d66c2fea
|
|||
|
df143c30cc
|
|||
|
9df2de9207
|
|||
|
217779d89a
|
|||
|
18b99e91b3
|
|||
|
6d7d641bc2
|
|||
|
c67fe08a33
|
|||
|
0218c47f2b
|
|||
|
dac497d685
|
|||
|
1e6a3d2596
|
|||
|
a63267ffc2
|
|||
|
b470196abb
|
|||
|
30815a3408
|
9
Caddyfile
Normal file
9
Caddyfile
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
default_sni web
|
||||||
|
}
|
||||||
|
|
||||||
|
https:// {
|
||||||
|
tls /tls/tls.crt /tls/tls.key
|
||||||
|
root * /srv
|
||||||
|
file_server
|
||||||
|
}
|
||||||
16
Dockerfile
Normal file
16
Dockerfile
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
# Package versions
|
||||||
|
ARG HUGO_VERSION="0.152.2"
|
||||||
|
ARG CADDY_VERSION="2.10.2"
|
||||||
|
|
||||||
|
# Stage 1: Build
|
||||||
|
FROM core.harbor.brds.ca/d-b.ca/hugo-builder:${HUGO_VERSION} AS builder
|
||||||
|
WORKDIR /project
|
||||||
|
COPY . .
|
||||||
|
RUN hugo --minify build
|
||||||
|
|
||||||
|
# Stage 2: Package
|
||||||
|
FROM docker.io/caddy:${CADDY_VERSION}
|
||||||
|
COPY Caddyfile /etc/caddy/Caddyfile
|
||||||
|
COPY --from=builder /project/public /srv
|
||||||
|
# tls.crt and tls.key should be mounted here at runtime.
|
||||||
|
VOLUME /tls
|
||||||
@@ -1,3 +1,3 @@
|
|||||||
# web
|
# Drew Bowering's Website
|
||||||
|
|
||||||
My personal website at https://www.d-b.ca/
|
My personal website at [https://www.d-b.ca/](https://www.d-b.ca/)
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ title = "Drew Bowering"
|
|||||||
headline = "IT Architect, Developer, Canoeist, Tubist"
|
headline = "IT Architect, Developer, Canoeist, Tubist"
|
||||||
# bio = "A little bit about me"
|
# bio = "A little bit about me"
|
||||||
links = [
|
links = [
|
||||||
# { email = "mailto:hello@your_domain.com" },
|
{ email = "mailto:drew@d-b.ca" },
|
||||||
# { link = "https://link-to-some-website.com/" },
|
# { link = "https://link-to-some-website.com/" },
|
||||||
# { amazon = "https://www.amazon.com/hz/wishlist/ls/wishlist-id" },
|
# { amazon = "https://www.amazon.com/hz/wishlist/ls/wishlist-id" },
|
||||||
# { apple = "https://www.apple.com" },
|
# { apple = "https://www.apple.com" },
|
||||||
|
|||||||
@@ -24,11 +24,11 @@ disableTextInHeader = false
|
|||||||
defaultBackgroundImage = "img/BG_Jasper.jpg" # used as default for background images
|
defaultBackgroundImage = "img/BG_Jasper.jpg" # used as default for background images
|
||||||
# defaultFeaturedImage = "IMAGE.jpg" # used as default for featured images in all articles
|
# defaultFeaturedImage = "IMAGE.jpg" # used as default for featured images in all articles
|
||||||
|
|
||||||
# highlightCurrentMenuArea = true
|
highlightCurrentMenuArea = true
|
||||||
# smartTOC = true
|
smartTOC = true
|
||||||
# smartTOCHideUnfocusedChildren = true
|
smartTOCHideUnfocusedChildren = false
|
||||||
|
|
||||||
giteaDefaultServer = "https://git.fsfe.org"
|
giteaDefaultServer = "https://git.brds.ca"
|
||||||
forgejoDefaultServer = "https://v8.next.forgejo.org"
|
forgejoDefaultServer = "https://v8.next.forgejo.org"
|
||||||
|
|
||||||
[header]
|
[header]
|
||||||
@@ -44,7 +44,7 @@ forgejoDefaultServer = "https://v8.next.forgejo.org"
|
|||||||
[homepage]
|
[homepage]
|
||||||
layout = "background" # valid options: page, profile, hero, card, background, custom
|
layout = "background" # valid options: page, profile, hero, card, background, custom
|
||||||
#homepageImage = "IMAGE.jpg" # used in: hero, and card
|
#homepageImage = "IMAGE.jpg" # used in: hero, and card
|
||||||
showRecent = false
|
showRecent = true
|
||||||
showRecentItems = 5
|
showRecentItems = 5
|
||||||
showMoreLink = false
|
showMoreLink = false
|
||||||
showMoreLinkDest = "/posts/"
|
showMoreLinkDest = "/posts/"
|
||||||
@@ -60,8 +60,8 @@ forgejoDefaultServer = "https://v8.next.forgejo.org"
|
|||||||
showDateUpdated = false
|
showDateUpdated = false
|
||||||
showAuthor = true
|
showAuthor = true
|
||||||
# showAuthorBottom = false
|
# showAuthorBottom = false
|
||||||
showHero = false
|
showHero = true
|
||||||
# heroStyle = "basic" # valid options: basic, big, background, thumbAndBackground
|
heroStyle = "background" # valid options: basic, big, background, thumbAndBackground
|
||||||
layoutBackgroundBlur = true # only used when heroStyle equals background or thumbAndBackground
|
layoutBackgroundBlur = true # only used when heroStyle equals background or thumbAndBackground
|
||||||
layoutBackgroundHeaderSpace = true # only used when heroStyle equals background
|
layoutBackgroundHeaderSpace = true # only used when heroStyle equals background
|
||||||
showBreadcrumbs = false
|
showBreadcrumbs = false
|
||||||
@@ -74,7 +74,7 @@ forgejoDefaultServer = "https://v8.next.forgejo.org"
|
|||||||
showPagination = true
|
showPagination = true
|
||||||
invertPagination = false
|
invertPagination = false
|
||||||
showReadingTime = true
|
showReadingTime = true
|
||||||
showTableOfContents = false
|
showTableOfContents = true
|
||||||
# showRelatedContent = false
|
# showRelatedContent = false
|
||||||
# relatedContentLimit = 3
|
# relatedContentLimit = 3
|
||||||
showTaxonomies = false
|
showTaxonomies = false
|
||||||
@@ -84,12 +84,12 @@ forgejoDefaultServer = "https://v8.next.forgejo.org"
|
|||||||
showZenMode = false
|
showZenMode = false
|
||||||
|
|
||||||
[list]
|
[list]
|
||||||
showHero = false
|
showHero = true
|
||||||
# heroStyle = "background" # valid options: basic, big, background, thumbAndBackground
|
heroStyle = "background" # valid options: basic, big, background, thumbAndBackground
|
||||||
layoutBackgroundBlur = true # only used when heroStyle equals background or thumbAndBackground
|
layoutBackgroundBlur = true # only used when heroStyle equals background or thumbAndBackground
|
||||||
layoutBackgroundHeaderSpace = true # only used when heroStyle equals background
|
layoutBackgroundHeaderSpace = true # only used when heroStyle equals background
|
||||||
showBreadcrumbs = false
|
showBreadcrumbs = false
|
||||||
showSummary = false
|
showSummary = true
|
||||||
showViews = false
|
showViews = false
|
||||||
showLikes = false
|
showLikes = false
|
||||||
showTableOfContents = false
|
showTableOfContents = false
|
||||||
|
|||||||
BIN
content/posts/new-website/featured.png
Normal file
BIN
content/posts/new-website/featured.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1022 KiB |
198
content/posts/new-website/index.md
Normal file
198
content/posts/new-website/index.md
Normal file
@@ -0,0 +1,198 @@
|
|||||||
|
---
|
||||||
|
title: "New Website"
|
||||||
|
date: "2025-06-12T08:00:00-06:00"
|
||||||
|
description: "There's finally a new website at d-b.ca."
|
||||||
|
summary: "I've published my personal website. A brief history of some past endeavours, and some details on the technology behind the new site."
|
||||||
|
---
|
||||||
|
|
||||||
|
I've finally published a proper website at [https://d-b.ca/](https://d-b.ca/).
|
||||||
|
The last time I had anything live on this domain was over 20 years ago,
|
||||||
|
according to the [Wayback Machine](https://web.archive.org/). What took so
|
||||||
|
long? The truth is, my interests have shifted over the years, and I've been
|
||||||
|
learning a lot. This site, while useful in its own right, is really a
|
||||||
|
culmination of a personal platform I've developed over time.
|
||||||
|
|
||||||
|
## History
|
||||||
|
|
||||||
|
My first personal website was developed while I was a student at the
|
||||||
|
[University of Alberta](https://ualberta.ca), near the end of the previous
|
||||||
|
century. The web was still in its early stages, but the university provided
|
||||||
|
students with the means to publish web content. It was mostly a novelty at the
|
||||||
|
time and didn't last beyond my time at school, but it sparked my interest in
|
||||||
|
Internet technologies and their applications.
|
||||||
|
|
||||||
|
That early site included one interesting feature. I developed a mechanism to
|
||||||
|
automatically update a page every time I logged into one of the school's
|
||||||
|
computers, so my friends could find me if they wanted to. At the time,
|
||||||
|
dynamically updating websites was a tricky thing. The most common way was
|
||||||
|
using [CGI](https://en.wikipedia.org/wiki/Common_Gateway_Interface), which is
|
||||||
|
like having a tiny program run every time someone requested a page. The
|
||||||
|
university did not allow student sites to use it. So, I wrote some shell
|
||||||
|
scripts that were called as part of my login and logout scripts that would
|
||||||
|
generate the static HTML file and write it to my web content directory. It
|
||||||
|
needed to handle cases like multiple logins, and the logout script didn't
|
||||||
|
always get triggered, so I'd have to keep an eye on it for stale entries.
|
||||||
|
|
||||||
|
### Self-Hosting
|
||||||
|
|
||||||
|
I've always been an avid self-hoster. Learning by getting a system up and
|
||||||
|
running works well for me. I also value the privacy and control that it
|
||||||
|
provides. Plus, it's much cheaper for me in the long run!
|
||||||
|
|
||||||
|
It really began when I was working at a local Internet service provider. I was
|
||||||
|
able to get a special deal on a good broadband connection at home, which
|
||||||
|
included a small network block (a `/28`, consisting of 16 IP addresses) that I
|
||||||
|
could use. I dedicated my largest machine as my server and developed several
|
||||||
|
services, including a new website.
|
||||||
|
|
||||||
|
My website at that time wasn't fancy, and was geared primarily towards
|
||||||
|
experimentation. I developed a simple content management system from scratch
|
||||||
|
in PHP, which I used to publish a blog. It also integrated with mailing
|
||||||
|
lists, another area I was exploring at the time.
|
||||||
|
|
||||||
|
### D-B.CA
|
||||||
|
|
||||||
|
I hadn't registered a domain name of my own in those early days, so everything
|
||||||
|
resided under a friend's domain. In late 2002, I decided to finally register
|
||||||
|
one of my own, primarily so I could have a stable email address. I wanted to
|
||||||
|
incorporate the initials in my name, so I came up with `d-b.ca`. This was a
|
||||||
|
compromise because someone was squatting on `db.ca` at the time, and, to my
|
||||||
|
knowledge, they still are.
|
||||||
|
|
||||||
|
Early on, I focused mostly on operating my email services and other
|
||||||
|
experiments, with little attention paid to a website. There were a few test
|
||||||
|
pages at times, but nothing substantial.
|
||||||
|
|
||||||
|
## Modern Technology
|
||||||
|
|
||||||
|
One of the projects I've been following is [Hugo](https://gohugo.io/). I've
|
||||||
|
seen and worked with various web content management systems in the past, and
|
||||||
|
they often feel cumbersome and present security concerns. Hugo is an example
|
||||||
|
of a "Static Site Generator." Think of it like this: instead of creating web
|
||||||
|
pages on the fly every time someone visits, Hugo takes all the raw content and
|
||||||
|
turns it into a set of ready-to-serve files, much like a compiler turns code
|
||||||
|
into an executable program. The resulting static resources can be served as
|
||||||
|
regular files from any web service, without the need for dynamically
|
||||||
|
generating content upon request from a database, as traditional CMS systems
|
||||||
|
do.
|
||||||
|
|
||||||
|
Using Hugo is much easier with a solid base template. There are
|
||||||
|
[many to choose from](https://themes.gohugo.io/), including the one I've
|
||||||
|
selected here called ["Blowfish"](https://blowfish.page/). I like how it
|
||||||
|
looks, and it supports the style of site that this is very well.
|
||||||
|
|
||||||
|
Another benefit of a static site generator is that all the sources for the
|
||||||
|
site can be treated like software code, making it simple to use development
|
||||||
|
tools like [Git](https://git-scm.com/) for version control. I keep the sources
|
||||||
|
for this site in a public repository on my own Git server. Feel free to take a
|
||||||
|
look:
|
||||||
|
|
||||||
|
{{< gitea repo="d-b.ca/web" >}}
|
||||||
|
|
||||||
|
### CI/CD
|
||||||
|
|
||||||
|
I've also set up a CI/CD pipeline to build and deploy the site whenever
|
||||||
|
changes are made to the source repository. What does this mean?
|
||||||
|
|
||||||
|
**CI** = *Continuous Integration*
|
||||||
|
> This is the practice of frequently integrating changes into a source
|
||||||
|
> repository. The changes are checked, assembled, and packaged through
|
||||||
|
> automated processes. [More information](https://martinfowler.com/articles/continuousIntegration.html)
|
||||||
|
|
||||||
|
**CD** = *Continuous Delivery*
|
||||||
|
> This is the capability of being able to take new changes (such as the
|
||||||
|
> outputs of the CI process) and getting them deployed and running
|
||||||
|
> automatically. [More information](https://continuousdelivery.com/)
|
||||||
|
|
||||||
|
The CI portion is triggered by a push to the
|
||||||
|
[`web`](https://git.brds.ca/d-b.ca/web) repository. It runs an automated
|
||||||
|
workflow that builds the site and packages the resulting artifacts into a
|
||||||
|
container image based on the [Caddy](https://caddyserver.com/) web server.
|
||||||
|
|
||||||
|
A container image is like a pre-packaged software environment that ensures the
|
||||||
|
website runs consistently regardless of the underlying infrastructure. The
|
||||||
|
resulting image contains everything the website needs to operate and can run
|
||||||
|
on any infrastructure that can support it, such as my own laptop or my server
|
||||||
|
cluster.
|
||||||
|
|
||||||
|
The build container with Hugo is another image that is only used to create the
|
||||||
|
website container. I maintain it in this repository:
|
||||||
|
|
||||||
|
{{< gitea repo="d-b.ca/hugo-builder" >}}
|
||||||
|
|
||||||
|
After the workflow has built the container image for running the website, it
|
||||||
|
updates the CD GitOps repository to deploy this new version immediately to a
|
||||||
|
private staging site. Another definition:
|
||||||
|
|
||||||
|
> **GitOps** refers to the practice of managing infrastructure automation by
|
||||||
|
> keeping machine-readable descriptions of the intended infrastructure in a
|
||||||
|
> version-controlled Git repository. A CD system will monitor the repository
|
||||||
|
> for changes, immediately adding, modifying, or removing infrastructure to
|
||||||
|
> bring the state of the operational system into alignment with the source
|
||||||
|
> description.
|
||||||
|
|
||||||
|
There are many benefits to managing infrastructure this way. Changes are
|
||||||
|
automatically tracked because everything is stored in an existing code
|
||||||
|
repository system that's specifically designed for managing and tracking
|
||||||
|
change. Problematic changes can be reverted easily by reverting the change in
|
||||||
|
the repository. Automation keeps things in sync at all times - any changes
|
||||||
|
made manually outside of this system are immediately spotted and removed.
|
||||||
|
|
||||||
|
When I want to publish the new version as the production website, I use my
|
||||||
|
regular private production GitOps repository to update the image version tag,
|
||||||
|
and the rest happens automatically. The CD repository for the staging site is
|
||||||
|
public, you're welcome to check it out here:
|
||||||
|
|
||||||
|
{{< gitea repo="d-b.ca/db-cd" >}}
|
||||||
|
|
||||||
|
#### Pipeline Diagram
|
||||||
|
|
||||||
|
{{< mermaid >}}
|
||||||
|
flowchart TB
|
||||||
|
subgraph GIT [Git Repository]
|
||||||
|
WR[(Web)]
|
||||||
|
CDR[(CD)]
|
||||||
|
end
|
||||||
|
|
||||||
|
WP(Push Web Updates)-->WR
|
||||||
|
WP ~~~ HBI
|
||||||
|
|
||||||
|
subgraph CI [CI Workflow]
|
||||||
|
CIP[Pull Source
|
||||||
|
Repository]-->BWI[Build Web
|
||||||
|
Image]
|
||||||
|
BWI-->PWI[Push Web
|
||||||
|
Image]
|
||||||
|
PWI-->UCD[Update CD
|
||||||
|
Repository]
|
||||||
|
end
|
||||||
|
|
||||||
|
PWI-->WI
|
||||||
|
WR-->CIP
|
||||||
|
|
||||||
|
subgraph DOCKER [Image Repository]
|
||||||
|
HBI((Hugo
|
||||||
|
Build))
|
||||||
|
WI((Web))
|
||||||
|
end
|
||||||
|
|
||||||
|
HBI-->BWI
|
||||||
|
|
||||||
|
UCD-->CDP(Push Image
|
||||||
|
Update)
|
||||||
|
CDP-->CDR
|
||||||
|
CDR-->CDPull
|
||||||
|
|
||||||
|
subgraph CD [CD Process]
|
||||||
|
CDPull[Pull Source Repository]-->DWI[Deploy Web Image]
|
||||||
|
end
|
||||||
|
|
||||||
|
WI-->DWI
|
||||||
|
{{< /mermaid >}}
|
||||||
|
|
||||||
|
## Underlying Platform
|
||||||
|
|
||||||
|
In future articles, I'll describe the evolution of the physical network and
|
||||||
|
systems this site is running on, and how they enabled me to build a
|
||||||
|
[Kubernetes](https://kubernetes.io/) cluster to scale this site and run other
|
||||||
|
services, all on hardware I assembled myself!
|
||||||
4
go.mod
4
go.mod
@@ -1,5 +1,5 @@
|
|||||||
module git.brds.ca/drew/web
|
module git.brds.ca/drew/web
|
||||||
|
|
||||||
go 1.24.2
|
go 1.25.4
|
||||||
|
|
||||||
require github.com/nunocoracao/blowfish/v2 v2.85.1 // indirect
|
require github.com/nunocoracao/blowfish/v2 v2.92.0 // indirect
|
||||||
|
|||||||
4
go.sum
4
go.sum
@@ -1,2 +1,2 @@
|
|||||||
github.com/nunocoracao/blowfish/v2 v2.85.1 h1:+wdHZ6kozmybTprY8RHFdumeg4lB8r5xmRy2FfQcweo=
|
github.com/nunocoracao/blowfish/v2 v2.92.0 h1:1EgHMRaY6VI438TIAN/5luNx16lg1e0Lrbi+6kDxpdA=
|
||||||
github.com/nunocoracao/blowfish/v2 v2.85.1/go.mod h1:4SkMc+Ht8gpQCwArqiHMBDP3soxi2OWuAhVney+cuyk=
|
github.com/nunocoracao/blowfish/v2 v2.92.0/go.mod h1:4SkMc+Ht8gpQCwArqiHMBDP3soxi2OWuAhVney+cuyk=
|
||||||
|
|||||||
Reference in New Issue
Block a user