1{
2 config,
3 lib,
4 pkgs,
5 ...
6}:
7
8let
9 cfg = config.services.kanboard;
10
11 toStringAttrs = lib.mapAttrs (lib.const toString);
12in
13{
14 meta.maintainers = with lib.maintainers; [ yzx9 ];
15
16 options.services.kanboard = {
17 enable = lib.mkEnableOption "Kanboard";
18
19 package = lib.mkPackageOption pkgs "kanboard" { };
20
21 dataDir = lib.mkOption {
22 type = lib.types.str;
23 default = "/var/lib/kanboard";
24 description = "Default data folder for Kanboard.";
25 example = "/mnt/kanboard";
26 };
27
28 user = lib.mkOption {
29 type = lib.types.str;
30 default = "kanboard";
31 description = "User under which Kanboard runs.";
32 };
33
34 group = lib.mkOption {
35 type = lib.types.str;
36 default = "kanboard";
37 description = "Group under which Kanboard runs.";
38 };
39
40 settings = lib.mkOption {
41 type =
42 with lib.types;
43 attrsOf (oneOf [
44 str
45 int
46 bool
47 ]);
48
49 default = { };
50
51 description = ''
52 Customize the default settings, refer to <https://github.com/kanboard/kanboard/blob/main/config.default.php>
53 for details on supported values.
54 '';
55 };
56
57 # Nginx
58 domain = lib.mkOption {
59 type = lib.types.str;
60 default = "kanboard";
61 description = "FQDN for the Kanboard instance.";
62 example = "kanboard.example.org";
63 };
64 nginx = lib.mkOption {
65 type = lib.types.nullOr (
66 lib.types.submodule (import ../web-servers/nginx/vhost-options.nix { inherit config lib; })
67 );
68 default = { };
69 description = ''
70 With this option, you can customize an NGINX virtual host which already
71 has sensible defaults for Kanboard. Set to `{ }` if you do not need any
72 customization for the virtual host. If enabled, then by default, the
73 {option}`serverName` is `''${domain}`. If this is set to null (the
74 default), no NGINX virtual host will be configured.
75 '';
76 example = lib.literalExpression ''
77 {
78 enableACME = true;
79 forceHttps = true;
80 }
81 '';
82 };
83
84 phpfpm.settings = lib.mkOption {
85 type =
86 with lib.types;
87 attrsOf (oneOf [
88 int
89 str
90 bool
91 ]);
92
93 default = { };
94
95 description = ''
96 Options for kanboard's PHPFPM pool.
97 '';
98 };
99 };
100
101 config = lib.mkIf cfg.enable {
102 users = {
103 users = lib.mkIf (cfg.user == "kanboard") {
104 kanboard = {
105 isSystemUser = true;
106 group = cfg.group;
107 home = cfg.dataDir;
108 createHome = true;
109 };
110 };
111
112 groups = lib.mkIf (cfg.group == "kanboard") {
113 kanboard = { };
114 };
115 };
116
117 services.phpfpm.pools.kanboard = {
118 user = cfg.user;
119 group = cfg.group;
120
121 settings = lib.mkMerge [
122 {
123 "pm" = "dynamic";
124 "php_admin_value[error_log]" = "stderr";
125 "php_admin_flag[log_errors]" = true;
126 "listen.owner" = "nginx";
127 "catch_workers_output" = true;
128 "pm.max_children" = "32";
129 "pm.start_servers" = "2";
130 "pm.min_spare_servers" = "2";
131 "pm.max_spare_servers" = "4";
132 "pm.max_requests" = "500";
133 }
134 cfg.phpfpm.settings
135 ];
136
137 phpEnv = lib.mkMerge [
138 { DATA_DIR = cfg.dataDir; }
139 (toStringAttrs cfg.settings)
140 ];
141 };
142
143 services.nginx = lib.mkIf (cfg.nginx != null) {
144 enable = lib.mkDefault true;
145 virtualHosts."${cfg.domain}" = lib.mkMerge [
146 {
147 root = lib.mkForce "${cfg.package}/share/kanboard";
148 locations."/".extraConfig = ''
149 rewrite ^ /index.php;
150 '';
151 locations."~ \\.php$".extraConfig = ''
152 fastcgi_split_path_info ^(.+\.php)(/.+)$;
153 fastcgi_pass unix:${config.services.phpfpm.pools.kanboard.socket};
154 include ${config.services.nginx.package}/conf/fastcgi.conf;
155 include ${config.services.nginx.package}/conf/fastcgi_params;
156 '';
157 locations."~ \\.(js|css|ttf|woff2?|png|jpe?g|svg)$".extraConfig = ''
158 add_header Cache-Control "public, max-age=15778463";
159 add_header X-Content-Type-Options nosniff;
160 add_header X-XSS-Protection "1; mode=block";
161 add_header X-Robots-Tag none;
162 add_header X-Download-Options noopen;
163 add_header X-Permitted-Cross-Domain-Policies none;
164 add_header Referrer-Policy no-referrer;
165 access_log off;
166 '';
167 extraConfig = ''
168 try_files $uri /index.php;
169 '';
170 }
171 cfg.nginx
172 ];
173 };
174 };
175}