{ pkgs, lib, config, ... }: with lib; let backplane-auth = "/etc/nixos/static/backplane-auth.scm"; cert-basedir = "/var/lib/ejabberd/certs"; target-certs = ["key" "cert" "chain" "fullchain"]; cert-origin = hostname: filename: "/var/lib/acme/${hostname}/${filename}.pem"; cert-target = hostname: filename: "${cert-basedir}/${hostname}-${filename}.pem"; move-server-certs = hostnames: let move-server-cert = hostname: map (filename: '' ensure_exists ${cert-origin hostname filename} cp -L ${cert-origin hostname filename} ${cert-target hostname filename} '') target-certs; in pkgs.writeShellScript "move-server-certs" '' function ensure_exists() { FILENAME=$1 if [ ! -e $FILENAME ]; then echo "file does not exist: $FILENAME" exit 1 fi } if [ -d ${cert-basedir} ]; then mkdir ${cert-basedir} fi ${concatStringsSep "\n" (concatMap move-server-cert hostnames)} chown -R ${config.services.ejabberd.user}:${config.services.ejabberd.group} ${cert-basedir} exit 0 ''; remove-server-certs = pkgs.writeShellScript "ejabberd-rm-combined-certs" '' rm ${cert-basedir}/*.pem ''; in { config = { security.acme.certs."fudo.im".email = "admin@fudo.org"; security.acme.certs."backplane.fudo.org".email = "admin@fudo.org"; systemd.services = { ejabberd-generate-certs = { enable = true; description = "Generate required SSL certs for ejabberd."; wantedBy = [ "ejabberd.service" ]; after = [ "acme-backplane.fudo.org.service" "acme-fudo.im.service" ]; serviceConfig = { Type = "oneshot"; ExecStart = "${move-server-certs ["fudo.im" "backplane.fudo.org"]}"; RemainAfterExit = true; ExecStop = remove-server-certs; StandardOutput = "journal"; }; }; ejabberd = { requires = [ "ejabberd-generate-certs.service" ]; environment = { FUDO_HOST_PASSWD_FILE = "/srv/jabber/secret/hosts-passwd.scm"; FUDO_SERVICE_PASSWD_FILE = "/srv/jabber/secret/services-passwd.scm"; }; }; }; services = { nginx = { virtualHosts = { "backplane.fudo.org" = { enableACME = true; }; "fudo.im" = { enableACME = true; }; }; }; ejabberd = { enable = true; configFile = pkgs.writeText "ejabberd-config.yml" (builtins.toJSON { loglevel = 4; access_rules = { c2s = { allow = "all"; }; announce = { allow = "admin"; }; configure = { allow = "admin"; }; pubsub_createnode = { allow = "local"; }; }; acl = { admin = { user = [ "niten@fudo.org" ]; }; }; hosts = [ "fudo.im" "backplane.fudo.org" ]; listen = [ { port = 5222; module = "ejabberd_c2s"; ip = "0.0.0.0"; starttls = true; starttls_required = true; } ]; certfiles = concatMap (hostname: map (filename: cert-target hostname filename) target-certs) ["fudo.im" "backplane.fudo.org"]; host_config = { "fudo.im" = { auth_method = "ldap"; ldap_servers = ["auth.fudo.org"]; ldap_port = 389; ldap_rootdn = "cn=jabber,dc=fudo,dc=org"; ldap_password = fileContents /srv/jabber/secret/ldap.passwd; ldap_base = "ou=members,dc=fudo,dc=org"; ldap_filter = "(objectClass=posixAccount)"; ldap_uids = { uid = "%u"; }; modules = { mod_adhoc = {}; mod_announce = {}; mod_avatar = {}; mod_blocking = {}; mod_caps = {}; mod_carboncopy = {}; mod_client_state = {}; mod_configure = {}; mod_disco = {}; mod_fail2ban = {}; mod_last = {}; mod_offline = { access_max_user_messages = 5000; }; mod_ping = {}; mod_privacy = {}; mod_private = {}; mod_pubsub = { access_createnode = "pubsub_createnode"; ignore_pep_from_offline = true; last_item_cache = false; plugins = [ "flat" "pep" ]; }; mod_roster = {}; mod_stream_mgmt = {}; mod_time = {}; mod_vcard = { search = false; }; mod_vcard_xupdate = {}; mod_version = {}; }; }; "backplane.fudo.org" = { auth_method = "external"; extauth_program = "${pkgs.guile}/bin/guile -s ${backplane-auth}"; extauth_pool_size = 3; auth_use_cache = true; modules = { mod_adhoc = {}; mod_caps = {}; mod_carboncopy = {}; mod_client_state = {}; mod_configure = {}; mod_disco = {}; mod_fail2ban = {}; mod_last = {}; mod_offline = { access_max_user_messages = 5000; }; mod_ping = {}; mod_pubsub = { access_createnode = "pubsub_createnode"; ignore_pep_from_offline = true; last_item_cache = false; plugins = [ "flat" "pep" ]; }; mod_roster = {}; mod_stream_mgmt = {}; mod_time = {}; mod_version = {}; }; }; }; }); }; }; }; }