quassel core on NixOS with Let's Encrypt

Published 2020-09-02 on Farid Zakaria's Blog

I have been wanting to take part of the NixOS community more; specifically the IRC channels. I have been heavily using the Discord server but I found many other contributors are only on the IRC network. ✊

#nixos #nix-community

I am however an admitted IRC n00b; and one of the biggest pain-points of IRC are that due to the decentralized nature of it, you don’t get to see any log messages when you are offline. How frustrating!

I tried https://matrix.org/ however the IRC bridge is not really great as it will not send large messages.

If I wasn’t enthusiastic about setting up a NixOS server I might just have used https://www.irccloud.com/.

A colleague however introduced me to Quassel.

Quassel IRC is a modern, cross-platform, distributed IRC client, meaning that one (or multiple) client(s) can attach to and detach from a central core.

Great! Let’s set that up on NixOS.

Prerequisites

I have a laptop which I will be running the Quassel client.

I have a NixOS server which I will be running the Quassel core server.

I have a registered sub-domain https://quassel.example.com which I’ve pointed to my server.

Requirements

I would like to run Quassel with TLS using Let’s Encrypt; a free TLS certificate provider.

NixOS Setup

TLS / ACME

First I create a module acme.nix; that will take care of fetching a TLS certificate from Let’s Encrypt using the ACME protocol.

I’ve heavily commented the below example to explain what’s going-on.

{ config, ...}: {

  # We will setup HTTP challenge to receive our ACME (Let's encrypt) certificate
  # https://nixos.org/manual/nixos/stable/#module-security-acme-nginx
  security.acme.acceptTerms = true;
  security.acme.email = "acme+example@gmail.com";
  services.nginx = {
    enable = true;
    virtualHosts = {
      "quassel.example.com" = {
        forceSSL = true;
        enableACME = true;
        locations."/" = { root = "/var/www"; };
      };
    };
  };

  # open the ports for HTTP & HTTPS
  networking.firewall.allowedTCPPorts = [ 80 443 ];

  # Create a new group `acme` and set the group of the ACME daemon to run as it.
  # We also allow any user in the `acme` group to access the certificate & key
  users.groups = { acme = { }; };
  security.acme.certs."quassel.example.com".allowKeysForGroup = true;
  security.acme.certs."quassel.example.com".group = "acme";
}

With the above module imported; the ACME daemon will perform the HTTP challenge to prove ownership of the FQDN quassel.example.com and receive a TLS certificate & key.

Quassel Core

Luckily there’s already a Quassel NixOS module that does most of the heavy lifting.

I simply configure it by forcing SSL and setting the certificate material to the one downloaded by the ACME daemon above.

{ config, pkgs, ... }: {

  # The quassel module will create a default user `quassel`
  # Add quassel to the acme group so that it can access the certificate
  users.groups.acme.members = [ "quassel" ];

  services.quassel = {
    enable = true;
    requireSSL = true;
    # set the certificate material to that downloaded by the HTTP challenge above
    certificateFile =
      "${config.security.acme.certs."quassel.example.com".directory}/full.pem";
    # Listen on the public interface
    interfaces = [ "0.0.0.0" ];
  };

  # make sure the quassel default port is open on the firewall
  networking.firewall.allowedTCPPorts = [ 4242 ];
}

Voila!

Now I just need to figure out a nice view setup for my Quassel client to look pretty. Hopefully you find this guide informational and it helps you also join the IRC NixOS community.