A practical guide to setting up a simple web server using bozohttpd on NetBSD, including configuration via inetd, HTTPS with acme-client, and optional multi-site setup.
# bozohttpd rocks - Setup a simple web server with bozohttpd on NetBSD
Source: [https://bozo.httpd.rocks/](https://bozo.httpd.rocks/)
---
Setup a simple web server with`bozohttpd`on[NetBSD](https://netbsd.org/)\.
If you’d prefer to use[OpenBSD](https://openbsd.org/), check out[httpd\.rocks](https://httpd.rocks/)\.
If you’d prefer to use something like Caddy instead, check out[caddy\.ninja](https://caddy.ninja/)\.
---
- [Before You Begin…](https://bozo.httpd.rocks/#before-you-begin)
- [Prep Your Domain\(s\)](https://bozo.httpd.rocks/#prep-your-domains)
- [Website Files](https://bozo.httpd.rocks/#website-files)
- [Configuring inetd\.conf](https://bozo.httpd.rocks/#configuring-inetdconf)
- [Start bozohttpd](https://bozo.httpd.rocks/#start-bozohttpd)
- [Setup HTTPS](https://bozo.httpd.rocks/#setup-https)- [Configuring acme\-client\.conf](https://bozo.httpd.rocks/#configuring-acme-clientconf) - [Tweaking Permissions](https://bozo.httpd.rocks/#tweaking-permissions) - [Running a Daily cronjob](https://bozo.httpd.rocks/#running-a-daily-cronjob)
- [Updating`inetd\.conf`to Support HTTPS](https://bozo.httpd.rocks/#updating-inetdconf-to-support-https)
- [What About Multiple Websites?](https://bozo.httpd.rocks/#what-about-multiple-websites)- [Updating acme\-client\.conf](https://bozo.httpd.rocks/#updating-acme-clientconf) - [Symlink to the Rescue\!](https://bozo.httpd.rocks/#symlink-to-the-rescue) - [Updating inetd\.conf](https://bozo.httpd.rocks/#updating-inetdconf) - [Editing rc\.conf](https://bozo.httpd.rocks/#editing-rcconf)
## Before You Begin…
This guide assumes you have already setup NetBSD on your desired server of choice\. If you need help setting up NetBSD on a VPS, check out the official guide[here](https://www.netbsd.org/docs/guide/en/chap-exinst.html)\.
Most commands will need to run via`doas`, since you should be logged in as a created user and never`root`directly\. You might need to install`doas`from packages FYI\.
All the examples in this guide use`bozo\.httpd\.rocks`for the domains \(how meta…\)\. Please remember to change this to your desired URL\.
## Prep Your Domain\(s\)
Make sure your DNS records are setup and working as intended with your desired domain\. You can check their status with:
## Website Files
Place your website files in the proper directory\. For this guide we will be placing all files into`/var/www/bozo\.httpd\.rocks`\.
## Configuring inetd\.conf
`inetd`executes a fresh httpd per connection, so it reads the cert files at the start of every request\. \(Not the best for performance, but for our simple requirements it’s fine\!\)
Place the following in your`/etc/inetd\.conf`file:
```
http stream tcp nowait:600 _httpd /usr/libexec/httpd httpd /var/www/bozo.httpd.rocks
```
## Start bozohttpd
Start`bozohttpd`on port 80 only\. We don’t need to worry about TLS right now\.
We start the web server by reloading`inetd`, since that is where we call it:
## Setup HTTPS
First, we need to install`acme\-client`from packages:
```
pkgin install acme-client
```
Next we create all the directories / sub\-directories that will be required in the following steps:
```
mkdir -p /etc/acme
mkdir -p /var/www/bozo.httpd.rocks/.well-known/acme-challenge
mkdir -p /etc/openssl/private
chmod 700 /etc/openssl/private
```
### Configuring acme\-client\.conf
Write to`/usr/pkg/etc/acme\-client\.conf`\. Make sure to change the domain and directory path to match your own\!
```
authority letsencrypt {
api url "https://acme-v02.api.letsencrypt.org/directory"
account key "/etc/acme/letsencrypt-privkey.pem"
}
domain bozo.httpd.rocks {
domain key "/etc/openssl/private/bozo.httpd.rocks.key"
domain full chain certificate "/etc/openssl/certs/bozo.httpd.rocks.fullchain.pem"
sign with letsencrypt
challengedir "/var/www/bozo.httpd.rocks/.well-known/acme-challenge"
}
```
Now we can get the certs:
```
acme-client -vAD bozo.httpd.rocks
```
If everything worked correctly, those new`key`and`pem`files should exist\. Feel free to double check:
```
ls -l /etc/openssl/private/bozo.httpd.rocks.key /etc/openssl/certs/bozo.httpd.rocks.fullchain.pem
```
**Important**: Before moving on, we need to:
1. Tweak the permissions of our cert files to avoid unwanted errors
2. Setup a simple`cronjob`to check our cert expiry dates daily
### Tweaking Permissions
```
doas chown root:wheel /etc/openssl/private/bozo.httpd.rocks.key
doas chmod 600 /etc/openssl/private/bozo.httpd.rocks.key
doas chgrp wheel /etc/openssl/private
doas chmod 700 /etc/openssl/private
```
### Running a Daily cronjob
You’ll want to setup this cron entry under`root`:
Then setup something simple:
```
0 3 * * * acme-client bozo.httpd.rocks
```
## Updating`inetd\.conf`to Support HTTPS
Return to the original`inetd\.conf`file and include support for`https`:
```
http stream tcp nowait:600 _httpd /usr/libexec/httpd httpd /var/www/bozo.httpd.rocks
https stream tcp nowait:600 root /usr/libexec/httpd httpd -U _httpd -Z /etc/openssl/certs/bozo.httpd.rocks.fullchain.pem /etc/openssl/private/bozo.httpd.rocks.key /var/www/bozo.httpd.rocks
```
You might have noticed that we use`root`user for the`https`instance\. This is required to avoid issues with running our`acme\-client`job above\.
Now restart`inetd`one last time:
That’s it\! Enjoy your web server\!
---
## What About Multiple Websites?
Don’t worry\! I’ve got you covered\. The following assumes you*completed everything*above this section\.
### Updating acme\-client\.conf
We will make a new key/pem pair \(calling it`websites`\) that will be shared across all of our hosted domains\. The first step is to include these “alternate” domains inside our`acme\-client\.conf`file:
```
authority letsencrypt {
api url "https://acme-v02.api.letsencrypt.org/directory"
account key "/etc/acme/letsencrypt-privkey.pem"
}
domain bozo.httpd.rocks {
domain key "/etc/openssl/private/websites.key"
domain full chain certificate "/etc/openssl/certs/websites.fullchain.pem"
alternative names {
example.com
example.org
example.net
}
sign with letsencrypt
challengedir "/var/www/acme"
}
```
### Symlink to the Rescue\!
You’ll need to “trick”`acme\-client`\(in the next steps\) into targeting the shared`\.well\-known`directory\. This will need to be done for each domain:
```
doas mkdir -p /var/www/example.com/.well-known
doas ln -sf /var/www/acme /var/www/example.com/.well-known/acme-challenge
```
### Updating inetd\.conf
We need to slightly tweak our existing`inetd\.conf`file and utilize bozohttpd’s`\-v`&`\-V`parameters:
```
http stream tcp nowait:600 _httpd /usr/libexec/httpd httpd -v /var/www -V default /var/www/default
```
Also be sure to remove the specific`https`line entirely\. After making those changes you can restart`inetd`:
```
doas /etc/rc.d/inetd restart
```
And now run through`acme\-client`to grab the new certs:
```
doas acme-client -v bozo.httpd.rocks
```
### Editing rc\.conf
Now we make some simple adjustments to our`/etc/rc\.conf`file:
```
httpd=YES
httpd_flags="-v /var/www -V -U _httpd -Z /etc/openssl/certs/websites.fullchain.pem /etc/openssl/private/websites.key"
httpd_wwwdir="/var/www/default"
```
and reload that as well:
```
doas /etc/rc.d/httpd restart
```
Congrats\! You are now hosting multiple websites through`bozohttpd`\!
---
A comprehensive guide on how an HTTP server works, covering networking protocols, chunked encoding, state machines, parser writing, and concurrency basics, with instructions to build one yourself.
The article introduces 'ymawky', a minimal HTTP web server written entirely in aarch64 assembly for macOS, using raw syscalls without libc wrappers to explore low-level system mechanics.
A blog post detailing the ongoing revival and modernization of OpenBSD's relayd(8) and httpd(8) daemons, including efforts to modernize the imsg message system and address pending diffs, with the author citing LLMs as motivation to return to C programming.