Tomcat en production

Petit récapitulatif des opérations à réaliser pour la mise en production d'un serveur Tomcat 5.5 ou 6.0 (mise à jour en cours pour Tomcat 7 et 8).

Installation

Machine virtuelle

Il faut installer un JDK récent. Celui d'Oracle devrait convenir, ou éventuellement OpenJDK.

Tomcat

Même sous Linux, on installe Tomcat depuis l'archive téléchargée sur leur site. L'installation par paquet rpm, apt-get ou autre amène parfois des surprises. (cf. forum developpez.net)

Log4J

Je préfère largement Log4J au Java Logging API. Je fais donc le remplacement.

JULI n'est pas terrible, mais il s'est largement amélioré. Par exemple, depuis Tomcat 8, il sait écrire chaque trace sur une seule ligne, et de façon asynchrone. Je le conserve donc, en simplifiant sa configuration.

Script de démarrage

Pour commencer, il peut être pratique de renseigner CATALINA_HOME, pour pouvoir l'utiliser dans la suite du script.

Tomcat est démarré avec son propre user, et surtout pas root. Comme j'utilise un Apache frontal, je n'ai pas besoin d'écouter sur le port 80.

Profile JVM et Mémoire

La JVM se lance avec les options par défaut, ce qui est rarement la meilleure de solutions.

JAVA_OPTS="$JAVA_OPTS -server -Xms512m -Xmx512m"

Pour faire générer un dump de mémoire en cas de OutOfMemoryError :

JAVA_OPTS="$JAVA_OPTS -XX:-HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=$CATALINA_HOME/logs"

Garbage Collector

Il n'y généralement pas d'optimisation a priori du ramasse-miettes. Son paramétrage se fait après diagnostic d'un problème.

En revanche, l'existence de collections explicites dans le code peut être une source de lenteur, il faut donc les désactiver.

JAVA_OPTS="$JAVA_OPTS -XX:+DisableExplicitGC"

JMX

En Java 5, on ajoute la propriété permettant de monitorer avec jConsole ou tout autre client JMX, comme MC4J ou jManage.

JAVA_OPTS="$JAVA_OPTS "-Dcom.sun.management.jmxremote

Si le serveur n'a pas de couche graphique, on va permettre l'accès à distance. Cet accès est sécurisé et nécessite une authentification dont les données sont stockées dans des fichiers properties, avec un fichier qui contient les couples user/password et un fichier qui associe les rôles aux users.

JAVA_OPTS="$JAVA_OPTS -Dcom.sun.management.jmxremote.port=1099 -Dcom.sun.management.jmxremote.rmi.port=1098
                      -Dcom.sun.management.jmxremote.access.file=$CATALINA_HOME/conf/jmx.access
                      -Dcom.sun.management.jmxremote.password.file=$CATALINA_HOME/conf/jmx.password"

Avec Java 6, l'accès JMX local est automatique ouvert, sans avoir à spécifier de variable supplémentaire. Cependant, en l'absence de la variable -Dcom.sun.management.jmxremote, Tomcat n'enregistrera pas ses propres MBeans ; on ne pourra donc monitorer que les données de la JVM, comme l'utilisation de la mémoire, mais pas les datasources ou connecteurs.

En conclusion, à partir de Java 5, on ajoute systématiquement la variable -Dcom.sun.management.jmxremote.

La page JMX/Remote donne des explications plus détaillées sur cet accès.

AWT - Display

Si Tomcat est lancé sur un serveur sans display, des erreurs peuvent se produire au démarrage. Cela est du à l'utilisation de composants AWT, qui, bien que pouvant ne pas être graphiques, essaient de se rattacher à un display.

Pour éviter cette tentative de rattachement, il faut ajouter la variable -Djava.awt.headless :

JAVA_OPTS="$JAVA_OPTS -Djava.awt.headless=true"

Applications fournies

Activer SSL

A partir du moment ou je veux utiliser les applications de gestion, comme le Manager, je passe par du SSL.

Sécurité du Manager

Il faut à la fois créer un user dans tomcat-users.xml et forcer l'utilisation de SSL.

Il vaut mieux stocker la version chiffrée du mot de passe :

> bin/digest.sh -a sha-512 sewatech
sewatech:6f9341ffb9...552c8a0e4
<!-- conf/tomcat-users.xml -->
<role rolename="manager" />
<user username="alexis" password="6f9341ffb9...552c8a0e4" roles="manager-gui" />
<!-- conf/server.xml -->
<Realm className="org.apache.catalina.realm.UserDatabaseRealm" resourceName="UserDatabase" digest="sha-512"/>

Et pour forcer le SSL, on ajouter une user-data-constraint aux contraintes de sécurité existantes dans le fichier WEB-INF/web.xml du manager

 <!-- WEB-INF/web.xml -->
 <security-constraint>
   <web-resource-collection>
     <web-resource-name>HTML Manager interface (for humans)</web-resource-name>
     <url-pattern>/html/*</url-pattern>
   </web-resource-collection>
   <auth-constraint>
      <role-name>manager-gui</role-name>
   </auth-constraint>
   
   <user-data-constraint>
      <transport-guarantee>CONFIDENTIAL</transport-guarantee>
   </user-data-constraint>
   
 </security-constraint>

La même portion doit être ajoutée à chaque security-constraint.

Ménage

Je retire les applications inutiles :

Pour ROOT, j'en vide le contenu pour le remplacer par une simple page index.html de redirection.

<!DOCTYPE html>
<html>
  <head>
    <meta http-equiv="REFRESH" content="0;URL=/myapp/">
    <title>Redirecting...</title>
  </head>
  <body>
  </body>
</html>

Applications d'admin

Je n'installe pas l'application admin, de toute façon elle ne fonctionne plus correctement dans Tomcat 6.

J'ajoute (et sécurise) les applications suivantes :

Applications métier

J'installe les applications métier + DataSource (+ Realm).

Je précompile les JSP (avec lambda probe Psi Probe)

Configuration

Ménage

Pour y voir un peu plus clair, je retire tous les commentaires dans le fichier server.xml.

Connector

SSL, mais je l'ai déjà dit. J'ouvre le connecteur AJP, pour installer Apache en frontal. Éventuellement, si AJP ne convient pas (par choix des administrateurs réseau), je crée un nouveau connecteur sur le 8082.

Chaque connecteur utilise son propre pool de thread, car je n'ai pas encore bien vu l'intérêt du pool partagé (Executor de Tomcat 6).

DataSource

Je crée les DataSources nécessaires dans GlobalNamingResources. Les jar sont placés dans libsw, déclaré comme autre répertoire de librairies (pour ne pas mélanger avec les jar d'origine).

Jasper

Désactiver le mode development

Sécurité

Utiliser les valves d'accès, au moins pour manager

Je n'active pas le SecurityManager, bien que ça pourrait être une bonne chose !

Traces

Log4J + valves de traces à la mode Apache + sewatrace