1{ config, lib, pkgs, ... }:
2
3with lib;
4
5let
6
7 cfg = config.services.confluence;
8
9 pkg = cfg.package.override (optionalAttrs cfg.sso.enable {
10 enableSSO = cfg.sso.enable;
11 });
12
13 crowdProperties = pkgs.writeText "crowd.properties" ''
14 application.name ${cfg.sso.applicationName}
15 application.password ${if cfg.sso.applicationPassword != null then cfg.sso.applicationPassword else "@NIXOS_CONFLUENCE_CROWD_SSO_PWD@"}
16 application.login.url ${cfg.sso.crowd}/console/
17
18 crowd.server.url ${cfg.sso.crowd}/services/
19 crowd.base.url ${cfg.sso.crowd}/
20
21 session.isauthenticated session.isauthenticated
22 session.tokenkey session.tokenkey
23 session.validationinterval ${toString cfg.sso.validationInterval}
24 session.lastvalidation session.lastvalidation
25 '';
26
27in
28
29{
30 options = {
31 services.confluence = {
32 enable = mkEnableOption "Atlassian Confluence service";
33
34 user = mkOption {
35 type = types.str;
36 default = "confluence";
37 description = "User which runs confluence.";
38 };
39
40 group = mkOption {
41 type = types.str;
42 default = "confluence";
43 description = "Group which runs confluence.";
44 };
45
46 home = mkOption {
47 type = types.str;
48 default = "/var/lib/confluence";
49 description = "Home directory of the confluence instance.";
50 };
51
52 listenAddress = mkOption {
53 type = types.str;
54 default = "127.0.0.1";
55 description = "Address to listen on.";
56 };
57
58 listenPort = mkOption {
59 type = types.port;
60 default = 8090;
61 description = "Port to listen on.";
62 };
63
64 catalinaOptions = mkOption {
65 type = types.listOf types.str;
66 default = [];
67 example = [ "-Xms1024m" "-Xmx2048m" "-Dconfluence.disable.peopledirectory.all=true" ];
68 description = "Java options to pass to catalina/tomcat.";
69 };
70
71 proxy = {
72 enable = mkEnableOption "proxy support";
73
74 name = mkOption {
75 type = types.str;
76 example = "confluence.example.com";
77 description = "Virtual hostname at the proxy";
78 };
79
80 port = mkOption {
81 type = types.port;
82 default = 443;
83 example = 80;
84 description = "Port used at the proxy";
85 };
86
87 scheme = mkOption {
88 type = types.str;
89 default = "https";
90 example = "http";
91 description = "Protocol used at the proxy.";
92 };
93 };
94
95 sso = {
96 enable = mkEnableOption "SSO with Atlassian Crowd";
97
98 crowd = mkOption {
99 type = types.str;
100 example = "http://localhost:8095/crowd";
101 description = "Crowd Base URL without trailing slash";
102 };
103
104 applicationName = mkOption {
105 type = types.str;
106 example = "jira";
107 description = "Exact name of this Confluence instance in Crowd";
108 };
109
110 applicationPassword = mkOption {
111 type = types.nullOr types.str;
112 default = null;
113 description = "Application password of this Confluence instance in Crowd";
114 };
115
116 applicationPasswordFile = mkOption {
117 type = types.nullOr types.str;
118 default = null;
119 description = "Path to the application password for Crowd of Confluence.";
120 };
121
122 validationInterval = mkOption {
123 type = types.int;
124 default = 2;
125 example = 0;
126 description = ''
127 Set to 0, if you want authentication checks to occur on each
128 request. Otherwise set to the number of minutes between request
129 to validate if the user is logged in or out of the Crowd SSO
130 server. Setting this value to 1 or higher will increase the
131 performance of Crowd's integration.
132 '';
133 };
134 };
135
136 package = mkPackageOption pkgs "atlassian-confluence" { };
137
138 jrePackage = mkPackageOption pkgs "oraclejre8" {
139 extraDescription = ''
140 ::: {.note }
141 Atlassian only supports the Oracle JRE (JRASERVER-46152).
142 :::
143 '';
144 };
145 };
146 };
147
148 config = mkIf cfg.enable {
149 users.users.${cfg.user} = {
150 isSystemUser = true;
151 group = cfg.group;
152 };
153
154 assertions = [
155 { assertion = cfg.sso.enable -> ((cfg.sso.applicationPassword == null) != (cfg.sso.applicationPasswordFile));
156 message = "Please set either applicationPassword or applicationPasswordFile";
157 }
158 ];
159
160 warnings = mkIf (cfg.sso.enable && cfg.sso.applicationPassword != null) [
161 "Using `services.confluence.sso.applicationPassword` is deprecated! Use `applicationPasswordFile` instead!"
162 ];
163
164 users.groups.${cfg.group} = {};
165
166 systemd.tmpfiles.rules = [
167 "d '${cfg.home}' - ${cfg.user} - - -"
168 "d /run/confluence - - - - -"
169
170 "L+ /run/confluence/home - - - - ${cfg.home}"
171 "L+ /run/confluence/logs - - - - ${cfg.home}/logs"
172 "L+ /run/confluence/temp - - - - ${cfg.home}/temp"
173 "L+ /run/confluence/work - - - - ${cfg.home}/work"
174 "L+ /run/confluence/server.xml - - - - ${cfg.home}/server.xml"
175 ];
176
177 systemd.services.confluence = {
178 description = "Atlassian Confluence";
179
180 wantedBy = [ "multi-user.target" ];
181 requires = [ "postgresql.service" ];
182 after = [ "postgresql.service" ];
183
184 path = [ cfg.jrePackage pkgs.bash ];
185
186 environment = {
187 CONF_USER = cfg.user;
188 JAVA_HOME = "${cfg.jrePackage}";
189 CATALINA_OPTS = concatStringsSep " " cfg.catalinaOptions;
190 JAVA_OPTS = mkIf cfg.sso.enable "-Dcrowd.properties=${cfg.home}/crowd.properties";
191 };
192
193 preStart = ''
194 mkdir -p ${cfg.home}/{logs,work,temp,deploy}
195
196 sed -e 's,port="8090",port="${toString cfg.listenPort}" address="${cfg.listenAddress}",' \
197 '' + (lib.optionalString cfg.proxy.enable ''
198 -e 's,protocol="org.apache.coyote.http11.Http11NioProtocol",protocol="org.apache.coyote.http11.Http11NioProtocol" proxyName="${cfg.proxy.name}" proxyPort="${toString cfg.proxy.port}" scheme="${cfg.proxy.scheme}",' \
199 '') + ''
200 ${pkg}/conf/server.xml.dist > ${cfg.home}/server.xml
201
202 ${optionalString cfg.sso.enable ''
203 install -m660 ${crowdProperties} ${cfg.home}/crowd.properties
204 ${optionalString (cfg.sso.applicationPasswordFile != null) ''
205 ${pkgs.replace-secret}/bin/replace-secret \
206 '@NIXOS_CONFLUENCE_CROWD_SSO_PWD@' \
207 ${cfg.sso.applicationPasswordFile} \
208 ${cfg.home}/crowd.properties
209 ''}
210 ''}
211 '';
212
213 serviceConfig = {
214 User = cfg.user;
215 Group = cfg.group;
216 PrivateTmp = true;
217 Restart = "on-failure";
218 RestartSec = "10";
219 ExecStart = "${pkg}/bin/start-confluence.sh -fg";
220 ExecStop = "${pkg}/bin/stop-confluence.sh";
221 };
222 };
223 };
224}