Using Let's Encrypt with UnrealIRCd

Introduction
Let's Encrypt is an initiative which allows you to get a real certificate for your server. That is, a certificate from a trusted Certificate Authority.

In the past, before 2016, you had two options: The first option works fine but costs money. The problem with the second option is that anyone can create such a certificate and someone with sufficient skills and resources could impersonate you. This is called a MitM attack. In other words: such a certificate is not as secure as a real one.
 * 1) Buy a certificate from a trusted Certificate Authority, or
 * 2) Use a self-signed certificate, like the one created during your first UnrealIRCd installation.

Before you begin
Let's Encrypt requires you to setup a number of things and will issue you 90-day certificate. Getting the certificate for the first time requires some manual labor. After this, you will setup automatic renewal. Automatic renewal will take care of generating and installing a new 90-day certificate each time the old one is near expiry, so you won't have to worry about the 90 day limit. This is all explained in this tutorial.

Requirements
This tutorial is written for *NIX. Perhaps one day someone could expand it for Windows (if possible). Additional steps may be required for some *nix platforms due to experimental support only from Let's Encrypt (most notably macOS) - this configuration is not covered here but once it has been setup the rest of this tutorial will still work.

The Let's Encrypt installation as described in this tutorial requires root access. We will assume you are running UnrealIRCd on a VPS and you have root access, this is after all the most common situation. Be sure to do all the things in this tutorial as root. Become root now by using  or whatever command or login method you normally use to become root.

Installing certbot
First, you need to install the 'certbot' tool. Follow the Install instructions on EFF's certbot page. A typical choice for a Linux user would be to choose I'm using -None of the above- on -Ubuntu/Debian/..-

IMPORTANT: Follow the Install instructions only, then get back here!

Open up port 80 (firewall!)
In this tutorial we will use port 80 as part of let's encrypt's verification mechanism. Make sure incoming port 80 is not firewalled. If you use the ufw firewall you may want to run something like. If you are using Amazon EC2 then don't forget to also allow port 80 in your Security Group.

Getting your first certificate (TEST)
Like all commands in this tutorial, run the following as root. Replace irc1.example.net with your server name: certbot certonly --test-cert --standalone --preferred-challenges http-01 -d irc1.example.net

You will be asked a few questions: Saving debug log to /var/log/letsencrypt/letsencrypt.log Enter email address (used for urgent renewal and security notices) (Enter 'c' to cancel): Enter your email address here Starting new HTTPS connection (1): acme-staging.api.letsencrypt.org
 * 1) certbot certonly --test-cert --standalone --preferred-challenges http-01 -d irc1.example.net

--- Please read the Terms of Service at https://letsencrypt.org/documents/LE-SA-v1.1.1-August-1-2016.pdf. You must agree in order to register with the ACME server at https://acme-staging.api.letsencrypt.org/directory --- (A)gree/(C)ancel: A

--- Would you be willing to share your email address with the Electronic Frontier Foundation, a founding partner of the Let's Encrypt project and the non-profit organization that develops Certbot? We'd like to send you email about EFF and our work to encrypt the web, protect its users and defend digital rights. --- (Y)es/(N)o: N Obtaining a new certificate Performing the following challenges: http-01 challenge for irc1.example.net Waiting for verification... Cleaning up challenges

IMPORTANT NOTES: - Congratulations! Your certificate and chain have been saved at: /etc/letsencrypt/live/irc1.example.net/fullchain.pem Your key file has been saved at: /etc/letsencrypt/live/irc1.example.net/privkey.pem Your cert will expire on 2017-12-01. To obtain a new or tweaked version of this certificate in the future, simply run certbot again. To non-interactively renew *all* of your certificates, run "certbot renew"

If you don't see the congratulations and instead see an error then you will have to resolve this first. Possible errors could be: a webserver running on port 80 or a firewall. The Let's Encrypt user community may be helpful.

If you have any errors, resolve them first, before proceeding!

Getting your first certificate (FOR REAL)
This assumes previous step was successful. It's now time to get the real certificate.

Get the real certificate
You will run (almost) the same command as in your test run earlier. The only thing you remove is the --test-cert parameter.

Command for single server network or network without robin DNS. Replace irc2.example.net with your server name: certbot certonly --standalone --preferred-challenges http-01 -d irc2.example.net You may have to answer a couple of questions again. Should you get a question about 'expanding or replacing' the certificate, answer E (for Expand).

Note on Round Robin DNS
Do you have a multi-server network with round-robin DNS enabled? That is, you have multiple servers (eg:  irc1 .example.net,  irc2 .example.net) and they are both also reachable by the name  irc .example.net.

In that case you will want your certificate to be valid for both names. Run the following as root. Replace irc2.example.net with your servername and irc.example.net with your "round robin DNS name": certbot certonly --standalone --preferred-challenges http-01 -d irc2.example.net -d irc.example.net As you can see you are requesting two names in the certificate here, irc2.example.net and irc.example.net.

IMPORTANT: Unfortunately Let's Encrypt is a real pain with Round Robin DNS. You will likely hit an error and have to re-try the command a number of times in order to get the certificate. This is because Let's Encrypt does not (necessarily) connect back to your host. It may connect to any other host in the round robin DNS. If you have only 2 servers then it may be doable in a couple of attempts, after all your chance is 1 out of 2 each attempt. If you have more than two or three servers then this may be troublesome. Let's Encrypt only permits 5 failed attempts per hour per account/host so you will quickly reach this limit (if you do, wait an hour). The solution to this problem is quite complex and involves setting up http servers/proxies on all your IRC servers (TODO: link anyone?).

