darkhttpd with stunnel
A minimal web server with authentication for serving static content
Some weeks ago, I booked a virtual private server (VPS) for playing around with web servers. I don't want to run anything that needs a high performance, so I bought the smallest solution available: 1 virtual core, 512 MB RAM, 10 GB SSD (cost: 1 € per month). This comes with Plesk Obsidian, Apache and nginx preconfigured but I really wanted to start from scratch with a minimal (suckless) solution.
My aim was to serve a static version of my personal TiddlyWiki with some sort of authentication.
Minimal HTTP servers
I have considered these servers:
All of them consist of roughly 2000-3000 lines of C code (don't know about busybox) and offer similar features. Here is a quick comparison:
- 1: Output of
top -n 1 -p $(pgrep busybox)etc. (in KiB)
- 2: darkhttpd lists file sizes, quark does not.
- 3: There is a patch for digest authentication but it's broken/outdated.
- 4: Basic authentication for the whole website, not on directory level.
- 5: There is a patch for CGI but it's broken/outdated.
How to serve static content via HTTP (Port 80)
I have put my web content in
/srv/static. This folder belongs to
root:root. And I have created a user
www) for serving the content.
┌──────┐ │ port 80 (http) │web ├─────────────────────────── │server│ │ └──────┘ localhost │ internet
sudo busybox httpd -h /srv/static -p 80 -f
sudo quark -d /srv/static -p 80 -l
sudo darkhttpd /srv/static/ --port 80 --chroot --uid www --gid www
sudo althttpd --root /srv/static/ --port 80 --user www
(You need superuser rights for running a server on port 80 and also for using the chroot feature.)
I picked darkhttpd because I want to have directory listings and use basic authentication.
When you want to use basic authentication, you need HTTPS. Otherwise you'll send your password unencrypted (though base64-encoded) over the internet.
Most tiny servers don't offer HTTPS built-in. They are meant to be used with stunnel or something similar for getting TLS encryption (HTTPS):
quark does not natively support TLS. A more suckless approach than to implement TLS into it is to use a TLS reverse proxy (e.g. tlstunnel, hitch or stunnel). It accepts encrypted TLS connections and forwards them as unencrypted requests to a server. In this case, one can run such a reverse proxy to listen on a public IP address and forward the requests to a local port or UNIX-domain socket.
I picked stunnel because it seems to be the most mature solution and it's referenced in this busybox wiki page and in the althttpd README.
How to configure stunnel + darkhttpd
- Install stunnel:
# on Ubuntu sudo apt install stunnel4
# generic cd ~/Downloads wget https://www.stunnel.org/downloads/stunnel-5.60.tar.gz tar xvzf stunnel-5.60.tar.gz cd stunnel-5.60/ ./configure make sudo make install
Get a SSL certificate:
- For example via acme.sh (follow instructions in the README).
The following examples assume you have put your certificate files here:
Let's consider three scenarios:
1. http and https
In case you don't want to use basic authentication (or if you do, make sure not logging in while connected via port 80):
┌──────┐ port 80 (http) │web ├┬────────────────────────── │server││┌───────┐ └──────┘└┤stunnel╞═════════════════ └───────┘ port 443 (https)
- Start darkhttpd on port 80 (see above).
- Configure stunnel like that:
output = /usr/local/var/log/stunnel.log cert = /etc/acme.sh/static/cert.pem key = /etc/acme.sh/static/key.pem [https] client = no accept = 443 connect = 80
- Start stunnel:
2. https only, with basic authentication
┌──────┐ port 10080 (http), 127.0.0.1 │web ├┬──────── localhost │ internet │server││┌───────┐ │ └──────┘└┤stunnel╞════════════════════ └───────┘ port 443 (https)
- Start darkhttpd with basic authentication, only accessible from localhost:
PASSWORD='s3cr3t-p4ssw0rd' sudo darkhttpd /srv/static/ --port 10080 --chroot --uid www --gid www --addr 127.0.0.1 --auth john:"$PASSWORD"
(Could also be started without
--chroot since we use a port number > 1024.)
- Configure stunnel:
output = /usr/local/var/log/stunnel.log cert = /etc/acme.sh/static/cert.pem key = /etc/acme.sh/static/key.pem [https] client = no accept = 443 connect = 127.0.0.1:10080
3. https plus a redirection to https on the http port
Follow steps from
2. https only, with basic authentication.
Additionally start another darkhttpd instance which redirects HTTP requests on port 80:
sudo darkhttpd /srv/static/ --port 80 --chroot --uid www --gid www --forward-all https://yourdomain.info