Tools Hiawatha Web Server Lead image: Lead Image © Tatiana Popov,
Lead Image © Tatiana Popov,

Security first with the Hiawatha web server

Small but Safe

The small but secure Hiawatha web server provides an appealing alternative to the complex Apache and other alternatives. By Hans-Cees Speel

Security on the Internet is vital. The Hiawatha web server [1], created by Hugo Lensink, is a small (and free) web server that subscribes to the principle "security by default." This article shows how to install and use Hiawatha.

You'll get the most benefit from Hiawatha if you run web applications, such as a CMS or any PHP website that occasionally gets hit by vulnerabilities (and they all do, of course). Hiawatha adds an extra layer of security, delivering ready-to-use rewrite rules for different CMS options.

In comparison with Apache and Nginx, the Hiawatha configuration file is much more concise and easier to edit. Hiawatha makes it very easy to switch on the security features for a CMS, for example; whereas setting up security for a CMS in Nginx or Apache will require the additional work of configuring modules and rules and testing them. See the box titled "Pros and Cons" for a summary of Hiawatha benefits and costs.

A Virtual Machine with Hiawatha

TurnKey Linux [2] is an open source project that provides 100+ free virtual machine images with support for many popular open-source applications, such as Joomla, Nginx, CRM, and more. You can use these virtual images in VMware, AWS Docker, and other virtualization environments. One easy way to set up a Hiawatha virtual machine is to start up the TurnKey Linux Nginx VM [3], then remove Nginx and add Hiawatha.

Start by downloading the TurnKey Linux Nginx VM, a small Linux Debian system, stripped for use as a VM, that comes with MySQL, PHP, and Nginx installed. I use this image because I like to install PHP/MySQL websites such as Joomla.

Deploy the image and give it two network adapters, one for administration and one for the web server. I gave the system 1GB memory, but it has not yet used more than 200MB.

Then, boot the image. You have several choices:

You'll want to install the security updates right away (get some coffee; it might take a while), apply static IP addresses, and shut down the system. (Because you're setting up a website, you probably want a static IP address, right?)

Now export the VM from VMware to disk as a basis to reuse later (OVA image). Once you get the VM up and running, the next step is to remove Nginx and install Hiawatha. Log in using SSH with the root account via the internal network adapter and the password you just inserted. If you look at the process list, you can see Nginx and fastcgi:

ps waux

See the output in Listing 1. The process overview now shows Nginx and php-fastcgi are running, as expected.

Listing 1: Process List

root       589  0.0  0.3 142492  3092 ?   Ss   20:35   0:00 nginx: master process
   /usr/sbin/nginx -g daemon on; master_process on;
www-data   591  0.0  0.3 142832  3716 ?   S    20:35   0:00 nginx: worker process
www-data   592  0.0  0.3 142832  3716 ?   S    20:35   0:00 nginx: worker process
www-data   593  0.0  0.3 142832  3716 ?   S    20:35   0:00 nginx: worker process
www-data   594  0.0  0.3 142832  3716 ?   S    20:35   0:00 nginx: worker process
www-data  1099  0.0  0.5 357844  5572 ?   S    20:35   0:00 /usr/bin/php-cgi -q -b /var/run/nginx/php-fastcgi.sock
www-data  1100  0.0  0.5 357844  5572 ?   S    20:35   0:00 /usr/bin/php-cgi -q -b /var/run/nginx/php-fastcgi.sock

