12 KiB
Tomcat
Installs and configures Apache Tomcat on Debian/Ubuntu systems. The
Tomcat version is selected automatically based on the Ubuntu release (7
on Trusty, 8 on Bionic, 10 on Noble) or can be pinned explicitly. The
role manages packages, the systemd unit, JVM options,
server.xml, catalina.properties, logging, the
optional Manager web application, JMX, and SSL/TLS certificates issued
by either Let’s Encrypt (via the letsencrypt-acme-sh-client
role) or a private CA (via the mkcert role).
Requirements
- The
openjdkrole must be applied before this one (declared as a dependency inmeta/main.yml). - Ubuntu Focal (20.04), Jammy (22.04), or Noble (24.04). Bionic (18.04) is supported but reaches EOL.
- For SSL with Let’s Encrypt: the
letsencrypt-acme-sh-clientrole. - For SSL with a private CA: the
mkcertrole.
Role Variables
Tomcat version
The version is detected automatically from the Ubuntu release. Override with:
# Pin a specific major version regardless of the OS release
tomcat_fixed_version: 9Packages and service
# Package installation state (present / latest / absent)
tomcat_pkg_state: present
# Whether the service should be enabled and started
tomcat_service_enabled: true
# Use a custom systemd unit (true on Ubuntu >= 18.04)
tomcat_use_systemd_unit: true
# Enable systemd security hardening directives in the unit file
tomcat_systemd_security_enhanced: falseJVM options
tomcat_min_heap_size: 2048m
tomcat_heap_size: '{{ tomcat_min_heap_size }}'
tomcat_permgen_size: 512m # used only with JDK <= 7
tomcat_file_encoding: 'UTF-8'
# Base JVM memory flags (override to add extra flags)
tomcat_java_opts: "-Xms{{ tomcat_min_heap_size }} -Xmx{{ tomcat_heap_size }}"
# Extra options appended to JAVA_OPTS
tomcat_other_java_opts: ""
# Outbound HTTP/HTTPS proxy for Tomcat's own connections
tomcat_proxy_enabled: false
tomcat_proxy_http_host: 'localhost'
tomcat_proxy_http_port: '3128'
tomcat_proxy_https_host: '{{ tomcat_proxy_http_host }}'
tomcat_proxy_https_port: '{{ tomcat_proxy_http_port }}'Connector thread pool (Executor)
A single named <Executor>
(tomcatThreadPool) is shared by all active connectors
(HTTP, HTTPS, or both).
tomcat_max_threads: 200
tomcat_executor_min_spare_threads: 10
# Maximum length of the pending-connection queue when all threads are busy
tomcat_executor_accept_count: 100
# Maximum depth of the internal executor work queue
# tomcat_max_queue_size: 32767 # default shown; set in host/group vars if neededHTTP connector
# Enable the plain HTTP connector
tomcat_http_enabled: true
# Automatically disable the HTTP connector when the HTTPS connector is active.
# Set to true to force HTTPS-only operation.
tomcat_http_disable_when_ssl: false
tomcat_http_port: 8080
tomcat_http_address: 0.0.0.0
# Timeouts (milliseconds)
tomcat_connection_timeout: 20000 # time to receive the request URI line
tomcat_upload_timeout: 300000 # maximum time for a request body upload
# Request size limits
tomcat_max_post_size: 1000000 # bytes; -1 to disable
tomcat_max_http_header_size: 8192 # bytesAJP connector
Disabled by default. Enable when Tomcat is fronted by Apache httpd
via mod_jk or mod_proxy_ajp.
tomcat_ajp_enabled: false
tomcat_ajp_port: 8009
tomcat_ajp_address: 127.0.0.1Reverse proxy integration
When Tomcat sits behind a reverse proxy, set these so that Tomcat
reports the correct public hostname and port in redirects and
request.getServerName().
tomcat_reverse_proxy_name_enabled: false
tomcat_reverse_proxy_name: '{{ ansible_fqdn }}'
tomcat_reverse_proxy_port: '{{ http_port | default(80) }}'
# Set to true to log the real client IP from X-Forwarded-For instead of the
# proxy address. The RemoteIpValve is activated automatically when AJP is on.
tomcat_direct_access: falsePaths
These are derived from tomcat_version and rarely need to
be overridden.
tomcat_catalina_home_dir: '/usr/share/tomcat{{ tomcat_version }}'
tomcat_catalina_base_dir: '/var/lib/tomcat{{ tomcat_version }}'
tomcat_conf_dir: '/etc/tomcat{{ tomcat_version }}'
tomcat_webapps_dir: '{{ tomcat_catalina_base_dir }}/webapps'
tomcat_logdir: '/var/log/tomcat{{ tomcat_version }}'
tomcat_tmp_dir: '{{ tomcat_catalina_base_dir }}/tmp/tomcat'
# Override only if you need a custom CATALINA_TMPDIR
# catalina_tmp_directory: /some/other/path
tomcat_enable_catalina_shared_loader: trueWebapps
tomcat_webapps_autodeploy: false
tomcat_webapps_unpack: falseShutdown port
A long-standing Tomcat bug can kill the process after ~50 days when the shutdown port is open. It is disabled by default.
tomcat_shutdown_port: -1 # -1 disables the shutdown port entirely
# tomcat_shutdown_port: 8005 # uncomment to re-enable
tomcat_shutdown_pwd: "<random>" # generated via lookup('password', …)Logging
tomcat_use_log4j: true
tomcat_install_the_log4j_properties: true
tomcat_log_level: INFO
tomcat_log_logger: CATALINA
tomcat_log_rotation_threshold: "ALL"
tomcat_log_max_file_size: "100MB"
tomcat_retain_old_logs: 30
tomcat_access_log_enabled: true
tomcat_access_log_rotation_freq: "daily"
# Forward logs to a Logstash / ELK stack
tomcat_send_to_logstash: false
tomcat_logstash_collector_host: logstash
tomcat_logstash_collector_socketappender_port: 4560
tomcat_logstash_collector_socketappender_reconndelay: 10000
# Use 'LOGSTASH' only to suppress local log files entirely
tomcat_logstash_logger: 'CATALINA, LOGSTASH'Manager web application
tomcat_install_admin: false
tomcat_manager_gui_user_enabled: true
tomcat_manager_gui_user: guiadmin
# tomcat_manager_gui_pwd: <vault>
tomcat_manager_script_user_enabled: false
tomcat_manager_script_user: scriptadmin
# tomcat_manager_script_pwd: <vault>
tomcat_manager_jmx_user_enabled: false
tomcat_manager_jmx_user: jmxadmin
# tomcat_manager_jmx_pwd: <vault>
tomcat_manager_status_user_enabled: false
tomcat_manager_status_user: statusadmin
# tomcat_manager_status_pwd: <vault>JMX
tomcat_jmx_enabled: false
tomcat_jmx_port: 8082
tomcat_jmx_auth_enabled: false
tomcat_jmx_use_ssl: false
tomcat_jmx_disable_additional_ports: true # requires JDK >= 7.0.25
tomcat_jmx_localhost_only: false
# Required when tomcat_jmx_auth_enabled is true (store in vault)
# tomcat_jmx_monitorpass: <vault>
# tomcat_jmx_controlpass: <vault>Remote debugging
tomcat_enable_remote_debugging: false
tomcat_remote_debugging_host: '0.0.0.0'
tomcat_remote_debugging_port: ':8100'JavaMelody monitoring
tomcat_javamelody: false
tomcat_javamelody_version: 1.82.0JDBC drivers
tomcat_install_jdbc: false
tomcat_install_pg_jdbc: '{{ tomcat_install_jdbc }}' # PostgreSQL JDBC driverSSL/TLS certificates
Setting tomcat_ssl_enabled: true does three things:
- Creates
tomcat_ssl_cert_dirand copies the certificate and private key into it with permissions readable only by thetomcatgroup (0640, ownedroot:{{ tomcat_user }}). - Adds an HTTPS connector to
server.xml. On Tomcat 9+ this usesHttp11NioProtocolwith a nested<SSLHostConfig>element so that PEM files are read natively without APR. On Tomcat 7/8 it usesHttp11AprProtocolwith inlineSSLCertificateFile/SSLCertificateKeyFileattributes. - For Let’s Encrypt: installs a renewal hook script at
{{ tomcat_letsencrypt_hooks_dir }}/tomcat. The script is called byacme.sh(via/usr/local/bin/acme-services-hook) on every successful renewal. It compares each source file against its destination usingcmpand restarts Tomcat only when at least one file has changed.
An Ansible handler listening on letsencrypt cert renewed
is also provided. Any task in the same play can trigger a key copy and
Tomcat restart by notifying that event:
- name: Install the certificate
...
notify: letsencrypt cert renewedCommon SSL variables
tomcat_ssl_enabled: false
# Certificate source: 'letsencrypt' or 'mkcert'
tomcat_ssl_cert_source: letsencrypt
# Directory on the managed host where Tomcat reads the cert and key.
# Created with mode 0750, owned root:{{ tomcat_user }}.
tomcat_ssl_cert_dir: '{{ tomcat_conf_dir }}/ssl'
tomcat_ssl_port: 8443
# TLS protocol filter in Tomcat '+' syntax.
# Tomcat 9+ (SSLHostConfig): TLSv1.2+TLSv1.3
# Tomcat 7/8 (APR SSLProtocol): TLSv1+TLSv1.1+TLSv1.2
tomcat_ssl_protocols: 'TLSv1.2+TLSv1.3'
tomcat_ssl_max_parameter_count: 1000
# Destination filenames inside tomcat_ssl_cert_dir
tomcat_ssl_fullchain_filename: 'fullchain.pem'
tomcat_ssl_key_filename: 'privkey.pem'Let’s Encrypt (letsencrypt-acme-sh-client role)
When tomcat_ssl_cert_source: letsencrypt, the role reads
certificates from the directory installed by the
letsencrypt-acme-sh-client role.
tomcat_ssl_letsencrypt_cert_dir resolves automatically from
letsencrypt_acme_sh_certificates_install_path when both
roles run in the same play. The fallback value matches that role’s
documented default.
# Resolved from letsencrypt_acme_sh_certificates_install_path when available.
# Override only if the letsencrypt role is not part of the same play.
tomcat_ssl_letsencrypt_cert_dir: "/var/lib/acme/live/{{ ansible_fqdn }}"
# Source filenames as produced by the letsencrypt-acme-sh-client role
# (no file extension by design)
tomcat_ssl_letsencrypt_fullchain_src_filename: 'fullchain'
tomcat_ssl_letsencrypt_key_src_filename: 'privkey'
# Hook directory — resolved from letsencrypt_acme_services_scripts_dir when available.
tomcat_letsencrypt_hooks_dir: '/usr/lib/acme/hooks'Private CA (mkcert role)
When tomcat_ssl_cert_source: mkcert, the role copies PEM
files generated by the mkcert role. Point
tomcat_ssl_mkcert_cert_dir at the directory containing the
certificate files for the relevant domain.
tomcat_ssl_mkcert_domain: '{{ ansible_fqdn }}'
tomcat_ssl_mkcert_cert_dir: '/srv/mkcert-ca/certs/{{ tomcat_ssl_mkcert_domain }}'
# Source filenames in tomcat_ssl_mkcert_cert_dir
tomcat_ssl_mkcert_fullchain_src_filename: 'fullchain.pem'
tomcat_ssl_mkcert_key_src_filename: 'privkey.pem'Example playbooks
HTTPS only with Let’s Encrypt
- hosts: appservers
roles:
- openjdk
- letsencrypt-acme-sh-client
- tomcat
vars:
letsencrypt_acme_install: true
letsencrypt_acme_sh_domains:
- domain: '{{ ansible_fqdn }}'
standalone: false
tomcat_ssl_enabled: true
tomcat_ssl_cert_source: letsencrypt
tomcat_http_disable_when_ssl: trueHTTP and HTTPS with a private CA
- hosts: devservers
roles:
- openjdk
- mkcert
- tomcat
vars:
tomcat_ssl_enabled: true
tomcat_ssl_cert_source: mkcert
tomcat_ssl_mkcert_cert_dir: '/srv/mkcert-ca/certs/{{ ansible_fqdn }}'HTTP only behind a reverse proxy
- hosts: appservers
roles:
- openjdk
- tomcat
vars:
tomcat_reverse_proxy_name_enabled: true
tomcat_ajp_enabled: true
tomcat_http_enabled: falseDependencies
openjdkrole (declared inmeta/main.yml), sourced fromgitea-s2i2s.isti.cnr.it/ISTI-ansible-roles/ansible-role-openjdk.letsencrypt-acme-sh-clientrole — optional, required whentomcat_ssl_cert_source: letsencrypt.mkcertrole — optional, required whentomcat_ssl_cert_source: mkcert.
License
EUPL-1.2
Author Information
Andrea Dell’Amico, andrea.dellamico@isti.cnr.it ISTI-CNR