Login Logout

Howto Tomcat

Tomcat est un serveur d’applications Java : il rend accessible des pages JSP (moteur Jasper) et des servlets Java (moteur Catalina) via le protocole HTTP (connecteur Coyote) ou AJP (Apache JServ Protocol). On l’utilise en général avec Apache en complément.

Installation

# apt install openjdk-7-jdk tomcat8 tomcat8-user

# /usr/share/tomcat8/bin/version.sh 
Using CATALINA_BASE:   /usr/share/tomcat8
Using CATALINA_HOME:   /usr/share/tomcat8
Using CATALINA_TMPDIR: /usr/share/tomcat8/temp
Using JRE_HOME:        /usr
Using CLASSPATH:       /usr/share/tomcat8/bin/bootstrap.jar:/usr/share/tomcat8/bin/tomcat-juli.jar
Server version: Apache Tomcat/8.0.14 (Debian)
Server built:   Feb 13 2017 09:37:48
Server number:  8.0.14.0
OS Name:        Linux
OS Version:     3.16.0-4-amd64
Architecture:   amd64
JVM Version:    1.7.0_121-b00
JVM Vendor:     Oracle Corporation

Note : on peut également installer Tomcat 7 avec les paquets _tomcat7*_

Configuration

La configuration système de Tomcat, et notamment les paramètres de la JVM, se trouve dans le fichier /etc/default/tomcat8 que l’on adapte ainsi :

# Rare sont les cas ou l'on peut activer le Java security manager
TOMCAT6_SECURITY=no

# Reglages memoire de base (a adapter selon votre quantite de RAM, dans l'exemple on a une seule instance et 4 Go de RAM)
JAVA_OPTS="${JAVA_OPTS} -Xms2g -Xmx2g -XX:NewSize=512m -XX:MaxPermSize=256m -Xss256k"

# Reglages du garbage collector
JAVA_OPTS="${JAVA_OPTS} -XX:+UseConcMarkSweepGC -XX:+CMSIncrementalMode -XX:CMSInitiatingOccupancyFraction=80"

# Compression des adresses 64bits sur 32bits pour gagner en memoire libre
JAVA_OPTS="${JAVA_OPTS} -XX:+UseCompressedOops"

# file limits pour eviter les "too many open files"
ulimit -n 8192

La configuration des options de Tomcat se trouve dans le répertoire /etc/tomcat8/ notamment dans le fichier /etc/tomcat8/server.xml :

<?xml version='1.0' encoding='utf-8'?>

<Server port="8005" shutdown="SHUTDOWN">
  <Listener className="org.apache.catalina.startup.VersionLoggerListener" />
  <Listener className="org.apache.catalina.core.JreMemoryLeakPreventionListener" />
  <Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener" />
  <Listener className="org.apache.catalina.core.ThreadLocalLeakPreventionListener" />
  <GlobalNamingResources>
    <Resource name="UserDatabase" auth="Container"
              type="org.apache.catalina.UserDatabase" description="User database that can be updated and saved"
              factory="org.apache.catalina.users.MemoryUserDatabaseFactory" pathname="conf/tomcat-users.xml" />
  </GlobalNamingResources>
  <Service name="Catalina">
    <Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" URIEncoding="UTF-8" redirectPort="8443" />
    <Engine name="Catalina" defaultHost="localhost">
      <Realm className="org.apache.catalina.realm.LockOutRealm">
        <Realm className="org.apache.catalina.realm.UserDatabaseRealm" resourceName="UserDatabase"/>
      </Realm>
      <Host name="localhost" appBase="webapps" unpackWARs="true" autoDeploy="true">
        <Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
               prefix="localhost_access_log" suffix=".txt" pattern="%h %l %u %t &quot;%r&quot; %s %b" />
      </Host>
    </Engine>
  </Service>
</Server>

On peut ainsi désactiver le déploiement automatique (à chaud) en modifiant :

      <Host name="localhost" appBase="webapps" unpackWARs="true" autoDeploy="false">

Ou encore changer les paramètres du connecteur HTTP (port TCP utilisé, timeout de la connexion) via :

    <Connector port="8765" protocol="HTTP/1.1" connectionTimeout="5000" URIEncoding="UTF-8" redirectPort="8443" />

Arborescence

Les fichiers de Tomcat sont dispersés, voici les répertoires importants :

  • CATALINA_BASE : ${catalina.base} = /var/lib/tomcat8
  • CATALINA_HOME : ${catalina.home} = /usr/share/tomcat8

