10 cfg = config.services.tomcat;
16 maintainers = with lib.maintainers; [
26 enable = lib.mkEnableOption "Apache Tomcat";
28 package = lib.mkPackageOption pkgs "tomcat9" {
33 type = lib.types.port;
36 The TCP port Tomcat should listen on.
40 purifyOnStart = lib.mkOption {
41 type = lib.types.bool;
44 On startup, the `baseDir` directory is populated with various files,
45 subdirectories and symlinks. If this option is enabled, these items
46 (except for the `logs` and `work` subdirectories) are first removed.
47 This prevents interference from remainders of an old configuration
48 (libraries, webapps, etc.), so it's recommended to enable this option.
52 baseDir = lib.mkOption {
53 type = lib.types.path;
54 default = "/var/tomcat";
56 Location where Tomcat stores configuration files, web applications
57 and logfiles. Note that it is partially cleared on each service startup
58 if `purifyOnStart` is enabled.
62 logDirs = lib.mkOption {
64 type = lib.types.listOf lib.types.path;
65 description = "Directories to create in baseDir/logs/";
68 extraConfigFiles = lib.mkOption {
70 type = lib.types.listOf lib.types.path;
71 description = "Extra configuration files to pull into the tomcat conf directory";
74 extraEnvironment = lib.mkOption {
75 type = lib.types.listOf lib.types.str;
77 example = [ "ENVIRONMENT=production" ];
78 description = "Environment Variables to pass to the tomcat service";
81 extraGroups = lib.mkOption {
83 type = lib.types.listOf lib.types.str;
84 example = [ "users" ];
85 description = "Defines extra groups to which the tomcat user belongs.";
91 description = "User account under which Apache Tomcat runs.";
94 group = lib.mkOption {
97 description = "Group account under which Apache Tomcat runs.";
100 javaOpts = lib.mkOption {
101 type = lib.types.either (lib.types.listOf lib.types.str) lib.types.str;
103 description = "Parameters to pass to the Java Virtual Machine which spawns Apache Tomcat";
106 catalinaOpts = lib.mkOption {
107 type = lib.types.either (lib.types.listOf lib.types.str) lib.types.str;
109 description = "Parameters to pass to the Java Virtual Machine which spawns the Catalina servlet container";
112 sharedLibs = lib.mkOption {
113 type = lib.types.listOf lib.types.str;
115 description = "List containing JAR files or directories with JAR files which are libraries shared by the web applications";
118 serverXml = lib.mkOption {
119 type = lib.types.lines;
122 Verbatim server.xml configuration.
123 This is mutually exclusive with the virtualHosts options.
127 commonLibs = lib.mkOption {
128 type = lib.types.listOf lib.types.str;
130 description = "List containing JAR files or directories with JAR files which are libraries shared by the web applications and the servlet container";
133 webapps = lib.mkOption {
134 type = lib.types.listOf lib.types.path;
135 default = [ tomcat.webapps ];
136 defaultText = lib.literalExpression "[ config.services.tomcat.package.webapps ]";
137 description = "List containing WAR files or directories with WAR files which are web applications to be deployed on Tomcat";
140 virtualHosts = lib.mkOption {
141 type = lib.types.listOf (
142 lib.types.submodule {
144 name = lib.mkOption {
145 type = lib.types.str;
146 description = "name of the virtualhost";
148 aliases = lib.mkOption {
149 type = lib.types.listOf lib.types.str;
150 description = "aliases of the virtualhost";
153 webapps = lib.mkOption {
154 type = lib.types.listOf lib.types.path;
156 List containing web application WAR files and/or directories containing
157 web applications and configuration files for the virtual host.
165 description = "List consisting of a virtual host name and a list of web applications to deploy on each virtual host";
168 logPerVirtualHost = lib.mkOption {
169 type = lib.types.bool;
171 description = "Whether to enable logging per virtual host.";
174 jdk = lib.mkPackageOption pkgs "jdk" { };
177 enable = lib.mkEnableOption "Apache Axis2 container";
179 services = lib.mkOption {
181 type = lib.types.listOf lib.types.str;
182 description = "List containing AAR files or directories with AAR files which are web services to be deployed on Axis2";
188 ###### implementation
190 config = lib.mkIf config.services.tomcat.enable {
192 users.groups.tomcat.gid = config.ids.gids.tomcat;
194 users.users.tomcat = {
195 uid = config.ids.uids.tomcat;
196 description = "Tomcat user";
197 home = "/homeless-shelter";
199 extraGroups = cfg.extraGroups;
202 systemd.services.tomcat = {
203 description = "Apache Tomcat server";
204 wantedBy = [ "multi-user.target" ];
205 after = [ "network.target" ];
208 ${lib.optionalString cfg.purifyOnStart ''
209 # Delete most directories/symlinks we create from the existing base directory,
210 # to get rid of remainders of an old configuration.
211 # The list of directories to delete is taken from the "mkdir" command below,
212 # excluding "logs" (because logs are valuable) and "work" (because normally
213 # session files are there), and additionally including "bin".
214 rm -rf ${cfg.baseDir}/{conf,virtualhosts,temp,lib,shared/lib,webapps,bin}
217 # Create the base directory
219 ${cfg.baseDir}/{conf,virtualhosts,logs,temp,lib,shared/lib,webapps,work}
220 chown ${cfg.user}:${cfg.group} \
221 ${cfg.baseDir}/{conf,virtualhosts,logs,temp,lib,shared/lib,webapps,work}
223 # Create a symlink to the bin directory of the tomcat component
224 ln -sfn ${tomcat}/bin ${cfg.baseDir}/bin
226 # Symlink the config files in the conf/ directory (except for catalina.properties and server.xml)
227 for i in $(ls ${tomcat}/conf | grep -v catalina.properties | grep -v server.xml); do
228 ln -sfn ${tomcat}/conf/$i ${cfg.baseDir}/conf/`basename $i`
231 ${lib.optionalString (cfg.extraConfigFiles != [ ]) ''
232 for i in ${toString cfg.extraConfigFiles}; do
233 ln -sfn $i ${cfg.baseDir}/conf/`basename $i`
237 # Create a modified catalina.properties file
238 # Change all references from CATALINA_HOME to CATALINA_BASE and add support for shared libraries
239 sed -e 's|''${catalina.home}|''${catalina.base}|g' \
240 -e 's|shared.loader=|shared.loader=''${catalina.base}/shared/lib/*.jar|' \
241 ${tomcat}/conf/catalina.properties > ${cfg.baseDir}/conf/catalina.properties
244 if cfg.serverXml != "" then
246 cp -f ${pkgs.writeTextDir "server.xml" cfg.serverXml}/* ${cfg.baseDir}/conf/
250 hostElementForVirtualHost =
253 <Host name="${virtualHost.name}" appBase="virtualhosts/${virtualHost.name}/webapps"
254 unpackWARs="true" autoDeploy="true" xmlValidation="false" xmlNamespaceAware="false">
256 + lib.concatStrings (innerElementsForVirtualHost virtualHost)
260 innerElementsForVirtualHost =
263 <Alias>${alias}</Alias>
264 '') virtualHost.aliases)
265 ++ (lib.optional cfg.logPerVirtualHost ''
266 <Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs/${virtualHost.name}"
267 prefix="${virtualHost.name}_access_log." pattern="combined" resolveHosts="false"/>
269 hostElementsString = lib.concatMapStringsSep "\n" hostElementForVirtualHost cfg.virtualHosts;
270 hostElementsSedString = lib.replaceStrings [ "\n" ] [ "\\\n" ] hostElementsString;
273 # Create a modified server.xml which listens on the given port,
274 # and also includes all virtual hosts.
275 # The host modification must be last here,
276 # else if hostElementsSedString is empty sed gets confused as to what to append
277 sed -e 's/<Connector port="8080"/<Connector port="${toString cfg.port}"/' \
278 -e "/<Engine name=\"Catalina\" defaultHost=\"localhost\">/a\\"${lib.escapeShellArg hostElementsSedString} \
279 ${tomcat}/conf/server.xml > ${cfg.baseDir}/conf/server.xml
282 ${lib.optionalString (cfg.logDirs != [ ]) ''
283 for i in ${toString cfg.logDirs}; do
284 mkdir -p ${cfg.baseDir}/logs/$i
285 chown ${cfg.user}:${cfg.group} ${cfg.baseDir}/logs/$i
288 ${lib.optionalString cfg.logPerVirtualHost (
291 mkdir -p ${cfg.baseDir}/logs/${h.name}
292 chown ${cfg.user}:${cfg.group} ${cfg.baseDir}/logs/${h.name}
297 # Symlink all the given common libs files or paths into the lib/ directory
298 for i in ${tomcat} ${toString cfg.commonLibs}; do
300 # If the given web application is a file, symlink it into the common/lib/ directory
301 ln -sfn $i ${cfg.baseDir}/lib/`basename $i`
303 # If the given web application is a directory, then iterate over the files
304 # in the special purpose directories and symlink them into the tomcat tree
306 for j in $i/lib/*; do
307 ln -sfn $j ${cfg.baseDir}/lib/`basename $j`
312 # Symlink all the given shared libs files or paths into the shared/lib/ directory
313 for i in ${toString cfg.sharedLibs}; do
315 # If the given web application is a file, symlink it into the common/lib/ directory
316 ln -sfn $i ${cfg.baseDir}/shared/lib/`basename $i`
318 # If the given web application is a directory, then iterate over the files
319 # in the special purpose directories and symlink them into the tomcat tree
321 for j in $i/shared/lib/*; do
322 ln -sfn $j ${cfg.baseDir}/shared/lib/`basename $j`
327 # Symlink all the given web applications files or paths into the webapps/ directory
328 for i in ${toString cfg.webapps}; do
330 # If the given web application is a file, symlink it into the webapps/ directory
331 ln -sfn $i ${cfg.baseDir}/webapps/`basename $i`
333 # If the given web application is a directory, then iterate over the files
334 # in the special purpose directories and symlink them into the tomcat tree
336 for j in $i/webapps/*; do
337 ln -sfn $j ${cfg.baseDir}/webapps/`basename $j`
340 # Also symlink the configuration files if they are included
341 if [ -d $i/conf/Catalina ]; then
342 for j in $i/conf/Catalina/*; do
343 mkdir -p ${cfg.baseDir}/conf/Catalina/localhost
344 ln -sfn $j ${cfg.baseDir}/conf/Catalina/localhost/`basename $j`
352 # Create webapps directory for the virtual host
353 mkdir -p ${cfg.baseDir}/virtualhosts/${virtualHost.name}/webapps
356 chown ${cfg.user}:${cfg.group} ${cfg.baseDir}/virtualhosts/${virtualHost.name}/webapps
358 # Symlink all the given web applications files or paths into the webapps/ directory
359 # of this virtual host
360 for i in "${lib.optionalString (virtualHost ? webapps) (toString virtualHost.webapps)}"; do
362 # If the given web application is a file, symlink it into the webapps/ directory
363 ln -sfn $i ${cfg.baseDir}/virtualhosts/${virtualHost.name}/webapps/`basename $i`
365 # If the given web application is a directory, then iterate over the files
366 # in the special purpose directories and symlink them into the tomcat tree
368 for j in $i/webapps/*; do
369 ln -sfn $j ${cfg.baseDir}/virtualhosts/${virtualHost.name}/webapps/`basename $j`
372 # Also symlink the configuration files if they are included
373 if [ -d $i/conf/Catalina ]; then
374 for j in $i/conf/Catalina/*; do
375 mkdir -p ${cfg.baseDir}/conf/Catalina/${virtualHost.name}
376 ln -sfn $j ${cfg.baseDir}/conf/Catalina/${virtualHost.name}/`basename $j`
384 ${lib.optionalString cfg.axis2.enable ''
385 # Copy the Axis2 web application
386 cp -av ${pkgs.axis2}/webapps/axis2 ${cfg.baseDir}/webapps
388 # Turn off addressing, which causes many errors
389 sed -i -e 's%<module ref="addressing"/>%<!-- <module ref="addressing"/> -->%' ${cfg.baseDir}/webapps/axis2/WEB-INF/conf/axis2.xml
391 # Modify permissions on the Axis2 application
392 chown -R ${cfg.user}:${cfg.group} ${cfg.baseDir}/webapps/axis2
394 # Symlink all the given web service files or paths into the webapps/axis2/WEB-INF/services directory
395 for i in ${toString cfg.axis2.services}; do
397 # If the given web service is a file, symlink it into the webapps/axis2/WEB-INF/services
398 ln -sfn $i ${cfg.baseDir}/webapps/axis2/WEB-INF/services/`basename $i`
400 # If the given web application is a directory, then iterate over the files
401 # in the special purpose directories and symlink them into the tomcat tree
403 for j in $i/webapps/axis2/WEB-INF/services/*; do
404 ln -sfn $j ${cfg.baseDir}/webapps/axis2/WEB-INF/services/`basename $j`
407 # Also symlink the configuration files if they are included
408 if [ -d $i/conf/Catalina ]; then
409 for j in $i/conf/Catalina/*; do
410 ln -sfn $j ${cfg.baseDir}/conf/Catalina/localhost/`basename $j`
420 PermissionsStartOnly = true;
421 PIDFile = "/run/tomcat/tomcat.pid";
422 RuntimeDirectory = "tomcat";
425 "CATALINA_BASE=${cfg.baseDir}"
426 "CATALINA_PID=/run/tomcat/tomcat.pid"
427 "JAVA_HOME='${cfg.jdk}'"
428 "JAVA_OPTS='${builtins.toString cfg.javaOpts}'"
429 "CATALINA_OPTS='${builtins.toString cfg.catalinaOpts}'"
430 ] ++ cfg.extraEnvironment;
431 ExecStart = "${tomcat}/bin/startup.sh";
432 ExecStop = "${tomcat}/bin/shutdown.sh";