Aral Balkan

Mastodon icon RSS feed icon

Setting up Hiawatha web server on Ubuntu 16.04

The unfortunately-named Hiawatha web server with its problematic logo1 is an independent, non-commercial, free and open web server built by Dutchman Hugo Leisink as a hobby project for the last 15 years or so. It’s primarily focused on security and the author appears to have a no-nonsense approach to its development.

Installing Hiawatha on Ubuntu

You can install Hiawatha on various platforms, including Linux, macOS, and Windows2.

To test it out, I first installed it from source on an Ubuntu 18.04 machine I commissioned from my regular host, CloudScale. While that worked, it was rather involved. If you are going to install it, I would highly recommed using the Hiawatha apt package. Sadly, there isn’t one for 18.04 yet so you’ll have to use 16.04.

Installing via apt

To begin, add the apt repository to your system, update your packages, and install the Hiawatha apt package:

sudo add-apt-repository ppa:octavhendra/hiawatha
sudo apt update
sudo apt upgrade
sudo apt install hiawatha

That will install the server but it will not run it. To do that, you need to use systemd:

sudo systemctl enable hiawatha
sudo systemctl start hiawatha

That will set up Hiawatha to be started automatically on restarts and start it up for the first time.

If you go to your domain/IP at this point, you should see the default Hiawatha welcome page.

Configuration

One of the goals of Hiawatha is to be easy to configure and to provide sane, safe defaults. To that end, once I learned the basics, I did find it much easier to understand than my regular web server, nginx.

The following is my setup3.

Highlights:

Directory details:

Configuration file:

#
# General settings.
#
ConnectionsTotal = 1000
ConnectionsPerIP = 25
SystemLogfile = /var/log/hiawatha/system.log
GarbageLogfile = /var/log/hiawatha/garbage.log

#
# Insecure servers (IPv4 and IPv6).
#
Binding {
  Port = 80
}

Binding {
  Port = 80
  Interface = 2a06:c01:1:1104::9349:73
}

#
# Default site.
#
# The default website is just a blank webpage. This is to thwart automated
# scanners as recommended in the default configuration.
Hostname = 127.0.0.1
WebsiteRoot = /var/www/default
StartFile = index.html
AccessLogfile = /var/log/hiawatha/access.log
ErrorLogfile = /var/log/hiawatha/error.log

#
# Virtual hosts.
#
VirtualHost {
  Hostname = equinodal.org, www.equinodal.org
  WebsiteRoot = /var/www/equinodal.org/public
  AccessLogfile = /var/www/equinodal.org/log/access.log
  ErrorLogfile = /var/www/equinodal.org/log/error.log
}

To activate the current configuration:

sudo systemctl restart hiawatha

You should now be able to access your site from your domain over HTTP (port 80).

TLS

Now that your site is up and running, it’s time to implement TLS. The days of HTTP are behind us, long live HTTPS.

Download PHP CLI:

Hiawatha has Let’s Encrypt support in the form of a script you can download but it is written in PHP and so you will need a bit of setup:

sudo apt install php7-cli

Dowload and install the Hiawatha Let’s Encrypt script:

Once you have the PHP CLI installed, download the Let’s Encrypt script (get the ACME v2 version) and uncompress it:

cd /usr/local/etc
wget https://www.hiawatha-webserver.org/files/letsencrypt-2.0.tar.gz
tar -zxf letsencrypt-2.0.tar.gz
rm letsencrypt-2.0.tar.gz
cd letsencrypt

Configure the Hiawatha Let’s Encrypt script:

In the letsencrypt folder, you’ll find a configuration file named letsencrypt.conf that you need to customise for your own needs.

The only changes I made were to add my email address for the ACCOUNT_EMAIL_ADDRESS field and to change the HIAWATHA_RESTART_COMMAND field to use systemd:

HIAWATHA_RESTART_COMMAND = sudo systemctl hiawatha restart

You also have to create the tls folder as specified by the HIAWATHA_CONFIG_DIR and HIAWATHA_CERT_DIR settings or the script will fail (this feels like a bug):

mkdir /etc/hiawatha/tls

Request the TLS certificate from the staging server:

Once you’ve configured the script, you need to actually request the certificate. Initially, you will be using the Let’s Encrypt staging server to make sure that everything works and then you will switch to using the production server.

With the current script, requesting a certificate is a two-step process (this should really be simplified to a single step) that involves registering and requesting.

From the folder that contains the letsencrypt script:

./letsencrypt register
./letsencrypt request equinodal.org

Request the certificate from the production server:

Unless you changed the configuration file, the first attempt will use the Let’s Encrypt staging server. Once that runs correctly, you can change the configuration file to use the production server and actually get your certificates:

