Setting up a ZNC bouncer on OpenBSD 6.4

The latest version of OpenBSD contains everything you might need to create a really powerful (SSL) ZNC bouncer in just a few simple steps, fully secured by you very own letsencrypt certificate.

The arms of a bouncer with an OpenBSD logo

Create an OpenBSD machine

Nothing could be more simple using Exoscale's "exo" command line client.

Firewall considerations

We'll want to make sure the following ports are let through to our OpenBSD instance:

  • 22/TCP: of course, we'll need to SSH into our machine, so port 22 needs to be allowed through.
  • 80/TCP: We'll use the default HTTP port in the process to obtain our Let's Encrypt certificate (to serve the challenge response).
  • 6697/TCP: The actual IRC port! You could pick something else here, as long as it's used consistently during the rest of this article.

This configuration can be easily applied using Exoscale security groups:

exo firewall create bouncer -d "The firewall rules for our bouncer"

This created a new security group, but it lacks rules for now. Let's fix that:

exo firewall add bouncer ssh
exo firewall add bouncer http
exo firewall add bouncer -P 6697 -p tcp -c "0.0.0.0/0" -d "IRC over SSL"

We're good to go! On with the actual instance.

Creating an OpenBSD cloud instance

Once again, the Exoscale CLI tool makes this easy for us:

VM_NAME="my-bouncer"
exo vm create -t OpenBSD $VM_NAME -s bouncer

Once deployed, connecting to the machine is as simple as:

exo ssh $VM_NAME

That should drop you right into an OpenBSD root shell. Nice!

You might want to install vim (or your favorite editor) now:

pkg_add vim

You can otherwise rely on vi.

Now is also a good time to setup a normal user. ZNC refuses to run as root (rightfully so), and this is good practice anyway.

Since our user will have to read the SSL private key (in order to let ZNC use it), let's prepare the ground and add the user to the wheel group as well.

adduser $USERNAME wheel

Setting up the acme/SSL with letsencrypt

OpenBSD comes preinstalled with all the tools we'll need to setup a proper SSL certificate for our instance.

Setting up DNS

This is a little bit outside of the scope of this article - but since we'll ask for a real Let's Encrypt certificate, now is the time for you to make sure your machine has a proper DNS name.

The DNS name will be henceforth refered to as $DOMAIN_NAME in the rest of this article.

Using httpd to serve the Let's Encrypt challenge

The way Let's Encrypt works is to send the acme client a challenge, that the requesting machine must then answer by placing a signed file in an HTTP accessible folder.

OpenBSD ships with a very capable web server in main, and it will be more than suited to serve the simple challenge. acme-client even comes with documentation on how to set it up!

First, let's enable httpd:

echo "httpd_flags=" > /etc/rc.conf.local

Before it can start, it will need a config file. Thankfully it's a very simple one, and is almost a perfect copy of the example given in acme-client's man page.

cat > /etc/httpd.conf <<EOF
server "default" {
        listen on * port 80

        location "/.well-known/acme-challenge/*" { 
                root "/acme" 
                request strip 2 
        }
}
EOF

Once the config is there, we can enable the service (so it survives reboots), and start it:

rcctl enable httpd
rcctl start httpd

Setting up and using acme client on OpenBSD

Thankfully, OpenBSD includes an acme client in base, so there's nothing for us to install!

Let's configure it:

# /etc/acme-client.conf
domain $DOMAIN_NAME {
        domain key "/etc/ssl/private/$DOMAIN_NAME.key"
        domain certificate "/etc/ssl/$DOMAIN_NAME.crt"
        domain full chain certificate "/etc/ssl/$DOMAIN_NAME.fullchain.pem"
        sign with letsencrypt
}

Now that we told acme client how to get a certificate for us and that we are ready to serve up the challenge it will send us, we should be all set to get a Let's Encrypt certificate.

To actually make the client request one for us, simply invoke, as root:

acme-client -vAD $DOMAIN_NAME

Adding the renewal to a cron

OpenBSd makes managing cron jobs very simple - daily crons can be added to the /etc/daily.local file (the file itself is the script).

echo 'acme-client $DOMAIN_NAME' >> /etc/daily.local

Ensure your user can see the key

We will run ZNC as a regular user (it even refuses to run as root), so we need to ensure that the user we selected to run our ZNC session can see the acme private key (the ZNC server needs to see the key to sign packets, of course).

Since the user we created is already in the wheel group, we just need to change the key's ownership:

chown $USERNAME /etc/ssl/private/$DOMAIN_NAME.key
chmod g+rx /etc/ssl/private  # This allows wheel members to list the dir.

Install znc

pkg_add znc

Make sure the configuration file does not have ipv6 enable as it apparently makes assumptions that are not valid on OpenBSD.

The last step is to simply run ZNC as your user! Or, of course, importing your configuration to ~/.znc/

Enjoy :)

As usual don't hesitate to let me know if you found this helpful!