Alternative: you could also consider buying a certificate for irc.example.net instead. Simple domain-only validation certificates are relatively cheap these days ($10 per year for a Comodo certificate via 3rd parties). Together with an Sni block this will be easy to setup. Basically you will use the paid irc.example.net SSL certificate in your Sni block and use the free Let's Encrypt certificate to serve the irc2.example.net one (using this tutorial as if it were a single server).

Alternative 2: if you are really lazy you could buy a wildcard domain certificate for *.example.net. These cost about $100 per year and you simply install them on as many servers as you want.

Install the certificate
Assuming previous step was successful a message was printed like: - Congratulations! Your certificate and chain have been saved at: /etc/letsencrypt/live/irc2.example.net/fullchain.pem Your key file has been saved at: /etc/letsencrypt/live/irc2.example.net/privkey.pem

Remember these paths.

Now I'm going to assume the path to your UnrealIRCd installation is /home/ircd/unrealircd and the account is called ircd. If this is not the case then change the path- and usernames in the commands below to suit your setup !

First of all, let's backup your existing SSL certificate, just to be sure.

cp /home/ircd/unrealircd/conf/ssl/server.cert.pem /home/ircd/unrealircd/conf/ssl/server.cert.pem.old cp /home/ircd/unrealircd/conf/ssl/server.key.pem /home/ircd/unrealircd/conf/ssl/server.key.pem.old

Now, let's copy the new certificate. Again, change the paths if needed: cp /etc/letsencrypt/live/irc2.example.net/fullchain.pem /home/ircd/unrealircd/conf/ssl/server.cert.pem cp /etc/letsencrypt/live/irc2.example.net/privkey.pem /home/ircd/unrealircd/conf/ssl/server.key.pem

We also need to change ownership of the files so the ircd account can read it (change ircd to your account name if it's named differently): chown ircd /home/ircd/unrealircd/conf/ssl/server.*.pem

If all of the above went well, make UnrealIRCd re-read the certificate. You should do this via /REHASH -ssl on IRC: /REHASH -ssl 18:55 [ExampleNET] !irc2.example.net *** [SSL rehash] Oper (~oper@test.net) requested a reload of all SSL related data (/rehash -ssl) You should not see any warnings or errors.

Now it's time to test your certificate! (re)connect to your server using SSL/TLS and make sure the certificate looks good (TODO: some site?)

IMPORTANT: You are NOT done yet! Certificates are only valid for 90 days so you need to setup certificate renewal

Certificate renewal
Put the following script in /usr/local/bin/unrealircd_cert
 * 1) !/bin/bash
 * 2) Script to renew Let's Encrypt (LE) certificate and install
 * 3) it in UnrealIRCd, taking into account user permissions.
 * 4) Version: 2017-09-02
 * 5) Please edit the following settings to match your configuration:
 * 1) Please edit the following settings to match your configuration:
 * 1) Please edit the following settings to match your configuration:

CERT="/etc/letsencrypt/live/irc1.unrealircd.org/fullchain.pem"
 * 1) Full path to LE certificate (usually called fullchain.pem)

KEY="/etc/letsencrypt/live/irc1.unrealircd.org/privkey.pem"
 * 1) Full path to LE key (usually called privkey.pem)

UNREALIRCD="/home/ircd/unrealircd"
 * 1) Full path to your UnrealIRCd directory

ACCOUNT="ircd"
 * 1) Username which runs UnrealIRCd


 * 1) Do not edit below this line
 * 1) Do not edit below this line

CERT_DEST="$UNREALIRCD/conf/ssl/server.cert.pem" KEY_DEST="$UNREALIRCD/conf/ssl/server.key.pem"

certbot renew

if cmp $CERT $CERT_DEST >/dev/null 2>&1; then exit 0 fi
 * 1) Now exit if the certificate is unchanged:

echo "Certificate changed. Installing to UnrealIRCd."

rm -f $CERT_DEST $KEY_DEST cp $CERT $CERT_DEST || exit 1 cp $KEY $KEY_DEST || exit 1 chown --no-dereference $ACCOUNT $CERT || exit 1 chown --no-dereference $ACCOUNT $KEY || exit 1

echo "Certificate and keys succesfully installed."

su -s /bin/sh -c "cd $UNREALIRCD; ./unrealircd reloadtls" - $ACCOUNT

Edit the script with your favorite editor to match your configuration: pico /usr/local/bin/unrealircd_cert

Make the script executable: chmod +x /usr/local/bin/unrealircd_cert

Test-run it: /usr/local/bin/unrealircd_cert

Then add a root crontab entry for it: crontab -e For example add this to the end of the crontab to make it run twice a day at 07:30 and 19:30: 30 19,07  * * *   /usr/local/bin/unrealircd_cert 1>/dev/null 2>&1

That's it. If for some reason your renewal script stops working correctly, Let's Encrypt will notify you about a week prior to your certificates expiration, giving you time to manually renew and fix your script - that said we do recommend periodically checking on your own to be sure renewals are happening and not relying on such notifications.

NOTE: If you install on multiple servers we recommend choosing different times for each server.

Update your link blocks
What type of link::password do you use? You may need to update them. Not only in unrealircd.conf on this server but also on the remote links.

SSL fingerprint validation
If you have: link irc1.test.net { [..]   password "00:11:22:33:44:55:66:77:88:99:AA:BB:CC:DD:EE:FF"; }; Then you are using SSL fingerprint validation.

This will not work with Let's Encrypt since certificates are renewed every 30-90 days. Instead, switch to password authentication (see next).

Password authentication
If you have: link irc1.test.net { [..]   password "somepassword"; }; Then you are fine. But, also check next section.

Additional verification
If you are running UnrealIRCd 4.0.14 or later you should turn on certificate validation by adding this to your link block: link irc1.test.net { [..]   verify-certificate yes; };

This will make UnrealIRCd check if the certificate is valid when linking. It will prevent a man in the middle attack.