Le répertoire CATALINA_BASE contient :

/var/lib/tomcat8/
├── conf -> /etc/tomcat8
├── lib
├── logs -> /var/log/tomcat8
├── policy
│   └── catalina.policy
├── webapps (répertoire où l'on peut déposer les servlets)
│   └── ROOT
│       ├── index.html
│       └── META-INF
│           └── context.xml
└── work -> /var/cache/tomcat8

Un élément important concerne les classes Java qui peuvent être déposées à différents endroits. L’ordre de chargement de ces classes (Class Loader) se fait ainsi :

  • /usr/share/tomcat6/lib/ : classes communes à toutes les servlets
  • /var/lib/tomcat8/webapps/foo/WEB-INF/lib/ : classes spécifiques à la servlet foo

Administration

Manager Tomcat

On peut installer le Manager Tomcat, une interface web permettant notamment déployer des servlets Java :

# apt install tomcat8-admin

Il faut ensuite ajouter un utilisateur au rôle manager, dans le fichier /etc/tomcat8/tomcat-users.xml :

<tomcat-users>
  [...]
  <role rolename="manager"/>
  <user username="foo" password="PASSWORD" roles="manager"/>
</tomcat-users>

L’accès au Manager Tomcat se fait sur http://127.0.0.1:8080/manager/html

Instances Tomcat

On peut faire tourner plusieurs instances Tomcat complètement indépendantes, avec leurs propres réglages et en permettant des arrêts/redémarrages d’une instance sans impacter les autres, le tout en mutualisant les binaires.

Installation et configuration d’une instance

Pour cela, on s’appuye sur systemd pour lequel il faut installer la bibliothèque PAM :

# apt install libpam-systemd

Et l’on crée une unité systemd /etc/systemd/user/tomcat.service :

[Unit]
Description=Tomcat %u.
After=network.target

[Service]
WorkingDirectory=%h
Environment="CATALINA_BASE=%h"
EnvironmentFile=%h/conf/env
UMask=0002
ExecStart=/usr/share/tomcat8/bin/catalina.sh run
# Pour Tomcat 7
#ExecStart=/usr/share/tomcat7/bin/catalina.sh run

SyslogIdentifier=tomcat@%u

[Install]
WantedBy=default.target

On peut ensuite créer une instance nommée foo avec un utilisateur dédié :

# mkdir -p /srv/tomcat
# tomcat8-instance-create /srv/tomcat/foo
# useradd -d /srv/tomcat/foo foo
# chown -R app:app /srv/tomcat/foo
# chmod -R u=rwX,g=rX,o= /srv/tomcat/foo
# chmod -R g+ws /srv/tomcat/foo

Créer les variables d’environnement dans /srv/tomcat/foo/conf/env :

# Memory allocation options.
# Xmx Max memory allocated to instance.
# Xms Allocated memory at startup.
# XX:MaxPermSize Memory allocated to internal objects.
JAVA_HOME="/usr/lib/jvm/java-1.7.0-openjdk-amd64"
JAVA_OPTS="${JAVA_OPTS} -server -Xms2g -Xmx2g -XX:NewSize=512m -XX:MaxPermSize=256m -Xss256k"
JAVA_OPTS="${JAVA_OPTS} -XX:+UseConcMarkSweepGC -XX:+CMSIncrementalMode -XX:CMSInitiatingOccupancyFraction=80"
JAVA_OPTS="${JAVA_OPTS} -XX:+UseCompressedOops"
JAVA_OPTS="${JAVA_OPTS} -XX:+UseParNewGC -XX:+CMSPermGenSweepingEnabled -XX:+CMSClassUnloadingEnabled -Xverify:none"

Il reste ensuite à ajuster les ports HTTP et SHUTDOWN dans /srv/tomcat/app/conf/server.xml :

<Server port="SHUTDOWN_PORT" shutdown="SHUTDOWN">
<Connector port="HTTP_PORT" protocol="HTTP/1.1" connectionTimeout="20000" URIEncoding="UTF-8" redirectPort="8443"/>

Enfin, il est nécessaire d’activer la conservation de la session de l’utilisateur :

# loginctl enable-linger foo

Gestion d’une instance

Activation au démarrage de l’instance :

# su - foo
$ systemctl --user enable tomcat

Démarrage de l’instance :

# su - foo
$ systemctl --user start tomcat

Arrêt de l’instance :

# su - foo
$ systemctl --user stop tomcat

Redémarrage de l’instance :

# su - foo
$ systemctl --user restart tomcat

Afficher le statut de l’instance :

# su - foo
$ systemctl --user status -l tomcat

Configuration avec Apache

Nous conseillons d’utiliser Apache comme reverse-proxy HTTP/HTTPS devant Tomcat. Pour cela on conseille d’utiliser le module proxy_http avec le connecteur HTTP de Tomcat. On peut également utiliser le module mod-jk avec le connecteur AJP de Tomcat.

avec proxy_http

# a2enmod proxy_http

Voici un VirtualHost type :

<VirtualHost *:80>
    ServerName www.example.com

    <IfModule mod_proxy_http.c>
        ProxyPass / http://127.0.0.1:8080/
        ProxyPassReverse / http://127.0.0.1:8080/
        <Proxy http://127.0.0.1:8080/>
            Require all granted
        </Proxy>
    </IfModule>
</VirtualHost>

avec mod-jk

# apt install libapache2-mod-jk

Il faut ensuite s’assurer d’avoir activer le connecteur AJP dans le fichier server.xml :

    <Connector port="8009" protocol="AJP/1.3" redirectPort="8443" />

On édite /etc/libapache2-mod-jk/workers.properties pour lister les instances Tomcat concernées :

workers.tomcat_home=/usr/share/tomcat8
workers.java_home=/usr/lib/jvm/default-java
worker.list=ajp13_worker
worker.ajp13_worker.port=8009
worker.ajp13_worker.host=localhost
worker.ajp13_worker.type=ajp13

Voici un VirtualHost type :

<VirtualHost *:80>
    ServerName www.example.com

    # Tout rediriger vers l'instance :
    JkMount /* ajp13_worker

    # Ne pas rediriger une destination spécifique :
    JkUnMount /favicon.ico ajp13_worker
    JkUnMount /documents/* ajp13_worker
</VirtualHost>

Note : les options pour libapache2-mod-jk sont configurables dans le fichier /etc/apache2/mods-available/jk.conf

Monitoring

Nagios

Vérification simple du port HTTP :

$ /usr/lib/nagios/plugins/check_http -H 127.0.0.1 -p 8080

Vérification simple du port AJP :

$ /usr/lib/nagios/plugins/check_tcp -H 127.0.0.1 -p 8009

FAQ

access_log de Tomcat

Tomcat peut générer des journaux d’accès similaires à ceux d’Apache. On configure cela via le fichier server.xml :

<Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"  
       prefix="localhost_access_log." suffix=".txt" pattern="common" resolveHosts="false"/>

Connecteur HTTP

Pour activer la compression GZIP de certains types de fichiers, ajouter les options suivantes dans le connecteur HTTP via le fichier server.xml :

compression="on" compressionMinSize="2048" compressableMimeType="text/html,text/xml,text/plain,text/javascript,application/javascript"

Drivers JDBC

Pour installer le driver JDBC pour MySQL :

# aptitude install libmysql-java
# cd /usr/share/tomcat6/lib/
# ln -s ../../java/mysql-connector-java.jar mysql.jar

Pour installer le driver JDBC pour PostgreSQL :

# aptitude install libpg-java
# cd /usr/share/tomcat6/lib/
# ln -s ../../java/mysql-connector-java.jar mysql.jar

Qu’est-ce que c’est JSVC ? Pourquoi l’utiliser ?

JSVC est un outil permettant d’uniformiser le lancement de “daemon” en JAVA pour tous les systèmes, notamment sous Windows. Sous Linux, il est parfois utilisé, mais son utilisation reste déconseillée vu qu’il existe d’autres outils pour faire cela et que son utilisation ne permet pas une gestion via JMX. Sous Debian, il a été utilisé sous Debian Lenny, mais il n’est plus utilisé dans les versions suivantes.

Tomcat n’écoute pas en IPv4, pourquoi ? Comment le corriger ?

Les versions récentes de Java préfèrent l’IPv6 si elle est présente. Le problème c’est que dans ce cas, il peut arriver que tomcat n’écoute pas en IPv4. Il faut alors modifier les propriétés par défaut en ajoutant ceci aux JAVA_OPTS :

-Djava.net.preferIPv4Stack=true

Problème taille upload

Le vhost doit forcer l’envoi du header Content-Length, il ne le fait pas toujours si le contenu est trop large. Voir https://httpd.apache.org/docs/current/mod/mod_proxy.html#request-bodies pour plus de détails.

SetEnv proxy-sendcl