# Let's Encrypt API settings
LE_CA_HOSTNAME = acme-v02.api.letsencrypt.org		# Production
LE_ISSUERS = Let's Encrypt Authority X3 \
             Let's Encrypt Authority X4

Update your Hiawatha configuration to use TLS:

Now it’s time to update your configuration to implement TLS. Here’s what my configuration looks like with TLS enabled and required.

Highlights:

Directories:

#
# General settings.
#
ConnectionsTotal = 1000
ConnectionsPerIP = 25
SystemLogfile = /var/log/hiawatha/system.log
GarbageLogfile = /var/log/hiawatha/garbage.log

#
# Insecure servers (IPv4 and IPv6).
#
Binding {
  Port = 80
}

Binding {
  Port = 80
  Interface = 2a06:c01:1:1104::9349:73
}

#
# Secure servers (IPv4 and IPv6).
#
Binding {
  Port = 443
  TLScertFile = /etc/hiawatha/tls/equinodal.org.pem
}

Binding {
  Port = 443
  Interface = 2a06:c01:1:1104::9349:73
  TLScertFile = /etc/hiawatha/tls/equinodal.org.pem
}

#
# Default site.
#
# The default website is just a blank webpage. This is to thwart automated
# scanners as recommended in the default configuration.
Hostname = 127.0.0.1
WebsiteRoot = /var/www/default
StartFile = index.html
AccessLogfile = /var/log/hiawatha/access.log
ErrorLogfile = /var/log/hiawatha/error.log

#
# Virtual hosts.
#
VirtualHost {
  Hostname = equinodal.org, www.equinodal.org
  WebsiteRoot = /var/www/equinodal.org/public
  RequireTLS = yes
  AccessLogfile = /var/www/equinodal.org/log/access.log
  ErrorLogfile = /var/www/equinodal.org/log/error.log
}

The only changes are the addition of secure IPv4 and IPv6 binding sections for TLS that reference the Let’s Encrypt certificate and the addition of the RequireTLS = yes setting to the virtual host.

Restart your server and you should be up and running over HTTPS:

sudo systemctl restart hiawatha

Node.js with a reverse proxy

The above is all you need if you want to host a static site with Hiawatha but what if you want to host your Node.js site? For that, we need to configure a reverse proxy and it is stupidly simple to do.

First, install Node.js on your server if you haven’t already:

curl -sL https://deb.nodesource.com/setup_8.x | sudo -E bash -
sudo apt-get install -y nodejs

Then, create a project to hold a very simple test server:

mkdir ~/node-server && cd ~/node-server
npm init -y
nano index.js

In index.js:

const http = require('http')

const server = http.createServer((request, response) => {
  response.statusCode = 200
  response.end('Hello from Node.js!\n')
})

server.listen(3000)

Run the Node server4:

node index.js

In another ssh session (or terminal window if local), test that the Node server works:

curl http://localhost:3000

You should see something like:

ubuntu@equinodal:~/spike$ curl http://localhost:3000
Hello from Node.js!

So, now, all we need to do is to update our Hiawatha configuration to use a reverse proxy that forwards all requests to our Node server. You do this in the virtual host section:

VirtualHost {
  Hostname = equinodal.org, www.equinodal.org
  ReverseProxy .* http://localhost:3000/
  WebsiteRoot = /var/www/equinodal.org/public
  RequireTLS = yes
  AccessLogfile = /var/www/equinodal.org/log/access.log
  ErrorLogfile = /var/www/equinodal.org/log/error.log
}

The only change is the addition of the ReverseProxy setting. (For some reason, the virtual host still needs the WebsiteRoot setting even though it is overriden by the reverse proxy setting.)

Restart the Hiawatha server and make sure that your Node server is running and you should be able to access it over TLS via your domain.

Conclusion

Hiawatha feels like a great alternative to nginx and other heavier web servers for personal projects and I look forward to using it in some of mine. I do hope that Hugo will do something to update the problematic name and iconography for 2018 so that I don’t have any reservations when I recommend it to others. If you do give it a shot, let me know how you get on via Mastodon.


  1. Cultural appropriation is never fun. Hiawatha is #NotYourMascot. I do hope that Hugo will reconsider the naming and iconography of an otherwise excellent project. ↩︎

  2. Note the following caveat for Windows: “I’ve never fully tested the impact that Cygwin or Windows has on Hiawatha, so don’t use the Windows version for production websites unless you’ve tested it yourself.” ↩︎

  3. Don’t try and access the site itself, I’m just using that domain to test with so it will most likely be offline. ↩︎

  4. Normally, you would run the server with a script like forever. ↩︎