Self-host your own digital island
1{ pkgs, config, lib, ... }:
2
3with lib;
4let
5 cfg = config.eilean;
6 domain = config.networking.domain;
7 passwdDir = "/var/lib/radicale/users";
8 passwdFile = "${passwdDir}/passwd";
9 userOps = { name, ... }: {
10 options = {
11 name = mkOption {
12 type = types.str;
13 readOnly = true;
14 default = name;
15 };
16 passwordFile = mkOption {
17 type = types.nullOr types.str;
18 };
19 };
20 };
21in {
22 options.eilean.radicale = {
23 enable = mkEnableOption "radicale";
24 users = mkOption {
25 type = with types; attrsOf (submodule userOps);
26 default = { };
27 };
28 };
29
30 config = mkIf cfg.radicale.enable {
31 services.radicale = {
32 enable = true;
33 settings = {
34 server = {
35 hosts = [ "0.0.0.0:5232" ];
36 };
37 auth = {
38 type = "htpasswd";
39 htpasswd_filename = passwdFile;
40 htpasswd_encryption = "bcrypt";
41 };
42 storage = {
43 filesystem_folder = "/var/lib/radicale/collections";
44 };
45 };
46 };
47
48 systemd.services.radicale = {
49 serviceConfig.ReadWritePaths = [ "/var/lib/radicale" ];
50 preStart =''
51 if (! test -d "${passwdDir}"); then
52 mkdir "${passwdDir}"
53 chmod 755 "${passwdDir}"
54 fi
55
56 umask 077
57
58 cat <<EOF > ${passwdFile}
59
60 ${lib.concatStringsSep "\n" (lib.mapAttrsToList (name: value:
61 "$(${pkgs.apacheHttpd}/bin/htpasswd -nbB \"${name}\" \"$(head -n 2 ${value.passwordFile})\")"
62 ) cfg.radicale.users)}
63 EOF
64 '';
65 };
66
67 services.nginx = {
68 enable = true;
69 recommendedProxySettings = true;
70 virtualHosts = {
71 "cal.${domain}" = {
72 forceSSL = true;
73 enableACME = true;
74 locations."/" = {
75 proxyPass = "http://localhost:5232";
76 };
77 };
78 };
79 };
80
81 eilean.dns.enable = true;
82 eilean.services.dns.zones.${domain}.records = [{
83 name = "cal";
84 type = "CNAME";
85 data = "vps";
86 }];
87 };
88}