The irony of having a BSD centric post as my first post on the linuxlab blog is not lost on me…
As a Linux admin by trade for the last two decades, I’ve only dabbled in BSD here and there. My last prior real experience with a BSD was when FreeBSD 5 was considered unstable. So it’s been quite a while.
Why am I doing this?
I had a thought that I might want to try to “spin up” an OpenBSD webhead for cheap on a VPS provider, just to get my bearings again with the progress of the razor-sharp security focused BSD Distribution. Caddy is my preferred http daemon these days since its dead simple to configure and get started with. But it doesn’t exist in the package tree. So we’ll manually install it and set it up to auto-start on boot.
Install Caddy on OpenBSD 6
Installation of caddy was quite painless. We’ll need to add the curl package in order to get started
pkg_add curl
pkg_add bash
Once we’ve installed curl from the ports package tree, lets go ahead and grab caddy from its official upstream.
Note: the following is not considered best practice, but included for expediency, and contains my default set of plugins.
curl https://getcaddy.com | bash -s http.cache,http.ipfilter,http.ratelimit
Now that caddy is installed, we can verify this with a which
command.
$ which caddy
/usr/local/bin/caddy
Great, we have the daemon binary installed, we’ll skip the Caddy configuration for now, and examine the rc scripts.
RC Scripting
This is where I was really tripped up. I didn’t think I’d ever find myself saying this but I really kind of missed systemd in this particular instance. And that’s only because I’m intimately familiar with how to create and manage services in systemd (or upstart, or sysvinit for that matter).
OpenBSD uses a very simplistic RC init system that is deceptively complex. And I’m only 80% clear on why I did some of the things I did along this process.
EDIT - Located a Template
After writing this article, I ran across a template for writing your rc files distributed via the upstream CVS server.
Inspect the templat here This will ease creation of new RC files significantly.
Create the rc.d/caddy file
Daemons are executed with an rc script, and they can load a special set of shell helpers to make generating rc files quick - given that you know the framework in use.
The following is the contents of /etc/rc.d/caddy
#!/bin/ksh
#
# $OpenBSD: caddy 2018/08/19
daemon="/usr/local/bin/caddy"
daemon_flags="-conf /etc/Caddyfile"
. /etc/rc.d/rc.subr
rc_bg=YES
rc_reload=NO
rc_start() {
${rcexec} "${daemon} ${daemon_flags} ${_bg}"
}
rc_check() {
pgrep -T "${daemon_rtable}" -q -xf "${pexp}"
}
rc_stop() {
pkill -T "${daemon_rtable}" -xf "${pexp}"
}
rc_cmd $1
You’ll notice that we source /etc/rc.d/rc.subr
- this is the magic sauce
that gives you the flexibility to free-form your rc file.
Each function defined: rc_start, rc_check, rc_stop
refer to a state/event
happening during the daemons lifecycle. We invoke rcexec
to control the
process kind of like we would with start-stop-daemon
in older linux installations.
Note: I’m not entirely positive in rcexec works at all like start-stop daemon but this is my own anecdotal findings.
We’ve scripted a few commands to feed back information in to the rc.subr framework
in the rc_check
invocation, which lets the rc system know when caddy is running.
And as you might have guessed. rc_stop
simply kills the parent thread of the
executing daemon.
We’re not quite done yet, we’ll need to inform the RC system about caddy’s
existance in /etc/rc.conf.local
:
pkg_scripts="caddy"
Now, we can use rcctl
to enable and start caddy.
sudo rcctl enable caddy
sudo rcctl start caddy
If you’ve placed the config file in /etc/Caddyfile
you should be able to navigate
to your server’s IP and get a response. There’s still more to do here, like
privilege de-escalation (its currently running as root). But this is a good
start, that we have a functional Caddy rc file.
Man pages for further reading
The BSD Man pages are an excellent guide, and will serve to help you along the way. I found the following man pages of great use in my journey to this minimally functioning rc script:
man 8 rc
man 8 rc.conf
man 8 rc.subr
Happy hacking out there! Until next time.