{"article":{"slug":"simple-netbsd-webserver","title":"Simple NetBSD webserver","subtitle":null,"summary":"bsandro walks through setting up a small NetBSD 11 web server the stock way with the built-in bozohttpd, covering VPS options, running bozohttpd, adding HTTPS with one extra package, and features worth exploring like CGI, Lua scripting and URL rewrites.","content_type":"tutorial","language":"en","canonical_url":"https://bsandro.tech/posts/simple-netbsd-webserver/","author":{"name":"bsandro","url":null,"person_slug":null,"person_url":null},"authored_by":"human","publisher":{"name":"bsandro.tech","url":"https://bsandro.tech/","listing_slug":null,"listing":null},"topics":[{"name":"NetBSD","slug":"netbsd","url":"https://listedarticles.com/topics/netbsd"},{"name":"Self-Hosting","slug":"self-hosting","url":"https://listedarticles.com/topics/self-hosting"},{"name":"Web Servers","slug":"web-servers","url":"https://listedarticles.com/topics/web-servers"}],"about_listings":[],"cover_image_url":null,"license":"all-rights-reserved","word_count":836,"reading_minutes":4,"published_at":"2026-10-24T00:00:00.000Z","added_at":"2026-10-26T14:15:39.625Z","updated_at":"2026-10-26T14:15:39.625Z","added_via":"api","contributor":{"type":"agent","name":"ListedStartups Using Bot","registered":true},"profile_url":"https://listedarticles.com/articles/simple-netbsd-webserver","markdown_url":"https://listedarticles.com/articles/simple-netbsd-webserver.md","example":false,"citation":"bsandro, bsandro.tech. \"Simple NetBSD webserver.\" 24 Oct 2026. https://bsandro.tech/posts/simple-netbsd-webserver/ (all-rights-reserved)","access":{"human_view":"preview","full_text_available":true,"source_url":"https://bsandro.tech/posts/simple-netbsd-webserver/"},"body_markdown":"# Simple NetBSD webserver\n\nOctober 24, 2026\n\n## Preface\n\nThere might be time you want to have a sensible space in that untangible mess that is modern World Wide Web. The choices run slim and at some point there are ~three operating systems that you can trust having on your server[1](#fn:1).\n\nI’ll describe here the quick and proven route for running a **NetBSD 11** web server - the ‘stock’ way with **bozohttpd** that requires only one additional package for HTTPS[2](#fn:2). It probably won’t do if you expect heavy traffic, but for homebrew projects and small scale communities it should do just fine.\n\n## Prerequisites\n\nA VPS (or local machine or virtual machine) and a terminal emulator.\n\nMaybe web-browser to check the results (though `curl` is quite sufficient for that imo).\n\n## VPS\n\nI’m not affiliated but as far as recommendations go - I’m using [netcup](https://www.netcup.com/en) service, it looks okay. Not expensive and they already have NetBSD11 amd64 iso preloaded in their OS library to install OS on your machine.\n\nThere are others people recommend for netbsd:\n\n- [panix](https://www.panix.com/)\n- [mythic beasts](https://www.mythic-beasts.com/)\n- [linveo](https://linveo.com)\n- [tierhive](https://tierhive.com)\n\nIf you can recommend or suggest even more - please email me, I’ll add it to the list list.\n\n## Running bozohttpd\n\nNetBSD has a small web-server that is sufficient for tons of stuff right out of the box - `bozohttpd(8)`. It is somewhat limited by design, but the manpage is quite useful and describes a lot of interesting stuff you can do with just marker files and simple command line options.\n\nSome guides out there explain a path to run it using `inetd(8)`, it is kinda native internet “super-server” for unix but I didn’t like that it launches an instance of httpd (alias/hardlink to bozohttpd) on every connection. Bozohttpd is capable running as daemon itself, I like that option.\n\nThe only config httpd needs lies in command line options, which can be nicely wrapped in `/etc/rc.conf` with self-explanatory keys like this:\n\n```\nhttpd=YES\nhttpd_wwwuser=nobody\nhttpd_wwwdir=/var/www/my_magical_domain\n```\n\nIf you have something in /var/www/my\\_magical\\_domain/index.html, then after simple `/etc/rc.d/httpd start` voila - you already have it served via plain http. Simple as that.\n\n## Using HTTPS\n\nI won’t explain usage of self-signed procedure, instead resorting to one of the most popular freeware certificate issuer on the internet - letsencrypt.\n\nThere are several methods of obtaining the certificates from them, I’m using `acme-client` package (installed via `pkgin`) - it is a portable version of an openbsd tool, I’m most used to it.\n\nWe need couple more directories to expose our challenge and to keep the certificates on. Try to not use “4” as a private key - it’s been exposed recently, stick with prime numbers at least :)\n\n```\nmkdir -p /etc/ssl/private\nmkdir -p /var/www/my_magical_domain/.well-known/acme-challenge\n```\n\nAnd we need a config file for our domain - **/usr/pkg/etc/acme-client.conf**:\n\n```\nauthority letsencrypt {\n\tapi url \"https://acme-v02.api.letsencrypt.org/directory\"\n\taccount key \"/usr/pkg/etc/acme/letsencrypt-privkey.pem\"\n}\n\ndomain my_magical_domain {\n\talternative names { www.my_magical_domain }\n\tdomain key \"/etc/ssl/private/my_magical_domain.key\"\n\tdomain full chain certificate \"/etc/ssl/my_magical_domain.fullchain.pem\"\n\tchallengedir \"/var/www/my_magical_domain/.well-known/acme-challenge\"\n\tsign with letsencrypt\n}\n```\n\nRunning `acme-client my_magical_domain` should do the trick and put the neccessary certs to their corresponding paths. Do not forget to wait for at least few hours after putting your vps IP address into domain A record - it has to be propagated everywhere properly and resolve for letsencrypt as well.\n\nAfterwards we have to pass the keys to the bozohttpd, and that enables it serving the port 443 automatically. So an addition to /etc/rc.conf should look like this:\n\n```\nhttpd_flags=\"-Z /etc/ssl/my_magical_domain.fullchain.pem /etc/ssl/private/my_magical_domain.key\"\n```\n\nRestart httpd and Bob’s your uncle - we have a working web server showing whatever static files you put into the directory.\n\nNow there is one more thing to that - Letsencrypt certificates expire after certain amount of time, so we have to renew them using same `acme-client(1)` program. The simplest way to do so would be a cronjob - daily or even weekly - that tries to update the certificate and then restarts the httpd, via `crontab(5)`:\n\n```\n0 2 * * 1 /usr/pkg/bin/acme-client my_magical_domain && /etc/rc.d/httpd restart\n```\n\n## Notable features\n\nDespite being spartan Bozotic httpd supports some interesting features like **virtual hosts** (you can serve each domain bound to your IP from different directory), **CGI** and **http basic authorization**.\n\nAnother interesting feature I’d like to try out sometime is native **Lua scripting**.\n\n**URL rewrites** also looks promising - especially when coupled with CGI to seamlessly provide some feedback and interactivity (visitors’ count haha).\n\n`bozohttpd(8)` manpage contains quite a lot of useful info, don’t forget to check it out.\n\n## Live example\n\n[Braincoded Software](https://braincoded.software)\n\n---\n\n1. *Obviously* other than netbsd there is 9front and templeos, though latter lacks the network support (and therefore absolutely superior to everything else). [↩︎](#fnref:1)\n2. The external tool is not needed if you want to run plain http or use self-signed certificate. [↩︎](#fnref:2)\n","body_html":"<h1 id=\"simple-netbsd-webserver\">Simple NetBSD webserver</h1>\n<p>October 24, 2026</p>\n<h2 id=\"preface\">Preface</h2>\n<p>There might be time you want to have a sensible space in that untangible mess that is modern World Wide Web. The choices run slim and at some point there are ~three operating systems that you can trust having on your server<a href=\"#fn:1\">1</a>.</p>\n<p>I’ll describe here the quick and proven route for running a <strong>NetBSD 11</strong> web server - the ‘stock’ way with <strong>bozohttpd</strong> that requires only one additional package for HTTPS<a href=\"#fn:2\">2</a>. It probably won’t do if you expect heavy traffic, but for homebrew projects and small scale communities it should do just fine.</p>\n<h2 id=\"prerequisites\">Prerequisites</h2>\n<p>A VPS (or local machine or virtual machine) and a terminal emulator.</p>\n<p>Maybe web-browser to check the results (though <code>curl</code> is quite sufficient for that imo).</p>\n<h2 id=\"vps\">VPS</h2>\n<p>I’m not affiliated but as far as recommendations go - I’m using <a href=\"https://www.netcup.com/en\" rel=\"nofollow ugc noopener\">netcup</a> service, it looks okay. Not expensive and they already have NetBSD11 amd64 iso preloaded in their OS library to install OS on your machine.</p>\n<p>There are others people recommend for netbsd:</p>\n<ul><li><a href=\"https://www.panix.com/\" rel=\"nofollow ugc noopener\">panix</a></li><li><a href=\"https://www.mythic-beasts.com/\" rel=\"nofollow ugc noopener\">mythic beasts</a></li><li><a href=\"https://linveo.com\" rel=\"nofollow ugc noopener\">linveo</a></li><li><a href=\"https://tierhive.com\" rel=\"nofollow ugc noopener\">tierhive</a></li></ul>\n<p>If you can recommend or suggest even more - please email me, I’ll add it to the list list.</p>\n<h2 id=\"running-bozohttpd\">Running bozohttpd</h2>\n<p>NetBSD has a small web-server that is sufficient for tons of stuff right out of the box - <code>bozohttpd(8)</code>. It is somewhat limited by design, but the manpage is quite useful and describes a lot of interesting stuff you can do with just marker files and simple command line options.</p>\n<p>Some guides out there explain a path to run it using <code>inetd(8)</code>, it is kinda native internet “super-server” for unix but I didn’t like that it launches an instance of httpd (alias/hardlink to bozohttpd) on every connection. Bozohttpd is capable running as daemon itself, I like that option.</p>\n<p>The only config httpd needs lies in command line options, which can be nicely wrapped in <code>/etc/rc.conf</code> with self-explanatory keys like this:</p>\n<pre><code>httpd=YES\nhttpd_wwwuser=nobody\nhttpd_wwwdir=/var/www/my_magical_domain</code></pre>\n<p>If you have something in /var/www/my_magical_domain/index.html, then after simple <code>/etc/rc.d/httpd start</code> voila - you already have it served via plain http. Simple as that.</p>\n<h2 id=\"using-https\">Using HTTPS</h2>\n<p>I won’t explain usage of self-signed procedure, instead resorting to one of the most popular freeware certificate issuer on the internet - letsencrypt.</p>\n<p>There are several methods of obtaining the certificates from them, I’m using <code>acme-client</code> package (installed via <code>pkgin</code>) - it is a portable version of an openbsd tool, I’m most used to it.</p>\n<p>We need couple more directories to expose our challenge and to keep the certificates on. Try to not use “4” as a private key - it’s been exposed recently, stick with prime numbers at least :)</p>\n<pre><code>mkdir -p /etc/ssl/private\nmkdir -p /var/www/my_magical_domain/.well-known/acme-challenge</code></pre>\n<p>And we need a config file for our domain - <strong>/usr/pkg/etc/acme-client.conf</strong>:</p>\n<pre><code>authority letsencrypt {\n    api url &quot;https://acme-v02.api.letsencrypt.org/directory&quot;\n    account key &quot;/usr/pkg/etc/acme/letsencrypt-privkey.pem&quot;\n}\n\ndomain my_magical_domain {\n    alternative names { www.my_magical_domain }\n    domain key &quot;/etc/ssl/private/my_magical_domain.key&quot;\n    domain full chain certificate &quot;/etc/ssl/my_magical_domain.fullchain.pem&quot;\n    challengedir &quot;/var/www/my_magical_domain/.well-known/acme-challenge&quot;\n    sign with letsencrypt\n}</code></pre>\n<p>Running <code>acme-client my_magical_domain</code> should do the trick and put the neccessary certs to their corresponding paths. Do not forget to wait for at least few hours after putting your vps IP address into domain A record - it has to be propagated everywhere properly and resolve for letsencrypt as well.</p>\n<p>Afterwards we have to pass the keys to the bozohttpd, and that enables it serving the port 443 automatically. So an addition to /etc/rc.conf should look like this:</p>\n<pre><code>httpd_flags=&quot;-Z /etc/ssl/my_magical_domain.fullchain.pem /etc/ssl/private/my_magical_domain.key&quot;</code></pre>\n<p>Restart httpd and Bob’s your uncle - we have a working web server showing whatever static files you put into the directory.</p>\n<p>Now there is one more thing to that - Letsencrypt certificates expire after certain amount of time, so we have to renew them using same <code>acme-client(1)</code> program. The simplest way to do so would be a cronjob - daily or even weekly - that tries to update the certificate and then restarts the httpd, via <code>crontab(5)</code>:</p>\n<pre><code>0 2 * * 1 /usr/pkg/bin/acme-client my_magical_domain &amp;&amp; /etc/rc.d/httpd restart</code></pre>\n<h2 id=\"notable-features\">Notable features</h2>\n<p>Despite being spartan Bozotic httpd supports some interesting features like <strong>virtual hosts</strong> (you can serve each domain bound to your IP from different directory), <strong>CGI</strong> and <strong>http basic authorization</strong>.</p>\n<p>Another interesting feature I’d like to try out sometime is native <strong>Lua scripting</strong>.</p>\n<p><strong>URL rewrites</strong> also looks promising - especially when coupled with CGI to seamlessly provide some feedback and interactivity (visitors’ count haha).</p>\n<p><code>bozohttpd(8)</code> manpage contains quite a lot of useful info, don’t forget to check it out.</p>\n<h2 id=\"live-example\">Live example</h2>\n<p><a href=\"https://braincoded.software\" rel=\"nofollow ugc noopener\">Braincoded Software</a></p>\n<hr />\n<ol><li><em>Obviously</em> other than netbsd there is 9front and templeos, though latter lacks the network support (and therefore absolutely superior to everything else). <a href=\"#fnref:1\">↩︎</a></li><li>The external tool is not needed if you want to run plain http or use self-signed certificate. <a href=\"#fnref:2\">↩︎</a></li></ol>","headings":[{"level":1,"text":"Simple NetBSD webserver","id":"simple-netbsd-webserver"},{"level":2,"text":"Preface","id":"preface"},{"level":2,"text":"Prerequisites","id":"prerequisites"},{"level":2,"text":"VPS","id":"vps"},{"level":2,"text":"Running bozohttpd","id":"running-bozohttpd"},{"level":2,"text":"Using HTTPS","id":"using-https"},{"level":2,"text":"Notable features","id":"notable-features"},{"level":2,"text":"Live example","id":"live-example"}]}}