goodbye github pages, also make header look nicer on mobile

This commit is contained in:
Brian Picciano 2021-01-23 17:49:12 -07:00
parent 3a2309c264
commit b2a271128c
5 changed files with 249 additions and 11 deletions

View File

@ -6,12 +6,10 @@ install: result
clean:
rm result
rm -rf _site
serve:
nix-shell -A serve
update:
nix-shell -p bundler --run 'bundler update'
lock:
nix-shell -p bundler -p bundix --run 'bundler lock; bundler package --no-install --path vendor; bundix; rm -rf .bundle vendor'
nix-shell -p bundler --run 'bundler update; bundler lock; bundix; rm -rf .bundle vendor'

View File

@ -12,18 +12,17 @@
in
{
build = derivation {
system = system;
inherit jekyll_env system;
name = "mediocre-blog";
builder = "${pkgs.bash}/bin/bash";
args = [ ./build.sh ];
src = ./src;
stdenv = pkgs.stdenv;
inherit jekyll_env;
};
serve = pkgs.stdenv.mkDerivation rec {
name = "jekyll_env";
serve = pkgs.stdenv.mkDerivation {
name = "mediocre-blog-shell";
# glibcLocales is required so to fill in LC_ALL and other locale
# related environment vars. Without those jekyll's scss compiler
@ -36,6 +35,8 @@
exec ${jekyll_env}/bin/jekyll serve -s ./src -d ./_site -w -I -D -H 0.0.0.0
'';
};
env = jekyll_env;
}

View File

@ -5,7 +5,7 @@ description: >-
A mix of tech, art, travel, and who knows what else.
baseurl: "" # the subpath of your site, e.g. /blog
url: https://blog.mediocregopher.com # the base hostname & protocol for your site, e.g. http://example.com
repository: mediocregopher/blog.mediocregopher.com
repository: https://github.com/mediocregopher/blog.mediocregopher.com
twitter_username: mediocre_gopher
github_username: mediocregopher
rss: rss

View File

@ -1,6 +1,6 @@
<header id="title-header" role="banner">
<div class="row">
<div class="seven columns">
<div class="seven columns" style="margin-bottom: 3rem;">
<h1 class="title">
<a href="{{ "/" | relative_url }}">{{ site.title | escape }}</a>
</h1>
@ -20,7 +20,7 @@
</div>
</div>
{%- if!page.nofollow != true %}
<div class="five columns light" style="text-align: right">
<div class="five columns light">
<span style="display:block; margin-bottom:0.5rem;">Get notified when new posts are published!</span>
<a href="{{ "/follow.html" | relative_url }}"><button class="button-primary">
<i class="fab fa-twitter"></i>

View File

@ -0,0 +1,239 @@
---
title: >-
Goodbye, Github Pages
description: >-
This blog is no longer sponsored by Microsoft!
---
Slowly but surely I'm working on moving my digital life back to being
self-hosted, and this blog was an easy low-hanging fruit to tackle. Previously
the blog was hosted on Github Pages, which was easy enough but also in many ways
restricting. By self-hosting I'm able to have a lot more control over the
generation, delivery, and functionality of the blog.
For reference you can find the source code for the blog at
[{{site.repository}}]({{site.repository}}). Yes, it will one day be hosted
elsewhere as well.
## Nix
Nix is something I'm slowly picking up, but the more I use it the more it grows
on me. Rather than littering my system with ruby versions and packages I'll
never otherwise use, nix allows me to create a sandboxed build pipeline for the
blog with perfectly reproducible results.
The first step in this process is to take the blog's existing `Gemfile.lock` and
turn it into a `gemset.nix` file, which is essentially a translation of the
`Gemfile.lock` into a file nix can understand. There's a tool called
[bundix][bundix] which does this, and it can be used from a nix shell without
having to actually install anything:
```
nix-shell -p bundix --run 'bundix'
```
The second step of using nix is to set up a nix expression in the file
`default.nix`. This will actually build the static files. As a bonus I made my
expression to also allow for serving the site locally with dynamic updating
everytime I change a source file. My `default.nix` looks like this:
```
{
# pkgs refers to all "builtin" nix pkgs and utilities. By importing from a
# URL I'm able to always pin this default.nix to a specific version of those
# packages.
pkgs ? import (fetchTarball "https://github.com/NixOS/nixpkgs/archive/cd63096d6d887d689543a0b97743d28995bc9bc3.tar.gz") {},
system ? builtins.currentSystem,
}:
let
# bundlerEnv looks for a Gemfile, Gemfile.lock, and gemset.nix inside
# gemdir, and derives a package containing ruby and all desired gems.
ruby_env = pkgs.bundlerEnv {
name = "ruby_env";
ruby = pkgs.ruby;
gemdir = ./.;
};
in
{
# build will derive a package which contains the generated static
# files of the blog. It uses the build.sh file (provided below) to
# do this.
build = derivation {
name = "mediocre-blog";
# The build.sh file (source provided below) is executed in order
# to actually build the site.
builder = "${pkgs.bash}/bin/bash";
args = [ ./build.sh ];
# ruby_env is provided as an input to build.sh so that it can
# use jekyll, and the src directory is provided so it can access
# the blog's source files. system is required by the derivation
# function, and stdenv provides standard utilities to build.sh.
inherit ruby_env system;
src = ./src;
stdenv = pkgs.stdenv;
};
# serve will derive an environment specifically tailored for being
# run in a nix-shell. The resulting shell will have ruby_env
# provided for it, and will automatically run the `jekyll serve`
# command to serve the blog locally.
serve = pkgs.stdenv.mkDerivation {
name = "mediocre-blog-shell";
# glibcLocales is required so to fill in LC_ALL and other locale
# related environment vars. Without those jekyll's scss compiler
# fails.
#
# TODO probably get rid of the scss compiler.
buildInputs = [ ruby_env pkgs.glibcLocales ];
shellHook = ''
exec ${ruby_env}/bin/jekyll serve -s ./src -d ./_site -w -I -D
'';
};
}
```
(Nix is a bit tricky to learn, but I highly recommend chapters 14 and 15 of [the
nix manual][manual] for an overview of the language itself, if nothing else.)
The `build.sh` used by the nix expression to actually generate the static files
looks like this:
```bash
# stdenv was given a dependency to build.sh, and so build.sh can use it to
# source in utilities like mkdir, which it needs.
source $stdenv/setup
set -e
# Set up the output directory. nix provides the $out variable which will be the
# root of the derived package's filesystem, but for simplicity later we want to
# output the site within /var/www.
d="$out/var/www/blog.mediocregopher.com"
mkdir -p "$d"
# Perform the jekyll build command. Like stdenv the ruby_env was given as a
# dependency to build.sh, so it has to explicitly use it to have access to
# jekyll. src is another explicit dependency which was given to build.sh, and
# contains all the actual source files within the src directory of the repo.
$ruby_env/bin/jekyll build -s "$src" -d "$d"
```
With these pieces in place I can easily regenerate the site like so:
```
nix-build -A build
```
Once run the static files will exist within a symlink called `result` in the
project's root. Within the symlink will be a `var/www/blog.mediocregopher.com`
tree of directories, and within that will be the generated static files, all
without ever having to have installed ruby.
The expression also allows me to serve the blog while I'm working on it. Doing
so looks like this:
```
nix-shell -A serve
```
When run I get a normal jekyll process running in my `src` directory, serving
the site in real-time on port 4000, once again all without ever installing ruby.
As a final touch I introduced a simple `Makefile` to my repo to wrap these
commands, because even these were too much for me to remember:
```
result:
nix-build -A build
install: result
nix-env -i "$$(readlink result)"
clean:
rm result
rm -rf _site
serve:
nix-shell -A serve
update:
nix-shell -p bundler --run 'bundler update; bundler lock; bundix; rm -rf .bundle vendor'
```
We'll look at that `install` target in the next section.
## nginx
So now I have the means to build my site quickly, reliably, and without
cluttering up the rest of my system. Time to actually serve the files.
My home server has a docker network which houses most of my services that I run,
including nginx. nginx's primary job is to listen on ports 80 and 443, accept
HTTP requests, and direct those requests to their appropriate service based on
their `Host` header. nginx is also great at serving static content from disk, so
I'll take advantage of that for the blog.
The one hitch is that nginx is currently running within a docker container,
as are all my other services. Ideally I would:
* Get rid of the nginx docker container.
* Build a nix package containing nginx, all my nginx config files, and the blog
files themselves.
* Run that directly.
Unfortunately extracting nginx from docker is dependent on doing so for all
other services as well, or at least on running all services on the host network,
which I'm not prepared to do yet. So for now I've done something janky.
If you look at the `Makefile` above you'll notice the `install` target. What
that target does is to install the static blog files to my nix profile, which
exists at `~/.nix-profile`. nix allows any package to be installed to a profile
in this way. All packages within a profile are independent and can be added,
updated, and removed atomically. By installing the built blog package to my
profile I make it available at `~/.nix-profile/var/www/blog.mediocregopher.com`.
So to serve those files via nginx all I need to do is add a read-only volume to
the container...
```
-v $HOME/.nix-profile/var/www/blog.mediocregopher.com:/var/www/blog.mediocregopher.com:ro \
```
...add a new virtual host to my nginx config...
```
server {
listen 80;
server_name blog.mediocregopher.com;
root /var/www/blog.mediocregopher.com;
}
```
...and finally direct the `blog` A record for `mediocregopher.com` to my home
server's IP. Cloudflare will handle TLS on port 443 for me in this case, as well
as hide my home IP, which is prudent.
## Deploying
So now it's time to publish this new post to the blog, what are the actual
steps? It's as easy as:
```
make clean install
```
This will remove any existing `result`, regenerate the site (with the new post)
under a new symlink, and install/update that newer package to my nix profile,
overwriting the previous package which was there.
And that's it! Nix is a cool tool that I'm still getting the hang of, but
hopefully this post might be useful to anyone else thinking of self-hosting
their site.
[jekyll]: https://jekyllrb.com/
[bundix]: https://github.com/nix-community/bundix
[manual]: https://nixos.org/manual/nix/stable/#chap-writing-nix-expressions