See the documentation for your Linux distro to see if Hiawatha is available directly from the project repositories. (At this writing, Hiawatha isn't available in Ubuntu.)

If you can't install Hiawatha from your distro's package repository, you'll need to add the install resource

apt-key adv --recv-keys --keyserver DC242980
echo "deb squeeze main" >> \

Then, install Hiawatha as follows:

apt-get update
apt-get install hiawatha

Hiawatha is now installed, but it can't bind to port 80 because Nginx is still using port 80. So, do the following:

apt-get remove nginx

Then log in via SSH again and run:

/etc/init.d/hiawatha start

The output should say "Starting web server: Hiawatha." Check the process list to see if Hiawatha is working:

ps waux | egrep iawa
shows hiawatha running
www-data  4766  0.1  0.3 118232  4016 ?        Ssl  20:13 0:00 /usr/sbin/hiawatha

You can use netstat to check the bindings:

netstat -tulpn

See the output in Listing 2.

Listing 2: netstat Output

Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name
tcp        0      0    *               LISTEN      4766/hiawatha
tcp        0      0*               LISTEN      944/perl
tcp        0      0    *               LISTEN      676/sshd
tcp        0      0  *               LISTEN      916/master
tcp        0      0   *               LISTEN      4766/hiawatha
tcp        0      0*               LISTEN      766/shellinaboxd
tcp        0      0 *               LISTEN      764/stunnel4
tcp        0      0 *               LISTEN      764/stunnel4
tcp6       0      0 :::22                   :::*                    LISTEN      676/sshd

Another way to check whether Hiawatha is working is to open a web browser and connect to it by typing the static internal IP address in the browser window.


If you have any problems with installing or starting Hiawatha, you can check for errors in the config file with:

service hiawatha check

Or the following command:

/etc/init.d/hiawatha restart

will also report errors, for instance, when loading certificates fails.

Check the Hiawatha logfile with:

tail -f /var/log/hiawatha/access.log

Configure Hiawatha

Now that you have a VM with the Hiawatha web server running on it, the next step is to install a website. The Hiawatha configuration file is /etc/hiawatha/hiawatha.conf. To open the file in the Vi text editor:

vi /etc/hiawatha/hiawatha.conf

Feel free to use another editor, such as nano, if you prefer.

The Hiawatha config file has the following sections:

It is better not to use the default website for serving your own websites but to serve them as virtual hosts. As the config file states: "automated web scanners won't find your possible vulnerable website" (by searching and scanning IP-addresses). Hiawatha installs a default website for you. In the config file, you can see where it lives:

WebsiteRoot = /var/www/hiawatha
StartFile = index.html
AccessLogfile = /var/log/hiawatha/access.log
ErrorLogfile = /var/log/hiawatha/error.log

I will leave the default website alone and instead define a new website as a virtual host. To define a new site, I need to configure Hiawatha to serve as a virtual host website and install HTML pages in the right directory.

Configure a Virtual Host

The following settings define a virtual host in the configuration file:

VirtualHost {
  Hostname =, \
  WebsiteRoot = /var/www/thisisagreatwebsite
  StartFile = index.html
  ErrorHandler = 404:/index.html

These settings tells Hiawatha to answer requests for and also for, where whatever can be any text at all (if these names exist in DNS).

Hiawatha will look for the HTML for this website in /var/www/thisisagreatwebsite/, and the start file is index.html. When you ask for a page that does not exist, webservers give an 404 error; in this case, the missing page will be the start page: the ErrorHandler setting takes care of that in this example configuration. This trick makes sure broken links will end up at the start page. Next, create a directory:

cd /var/www
mkdir thisisagreatwebsite

and copy the default website page of Hiawatha, inserting the Greatwebsite keyword:

cat /var/www/hiawatha/index.html | \
  sed 's/Installation successful/Greatwebsite/' >\

Adjust the file rights so the web server can read those pages

find ./thisisagreatwebsite -exec chown www-data:www-data {} +
find ./thisisagreatwebsite -type d -exec chmod 1774 {} +

You need to re-run the two find commands if you add new files to the website files while being root: since you log in as root via SSH, you need to change file rights so the website can read them.

ls -all  /var/www/thisisagreatwebsite

should now show the following:

drwxrwxr-T  2 www-data www-data 4096 Dec 30 17:34 .
drwxr-xr-x 26 root     root     4096 Dec 30 17:34 ..
-rw-r--r--  1 www-data www-data 1768 Dec 30 17:34 index.html

Restart the web server to test:

service hiawatha check
/etc/init.d/hiawatha restart

Configure DNS or Your hosts File

Now you can see if the website actually works. You have to make sure resolves in DNS to the IP address of your web server.

For testing purposes, you can adjust your local hosts configuration. In Windows, open file C:\Windows\System32\Drivers\Etc\hosts with administrator rights. Add a line like the following:

In Linux, find the etc/hosts file and add the new address. Next, you can restart your browser and point it to You should see your new website in your browser.


Things might not go so smoothly for your new website. The following command:

service hiawatha check

will report errors in your config file.

/etc/init.d/hiawatha restart

can also report errors; for instance, when loading certificates fails.

Have a look at the Hiawatha access logfile with:

tail -f /var/log/hiawatha/access.log

To view the error log, enter:

tail -f /var/log/hiawatha/error.log

Start your web browser and surf to

If you can ping your website by IP address but not by its domain name:


you know the problem is related to DNS and not Hiawatha itself.

Switching On the Anti-Hacker Configuration

The great virtual host website is working. Now I have to protect it from attack. Because I want to set up my servers according to the "defense in depth" standard, I choose to switch on almost all anti-hack preventions settings. My default stance is that Joomla will surely have vulnerabilities I do not know about (but others do). You might find this extreme security focus too much of a good thing, because defense in depth sometimes worsens performance, and features like SQL prevention can potentially block legitimate traffic.

You can choose not to use some or all of the prevention clauses in the following configuration: think about it and choose. The same argument is true for which TLS version to allow: Allowing TLS 1.0 could make your visitors vulnerable to sniffing attacks. My recommendation is to use the settings as reflected below, but please do make your own choices.

The configuration in Listing 3 includes settings that will help you:

Listing 3: Config File Settings

ServerId = www-data
ConnectionsTotal = 1000
ConnectionsPerIP = 25
SystemLogfile = /var/log/hiawatha/system.log
GarbageLogfile = /var/log/hiawatha/garbage.log
ExploitLogfile = /var/log/exploit_attempts.log   # xss sqli etc
DHsize = 4096                   # default 2048, for tls
RandomHeader = 250              # anti decryption on https listening
set local_net =  #define your local networks you do not want to block
# Deny service to clients who misbehave.
#anti hacker trying evil things
PreventCSRF = yes  # ignoring all cookies sent by a browser when following an external link
PreventSQLi = yes  #no 100% guarantee, resource intensive!
PreventXSS = yes   # replacing a less-then, greater-then, quote or double-quote in the URL with an underscore
BanlistMask = deny local_net        ## this network will not be banned
RequestLimitMask = deny local_net   ## this network can upload all they want
BanOnDeniedBody = 120
BanOnGarbage = 600              #seconds
BanOnInvalidURL = 0             #seconds #risky if > 0
BanOnMaxReqSize = 600           #seconds
BanOnSQLi = 600                 #seconds
BanOnWrongPassword = 3:120      #seconds
MinTLSversion = 1.1             #drop attempts to fool webserver to be insecure. You might want 1.0
#anti dos
BanOnFlooding = 10/1:15
KickOnBan = yes                 # close all connections for an IP that is banned
#MaxUrlLength = 500             #default 1000. Longer -> 404
ReconnectDelay = 3              #how long connection wil stay open after no traffic
RebanDuringBan = yes            # keep them banned if they retry
#anti ddos: usable when under attack
#BanOnMaxPerIP = 60                     #seconds
#ChallengeClient = 200, httpheader, 60  #after 200 connects send a coockie
BanOnTimeout = 10                       #ban if no request comes after X seconds, only syn etc
#ListenBacklog = 128                    #default 16

Alas, distributed DOS attacks (DDOS attacks) are sometimes more than you can beat with just one clever Hiawatha server. The configuration in Listing 3 might help but is not sufficient protection. See the Hiawatha documentation for more on other steps you can take to defend your system from attacks.

Of course, you should monitor your logfiles to ensure you don't block things you do not want to block:

tail -f /var/log/hiawatha/exploit_attempts.log

Also, it is a good idea to check your stats for clues on how you can improve CPU or memory usage. The top command provides a wealth of knowledge on the state of your system.

For low-traffic websites, you should expect no problems. If you have a lot of traffic, you might need to pay attention to the effect these security settings have on performance. If the load is high, the settings in Listing  4 might help. I would always recommend the caching settings. After altering your config file, restart the web server to check for errors.

Listing 4: Performance Settings

CacheRProxyExtensions = css, gif, html, jpg, js, png, txt
CacheSize = 25 #mb
CacheMaxFilesize = 128  #kb
##load tinkering
#ListenBacklog = 128    #default 16
#MaxServerLoad = 0.7    #drop on high load (eeks)
#SocketSendTimeout = 10 #default is 3 Sets the SO_SNDTIMEO value for all client connection sockets
#ThreadPoolSize = 50    #default 25
#ThreadKillRate = 10    #default 1

Installing Joomla

Joomla is a popular open source CMS you can run on top of Hiawatha. (Before you install Joomla, or make any other major change to your system, consider taking a snapshot of the virtual machine so you can easily revert back if you have problems.)

To add Joomla to the website, I need to make the following changes to the Hiawatha config file:

Open the Hiawatha config file and add the settings in Listing 5.

Listing 5: Getting Ready for Joomla

#yes fastcgi, bit adjusted (php-fastcgi.sock)
FastCGIserver {
        FastCGIid = PHP5
        ConnectTo = /var/lib/hiawatha/php-fastcgi.sock
        Extension = php
#url toolkit for joomla
UrlToolkit {
    ToolkitID = joomla
    Match base64_encode[^(]*\([^)]*\) DenyAccess
    Match (<|%3C)([^s]*s)+cript.*(>|%3E) DenyAccess
    Match GLOBALS(=|\[|\%[0-9A-Z]{0,2}) DenyAccess
    Match _REQUEST(=|\[|\%[0-9A-Z]{0,2}) DenyAccess
    Match ^/index\.php Return
    RequestURI exists Return
    Match .* Rewrite /index.php
VirtualHost {
        Hostname =, *
        WebsiteRoot = /var/www/thisagreatwebsite
        StartFile = index.php   #php, not html of course
        ErrorHandler = 404:/index.html
        TimeForCGI = 5
        UseFastCGI = PHP5
        UseToolkit = joomla

Next, you need to change one line in the fastcgi config file (/etc/default/php-fastcgi) so it uses a socket in the Hiawatha directories. Change the following line:


to say:


Download the latest stable version of Joomla from the project website  [4]. At the time of writing, the current version was 3.4.5. Copy the link download location and download and unzip it:

cd /var/www/thisisagreatwebsite

Now make a configuration.php file and adjust file rights properly, so the web server can make and change files as needed:

touch  configuration.php
find -type d -exec chmod 1774 {} +
find -exec chown www-data:www-data {} +

The preceding commands ensure that the Joomla installation can add files and folders by using the sticky bit on directories [5].

Carry on with the Joomla install through your web browser. Go to, and you should be redirected to the standard Joomla install script at Fill in all the details, like the password, the name of the website, and so on. Please refer to the Joomla documentation [6] for detailed information.

After installing Joomla, you need to change some details in the /etc/php5/cgi/php.ini file so it will work right with Hiawatha. Find the following settings and change them to the following values:

cgi.fix_pathinfo = 0
# Enable GZip content encoding
zlib.output_compression = On
zlib.output_compression_level = 6

Reboot and see if the website you just installed shows up at

The Joomla logging is usually in /var/www/thisisagreatwebsite/logs/. Typical troubleshooting commands are:

tail -f /var/www/thisisagreatwebsite/logs/acces.log
tail -f /var/www/thisisagreatwebsite/logs/error.log

My Joomla website did not work properly under TLS because the baseref was wrong (HTTP instead of HTTPS). I found a fix online, which was to change the file joomla/libraries/joomla/document/html/renderer/head.php.

Find the next bit of code at around line  65 and comment it out, as follows:

// Generate base tag
/** $base = $document->getBase();
if (!empty($base))
$buffer .= $tab . '<base href="' . $document->getBase() . '" />' . $lnEnd;
} **/

Adding Firewall Rules

If your Hiawatha web server is connected to the Internet, it makes sense to make sure an outside user can only connect through ports 80 and 443. On the inside interface, you can leave other ports open, such as ports for SSH (22), webmin, and so forth.

On the Debian-based TurnKey Linux, you can add iptables rules that load after every reboot. Before you begin, make a snapshot or backup in VMware or your hypervisor, in case you accidentally lock yourself out.

Create (or open) the file network/if-pre-up.d/iptablesload in a text editor and add the iptables scripting rules shown in Listing 6. Then, make sure the file is executable:

Listing 6: Firewall Rules

01 #!/bin/bash
02 #iptables script reverse-proxy version 1.0 dec 2015 By Hans-Cees Speel.
03 EXTDEV=eth1  #external device
04 LANDEV=eth0
06 echo -n "flushing all chains"
07     /sbin/iptables -F -t filter
08     /sbin/iptables -F -t nat
09     /sbin/iptables -F -t mangle
10     /sbin/iptables -X -t filter
11     /sbin/iptables -X -t nat
12     /sbin/iptables -X -t mangle
13     /sbin/iptables --flush  FORWARD
14     /sbin/iptables --flush  INPUT
15     /sbin/iptables --flush  OUTPUT
17 #exit
19 #policies for the chains
20     /sbin/iptables --policy FORWARD DROP
21     /sbin/iptables --policy INPUT DROP
22     /sbin/iptables --policy OUTPUT DROP
24 #new chains. Statefull and scrub icmp
25     /sbin/iptables --new-chain StatefulInputFilter
26     /sbin/iptables --new-chain icmpInOut
28 ###INPUT chain
29 #icmp scrubbed via icmpInOut, local loop is accepted #multicast is dropped, rest to stateful chain
30     /sbin/iptables --append INPUT --protocol icmp --jump icmpInOut
31     /sbin/iptables --append INPUT -i lo -j ACCEPT
32     /sbin/iptables --append INPUT -s    -j DROP
33     /sbin/iptables --append INPUT -d    -j DROP
34     /sbin/iptables --append INPUT -j StatefulInputFilter
36 #accept outgoing traffic, drop forward traffic
37 /sbin/iptables --append OUTPUT --jump ACCEPT
38 /sbin/iptables --append FORWARD -j DROP
40 #StatefulInputFilter chain for incoming syns # Allow established connections, accept Lan, accept 80,443 internet
41 /sbin/iptables --append StatefulInputFilter  -m state --state ESTABLISHED,RELATED -j ACCEPT
42 /sbin/iptables --append StatefulInputFilter -m state --state NEW ! -i  $EXTDEV -j ACCEPT
43 /sbin/iptables --append StatefulInputFilter -p tcp -m multiport --dport 80,443 -m state --state NEW -j ACCEPT
44 /sbin/iptables --append StatefulInputFilter --jump DROP
46 #chain icmpInOut This chain is used for icmp and lets only certain kinds in.
47 /sbin/iptables --append icmpInOut --proto icmp --icmp-type redirect -o $LANDEV --jump ACCEPT
48 /sbin/iptables --append icmpInOut --proto icmp --icmp-type echo-request --jump ACCEPT
49 /sbin/iptables --append icmpInOut --proto icmp --icmp-type echo-reply --jump ACCEPT
50 /sbin/iptables --append icmpInOut --proto icmp --icmp-type destination-unreachable --jump ACCEPT
51 /sbin/iptables --append icmpInOut --proto icmp --icmp-type source-quench --jump ACCEPT
52 /sbin/iptables --append icmpInOut --proto icmp --icmp-type time-exceeded --jump ACCEPT
53 /sbin/iptables --append icmpInOut --proto icmp --icmp-type parameter-problem --jump ACCEPT
54 /sbin/iptables --append icmpInOut --jump DROP
56 #enable tcp synflood protection by using coockies ddos defense
57 echo 1 > /proc/sys/net/ipv4/tcp_syncookies
58 /usr/bin/logger Iptables script hcs implemented
59 ############# you might also consider installing fail2ban
chmod +x network/if-pre-up.d/ \
  iptablesload # make it executable reboot

After the reboot, check if the iptables rules have loaded with iptables -L.

The iptable rules in Listing 6 assume your outside interface is eth1. You can check if this is so with the command ifconfig. If your outside interface is eth0, adjust the firewall rules accordingly. (If you have only one interface, I suggest you add another interface for security reasons.)

Adding TLS Encryption

Adding TLS encryption (HTTPS) to your website is important. TLS ensures no one can listen in on visitors to your website or steal credit cards. Google also ranks your website higher if it serves HTTPS.

Adding encryption to your website is fairly easy, but getting a working certificate to do so is more difficult. Until recently, the only two viable options for obtaining a certificate to use with TLS/SSL were:

Another option to consider is a new open source project called Let's Encrypt, which is attempting to make certificates free. Let's Encrypt is still in beta, but it works well on my Linux system. If you feel like exploring Let's Encrypt, see the instructions at the project website [7].

For purposes of this article, I'll assume you are setting up a small, private site and are satisfied with a self-signed certificate. Listing 7 shows the steps for setting up a self-signed certificate for Hiawatha. For simplicity, I'll use this self-signed certificate for both the default website and the virtual host website.

Listing 7: A Self-Signed Certificate

cd /root/certs
openssl genrsa -out default-serverkey.pem 2048
openssl req -new -x509 -days 3650 -key default-serverkey.pem -out server.crt
echo "" >> default-serverkey.pem
cat server.crt >> default-serverkey.pem
echo "" >> default-serverkey.pem
rm -f server.crt
mkdir /etc/hiawatha/certs
cp default-serverkey.pem /etc/hiawatha/certs
chown www-data:www-data /etc/hiawatha/certs/default-serverkey.pem
chmod 400 /etc/hiawatha/certs/default-serverkey.pem

If you decide to acquire a trusted certificate, you will probably want to give each virtual host a unique certificate of its own. In step three, you need to fill in information about your website. Once you have your certificate, you'll need to change the configuration with a port 443 binding and add TLS to the default website configuration (Listing 8).

Listing 8: Binding Port 443

Binding {
        Port = 443
        TLScertFile = /etc/hiawatha/certs/default-serverkey.pem
#       #Interface =
        TimeForRequest = 2,45           #default 5,30

As you can see in Listing 8, the binding configuration has its own TLS certificate. This certificate will be used for the default website you get if you connect to the web server without a valid host HTTP header. The Interface line lets you configure the server to listen only on specific IP addresses. (Note that the Interface option is disabled in Listing 8.)

You also need to change the virtual host configuration to include our new certificate (Listing 9). The configuration for the virtual host is not much different from a host without TLS: just three lines more. Requiring TLS makes sure the web server will redirect unencrypted connections on port 80 to encrypted ones on port 443. This is a good thing, because you want to protect visitors from eavesdropping. The second line states where to find the certificate. Check the latest changes with:

Listing 9: New Virtual Host Configuration

VirtualHost {
  Hostname =, *
  TLScertFile = /etc/hiawatha/certs/ default-serverkey.pem
  RequireTLS = yes #redirect port 80 to 443
  WebsiteRoot = /var/www/thisisagreatwebsite
  StartFile = index.html
  ErrorHandler = 404:/index.html
service hiawatha check

If all is well, you can restart Hiawatha:

/etc/init.d/hiawatha restart

Point your browser to https://<ip-address>/ where <ip-address> is the IP address of your web server host. You should now see a browser warning about the untrusted certificate.


Hiawatha is secure and easy-to-use web server alternative that supports many popular CMS options and server extensions. The Hiawatha web server might not have all the bells and whistles you get with Apache, but it is an attractive alternative for small sites where security is important.