Sunday, May 5, 2019

Using Hugo Without a Theme

Hugo is a very powerful site generator, and includes plenty of features for large static sites. Most tutorials focus on how to quickly get a nice-looking site using a theme.

What if you're coming from the other direction, however? Maybe you want to extend an existing single-page site to multiple pages without totally structuring it (or copying and pasting the common bits). Or maybe you're perfectly happy to write your own CSS. Hugo is still a great tool!

Just show me an example!

You don't have to read any of this post if you don't want to -- just see the hugo-skel repository in Github.

The explanation

(This isn't meant to be a standalone post -- It's helpful to work through the Hugo quickstart guide, at least, to get familiar with Hugo's terminology and basic structure.)

The gist of it is, look at the base template lookup order, which shows that you can use the layouts directory instead of the themes directory to find templates.

  • All you really need is layouts/_default/baseof.html -- that's the base template for all other types of pages. This is where you write "<!DOCTYPE html><html lang="en"><head> [...]".
  • To define actual pages, put them in content just as you would if you were using a theme. Here's a minimal example:
    title: "Main page"
    <p>This is the main page content.</p>
  • Put your static files (CSS, Javascript) in the static directory.
  • You'll get warnings if you don't define at least a few other specific templates:
    • Hugo will give warnings on site generation unless you have (assuming we're putting everything in the layouts directory): layouts/index.html and layouts/_default/single.html. To (mostly) avoid duplicating template logic, you can have them reference your baseof.html: Where you'll want the main content of your pages, define a "main" block in baseof.html like this:
      {{ block "main" . }}{{ .Content }}{{ end}}
    • Now, you can write a minimal template in layouts/index.html -- layouts/_default/single.html: Put the following in both files to override the "main" block from baseof.html with an empty string:
      {{ block "main" . }}{{ end}}
  • By default Hugo also wants to generate "taxonomy" pages, which list groups of pages of the same type. To turn this off, add the following to your config.toml:
    disableKinds = ["taxonomy", "taxonomyTerm"]

That's it! Now you've got all the power of Hugo's template engine, without anything controlling your formatting.

All of this, along with an example of using Hugo's menu system, is in the hugo-skel git repo. I tested this out with Hugo 0.54.0.

Wednesday, October 18, 2017

Painless and secure SSH key management


SSH keys are great – they let you log into remote machines without typing your password every time. You should protect them with their own passphrases, though, so anyone who gets your key doesn’t automatically get access to all your shell accounts. This means you have to set up an ssh-agent to hold your keys. (Otherwise you’d have to type the key’s passphrase every time, and you haven’t achieved very much.)
It's not obvious how best to manage the ssh-agent: When to start a new one, when to load new keys, etc. (Some systems like OS X will start an ssh-agent for you on login, which makes things a big simpler.)
My goal here is to describe a platform-independent setup that is secure enough for my purposes, and convenient to use. I think it might work well for others too.


Source this in your .bashrc, name your keys like ~/.ssh/*-key, and type kc when you want to load them.


  1. I don’t have to type my password every time I log into a remote machine with ssh.
  2. Conversely, I don’t want my credentials saved in memory forever. I want to be re-prompted from time to time.
  3. My credentials should be encrypted on-disk, so someone who grabs my hard drive or gets access to a backup doesn’t have unfettered access to them. (Here are some good notes about keeping your keys secure on disk.)
  4. I don’t want to use an extra program to manage things. I want to depend on ssh-agent, my .bashrc, and nothing else.
  5. The solution should work most Linux distros and OS X without modification.
Goals 1-3 are fairly general, and I think most people should want those things. Goals 4 and 5 are particular to my workflow, and are what prompted my solution.


See this file: .bashrc.ssh-agent, which is a simple modification of existing scripts that wrap ssh-agent.
Usage works like this:
  • Source the script from your .bashrc: . ~/.bashrc.ssh-agent
  • Put your keys in ~/.ssh, ending with the *-key suffix. (This lets you easily exclude keys from auto-loading by changing the suffix. For instance, you could have ~/.ssh/home-key and ~/.ssh/work-key.)
  • Give all your keys the same passphrase.
  • To load keys, type kc. You should be prompted for your passphrase.
The first time you open a terminal after restarting, you should see “Initializing new SSH agent…”. You shouldn’t see anything in subsequent terminals.
If you add a key, you can run kc again to load it up.
If something happens to the running ssh-agent, you'll have to re-run kc in every running terminal window to load the new context.
It works like this:
  1. At login, it checks if an ssh-agent (launched by us) is running, and starts one if not.
  2. On demand, it load all keys into the running ssh-agent. (This might be because you just restarted your machine, or because your keys expired and you want to reload them. We’ll save them for 18 hours, because that will cause you to get re-prompted every day. They’ll usually expire overnight, so you’ll get prompted in the morning.)
This is is based heavily off of a gist by Michael Zedeler which did the agent management. I added the key-loading logic I wanted.


  • Some recent versions of OS X and some Linux distros will automatically start an ssh-agent for you. You may be able to just run ssh-add <your-keys>.
  • The gist this is based off of by Michael Zedeler is a great example to build off of.
  • Keychain provides very similar functionality bundled in a standalone application. This solution is heavily inspired by Keychain.


If you start multiple shells very quickly, you can trigger a race condition and start two ssh-agents. (This can happen, for instance, restoring a desktop session after a reboot on OS X.) Some locking would probably be useful. The workaround is to kill both ssh-agents and just start over.

Sunday, July 23, 2017

SELinux, ssh keys, and backing up your home directory

I'm fairly inexperienced with the ins and outs of SELinux, so this was novel to me:

I recently restored a /home partition from a backup, after which ssh key login stopped working.

I went through all the normal checks (permissions on my home directory, ~/.ssh, ~/.ssh/authorized_keys).

I started a debug sshd with "/usr/sbin/sshd -d -p 2222" -- and key login worked!.

The culprit turned out to be SELinux -- if I turned off enforcement with setenforce 0, I could log in via ssh keys again. Sure enough, there were messages in /var/log/audit/audit.log mentioning denied access to authorized_keys.

Running sudo restorecon -rv . from my restored home directory got things working again (and showed some helpful output about the changing contexts).

So, the real take-away (which is obvious for anyone who's more used to SELinux than me), is to if your ssh keys aren't being recognized, be sure to check /var/log/audit/audit.log as well.

Most of what I learned about this is from this blog post.

Sunday, October 26, 2014

Compiling Tor on CentOS 6.5

$ yum groupinstall "Development Tools"
$ yum install libevent-devel openssl-devel
$ ./configure
$ make
$ make install

That's it. I actually started writing this when I thought it would be more complicated.

It looks like the RPM for CentOS doesn't work with NTor (the new, faster) handshakes. There's some discussion on tor-relays@ about this here.

Tuesday, October 14, 2014

CrashPlan doesn't load on Ubuntu 14.04

These instructions from CrashPlan are spot on.

I installed webkit and added a line to run.conf as they described, and everything worked fine.

Saturday, June 7, 2014

Compiling mosh-chrome on 64-bit Ubuntu 14.04

mosh-chrome is great. For me, it addresses the last major feature that's keeping me from just using a light, cheap Chromebook as my day-to-day laptop as opposed to some beautiful/grotesque beast like a Thinkpad.

Anyway, these are my notes from compiling mosh-chrome on a relatively stock 64-bit (amd64) Ubuntu 14.04 machine:

  • Install the following packages: git subversion build-essential cmake autoconf libc6:i386 libstdc++6:i386 protobuf-compiler
    (Some of these are standard dev tools, some are 32-bit packages you won't get by default with a 64-bit dev toolchain, and there's one Google-specific tool thrown in there.)
  • pod2man gives an error when attempting to compile openssl. I wrote down a nasty workaround here last night. It's ugly but it worked for me.

That's it.

Compiling openssl 1.0.1g with Perl 5.18, the terrible way

[Edit: 2014-12-28: Newer versions of pod2man don't have this problem, apparently. The openssl issue has been closed, and this works for me now without the workaround below.]

It appears that openssl 1.0.1g doesn't compile with Perl 5.18 because the 5.18 of pod2man is stricter than previous versions, resulting in lots of errors like this:

cms.pod around line 457: Expected text after =item, not a number

There are patches ([1], [2], [3], plus the link above) that deal with this, but I couldn't find one that applied cleanly against openssl 1.0.1g.

In this particular case, I'm building openssl as a prerequisite for something else and won't be installing any manpages anywhere, so I actually don't care at all about building the documentation. So instead of actually fixing this, I just blanked out all the files:

$ echo "=pod" > ./../blank.pod
$ find . -name '*.pod' -exec 'cp' './../blank.pod' '{}' \;

This seems to be the simplest thing that works without modifying the build process at all or removing files, if one can't get any of the above patches to apply.

[Edited 2014-10-06 to simplify command for blanking pod files.]