As mentioned on the front page this site is available over TOR as well as the clear net. Thing is, serving one static site over multiple URLs causes some issues due to the static nature of the site.

Static site with two URLs

A lot of URLs are hard coded into the HTML files of the site when it is generated. This means that even though you go through the onion link, as soon as you click on any navigation link on the site you are transported back to the clear net version.

To solve this I’ve duplicated the site. One copy is generated using the clear net address, the other the onion address. Having the site duplicated on the server does mean it uses twice the storage - a whole whopping 1.8MB x 2. Meaning one copy of my entire site is a little less than the average single-page size in 2022 (Web Almanac - page weight 2022). It’s a compromise I am happy to make.

For convenience the build and deploy process has been turned into a simple bash script.

#!/usr/bin/env bash

set -euo pipefail # stop on empty var, error or pipe fail.

_onionURL='http://xxxxx' # onion url
_remoteServerLogin="" # <user>@<server> for SSH login to remote server

# generate regular site 
hugo 
# generate onion site
hugo --baseURL "$_onionURL" --destination ./TOR_public

# upload regular site
rsync -avz -e "ssh -i \"$HOME/.ssh/kjell.nicolaysen.nu-deployment-key\"" public/ "$_remoteServerLogin":/var/www/html/kjell.nicolaysen.nu/clearNet/

# upload onion site
rsync -avz -e "ssh -i \"$HOME/.ssh/kjell.nicolaysen.nu-deployment-key\"" TOR_public/ "$_remoteServerLogin":/var/www/html/kjell.nicolaysen.nu/onion/

Side note: The rsync command used for the upload has some additional security to it, making the SSH key unusable for anything other than updating the site. May write up a post about this in future. The site generation script, as it is now, will not catch any hardcoded links to the clear net site (eg. referencing back to a previous post) which is something I will have to look at fixing later. It is also set to use the default SSH port.

Configure web server

All that remains is configuring caddy (the web server) to serve up the correct directory. Along with a notification (if you visit the clear net site with the TOR browser) that the site is available as an onion address as well.

kjell.nicolaysen.nu:443 { 
        header Onion-Location http://kcnicqqoyqeiwtqtpznke52ryzqjelonbpg3sp6f3tc74lyzi5tb6sad.onion{path}
        root * /var/www/html/kjell.nicolaysen.nu/clearNet
        file_server
        import /etc/caddy/caddy_security.conf
}

# TOR hidden site
http://kcnicqqoyqeiwtqtpznke52ryzqjelonbpg3sp6f3tc74lyzi5tb6sad.onion {
        root * /var/www/html/kjell.nicolaysen.nu/onion
        file_server
	import /etc/caddy/caddy_onion_security.conf
}

Vanity onion address

The eagle eyed reader may have spotted this site uses a vanity onion address – meaning the kcnic portion was selected rather than randomly created.

Onion address are not just an address, but also the ed25519 public key [Torproject] for your site. It is randomly generated, but with a bit of time and computational power it is possible to genreate vanity addresses using brute force [mkp224o]. The longer the vanity portion of the address, the longer time is required to match it. Meaning the more computing power you have to throw at it the faster it works (or longer address you can customize).

For reference, it tok my Raspberry Pi 4 roughly thirty hours to generate that onion address (lucky? unlucky? Dunno, but that is how log it tok).

And voila a functional static site served over vanity onion and clear net.