Apache Tomcat ist ein Open-Source-Servlet-Container für Java-Webanwendungen. Er implementiert Java Servlet, JSP und WebSocket-Technologien.

Warum Tomcat?

Vorteile

- Leichtgewichtig
- Einfache Konfiguration
- Große Community
- Aktive Entwicklung
- Produktionsreif

Tomcat-Versionen

| Version | Java | Servlet | JSP | |---------|------|---------|-----| | Tomcat 10 | 11+ | 6.0 | 3.1 | | Tomcat 9 | 8+ | 4.0 | 2.3 | | Tomcat 8.5 | 7+ | 3.1 | 2.3 |

Voraussetzungen

Java installieren

# OpenJDK 17 (empfohlen)
apt update
apt install openjdk-17-jdk

# Version prüfen
java -version

# JAVA_HOME setzen
echo 'export JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64' >> /etc/profile
source /etc/profile

Installation

Benutzer erstellen

useradd -r -m -d /opt/tomcat -s /bin/false tomcat

Tomcat herunterladen

cd /tmp
wget https://dlcdn.apache.org/tomcat/tomcat-10/v10.1.18/bin/apache-tomcat-10.1.18.tar.gz

# Extrahieren
tar -xzf apache-tomcat-10.1.18.tar.gz
mv apache-tomcat-10.1.18/* /opt/tomcat/

# Berechtigungen
chown -R tomcat:tomcat /opt/tomcat
chmod +x /opt/tomcat/bin/*.sh

Verzeichnisstruktur

/opt/tomcat/
├── bin/           # Start-/Stop-Skripte
├── conf/          # Konfiguration
├── lib/           # Bibliotheken
├── logs/          # Log-Dateien
├── temp/          # Temporäre Dateien
├── webapps/       # Anwendungen
└── work/          # Kompilierte JSPs

Systemd-Service

Service-Datei erstellen

# /etc/systemd/system/tomcat.service

[Unit]
Description=Apache Tomcat 10
After=network.target

[Service]
Type=forking

User=tomcat
Group=tomcat

Environment="JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64"
Environment="CATALINA_HOME=/opt/tomcat"
Environment="CATALINA_BASE=/opt/tomcat"
Environment="CATALINA_PID=/opt/tomcat/temp/tomcat.pid"
Environment="CATALINA_OPTS=-Xms512M -Xmx1024M -server -XX:+UseParallelGC"

ExecStart=/opt/tomcat/bin/startup.sh
ExecStop=/opt/tomcat/bin/shutdown.sh

RestartSec=10
Restart=always

[Install]
WantedBy=multi-user.target

Service aktivieren

systemctl daemon-reload
systemctl enable --now tomcat
systemctl status tomcat

Konfiguration

Server-Port ändern

<!-- /opt/tomcat/conf/server.xml -->

<!-- HTTP-Connector -->
<Connector port="8080" protocol="HTTP/1.1"
           connectionTimeout="20000"
           redirectPort="8443"
           maxThreads="150"
           minSpareThreads="25" />

<!-- AJP-Connector (für Apache/Nginx) -->
<Connector port="8009" protocol="AJP/1.3"
           redirectPort="8443"
           secretRequired="false" />

Manager-App aktivieren

<!-- /opt/tomcat/conf/tomcat-users.xml -->

<tomcat-users>
    <role rolename="manager-gui"/>
    <role rolename="manager-script"/>
    <role rolename="admin-gui"/>
    <user username="admin" password="SicheresPasswort!"
          roles="manager-gui,manager-script,admin-gui"/>
</tomcat-users>

Remote-Zugriff auf Manager

<!-- /opt/tomcat/webapps/manager/META-INF/context.xml -->

<Context antiResourceLocking="false" privileged="true">
    <Valve className="org.apache.catalina.valves.RemoteAddrValve"
           allow="127\.\d+\.\d+\.\d+|::1|0:0:0:0:0:0:0:1|192\.168\.1\.\d+" />
</Context>

Host-Manager (analog)

<!-- /opt/tomcat/webapps/host-manager/META-INF/context.xml -->

<Context antiResourceLocking="false" privileged="true">
    <Valve className="org.apache.catalina.valves.RemoteAddrValve"
           allow="127\.\d+\.\d+\.\d+|::1|192\.168\.1\.\d+" />
</Context>

Anwendung deployen

WAR-Datei kopieren

cp myapp.war /opt/tomcat/webapps/
chown tomcat:tomcat /opt/tomcat/webapps/myapp.war

# Automatisches Deployment
# Tomcat entpackt die WAR automatisch

Über Manager-App

URL: http://server-ip:8080/manager/html
→ WAR file to deploy
→ Datei auswählen
→ Deploy

Anwendung entfernen

# Manuell
rm -rf /opt/tomcat/webapps/myapp
rm /opt/tomcat/webapps/myapp.war

# Oder über Manager-App
→ Applications → Undeploy

Virtual Hosts

Mehrere Hosts

<!-- /opt/tomcat/conf/server.xml -->

<Engine name="Catalina" defaultHost="localhost">

    <!-- Standard-Host -->
    <Host name="localhost" appBase="webapps"
          unpackWARs="true" autoDeploy="true">
    </Host>

    <!-- Zusätzlicher Host -->
    <Host name="app.example.com" appBase="app-webapps"
          unpackWARs="true" autoDeploy="true">
        <Alias>www.app.example.com</Alias>
        <Valve className="org.apache.catalina.valves.AccessLogValve"
               directory="logs"
               prefix="app_access_log" suffix=".txt"
               pattern="%h %l %u %t &quot;%r&quot; %s %b" />
    </Host>

</Engine>

Host-Verzeichnis erstellen

mkdir /opt/tomcat/app-webapps
chown tomcat:tomcat /opt/tomcat/app-webapps

SSL/TLS einrichten

Keystore erstellen

keytool -genkey -alias tomcat -keyalg RSA -keysize 2048 \
    -keystore /opt/tomcat/conf/keystore.jks \
    -validity 365

SSL-Connector

<!-- /opt/tomcat/conf/server.xml -->

<Connector port="8443" protocol="org.apache.coyote.http11.Http11NioProtocol"
           maxThreads="150" SSLEnabled="true">
    <SSLHostConfig>
        <Certificate certificateKeystoreFile="conf/keystore.jks"
                     certificateKeystorePassword="passwort"
                     type="RSA" />
    </SSLHostConfig>
</Connector>

Let's Encrypt-Zertifikat

# Zertifikat in PKCS12 konvertieren
openssl pkcs12 -export \
    -in /etc/letsencrypt/live/example.com/fullchain.pem \
    -inkey /etc/letsencrypt/live/example.com/privkey.pem \
    -out /opt/tomcat/conf/keystore.p12 \
    -name tomcat \
    -passout pass:passwort
<Connector port="8443" protocol="org.apache.coyote.http11.Http11NioProtocol"
           maxThreads="150" SSLEnabled="true">
    <SSLHostConfig>
        <Certificate certificateKeystoreFile="conf/keystore.p12"
                     certificateKeystorePassword="passwort"
                     certificateKeystoreType="PKCS12"
                     type="RSA" />
    </SSLHostConfig>
</Connector>

Nginx als Reverse Proxy

Nginx-Konfiguration

# /etc/nginx/sites-available/tomcat

upstream tomcat {
    server 127.0.0.1:8080;
}

server {
    listen 80;
    server_name app.example.com;
    return 301 https://$server_name$request_uri;
}

server {
    listen 443 ssl http2;
    server_name app.example.com;

    ssl_certificate /etc/letsencrypt/live/app.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/app.example.com/privkey.pem;

    location / {
        proxy_pass http://tomcat;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

Tomcat für Proxy konfigurieren

<!-- /opt/tomcat/conf/server.xml -->

<Connector port="8080" protocol="HTTP/1.1"
           connectionTimeout="20000"
           redirectPort="8443"
           proxyName="app.example.com"
           proxyPort="443"
           scheme="https"
           secure="true" />

Apache mod_jk (AJP)

Apache-Modul installieren

apt install libapache2-mod-jk

Worker-Konfiguration

# /etc/libapache2-mod-jk/workers.properties

worker.list=tomcat

worker.tomcat.type=ajp13
worker.tomcat.host=localhost
worker.tomcat.port=8009

Apache Virtual Host

# /etc/apache2/sites-available/tomcat.conf

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

    JkMount /* tomcat

    # Statische Dateien direkt
    JkUnMount /static/* tomcat
    Alias /static /var/www/static
</VirtualHost>

Performance-Tuning

JVM-Optionen

# /opt/tomcat/bin/setenv.sh

#!/bin/sh

CATALINA_OPTS="-Xms1024M -Xmx2048M"
CATALINA_OPTS="$CATALINA_OPTS -XX:+UseG1GC"
CATALINA_OPTS="$CATALINA_OPTS -XX:MaxGCPauseMillis=200"
CATALINA_OPTS="$CATALINA_OPTS -XX:+HeapDumpOnOutOfMemoryError"
CATALINA_OPTS="$CATALINA_OPTS -XX:HeapDumpPath=/opt/tomcat/logs/"

export CATALINA_OPTS
chmod +x /opt/tomcat/bin/setenv.sh

Connector-Tuning

<Connector port="8080" protocol="HTTP/1.1"
           connectionTimeout="20000"
           redirectPort="8443"
           maxThreads="200"
           minSpareThreads="25"
           maxConnections="10000"
           acceptCount="100"
           enableLookups="false"
           compression="on"
           compressionMinSize="2048"
           compressableMimeType="text/html,text/xml,text/plain,text/css,application/json" />

Session-Konfiguration

<!-- /opt/tomcat/conf/web.xml oder app/WEB-INF/web.xml -->

<session-config>
    <session-timeout>30</session-timeout>
    <cookie-config>
        <http-only>true</http-only>
        <secure>true</secure>
    </cookie-config>
</session-config>

Sicherheit

Sicherheits-Checkliste

<!-- /opt/tomcat/conf/server.xml -->

<!-- 1. Server-Info verstecken -->
<Connector port="8080" ...
           server="Apache" />

<!-- 2. Shutdown-Port deaktivieren -->
<Server port="-1" shutdown="SHUTDOWN">

Error-Seiten

<!-- /opt/tomcat/conf/web.xml -->

<error-page>
    <error-code>404</error-code>
    <location>/error/404.html</location>
</error-page>

<error-page>
    <error-code>500</error-code>
    <location>/error/500.html</location>
</error-page>

Security Manager

# Aktivieren (optional, erhöht Sicherheit)
/opt/tomcat/bin/startup.sh -security

Unnötige Apps entfernen

# In Produktion entfernen
rm -rf /opt/tomcat/webapps/ROOT
rm -rf /opt/tomcat/webapps/docs
rm -rf /opt/tomcat/webapps/examples
# Manager-Apps nur bei Bedarf behalten

Logging

Logging-Konfiguration

# /opt/tomcat/conf/logging.properties

handlers = 1catalina.org.apache.juli.AsyncFileHandler, \
           2localhost.org.apache.juli.AsyncFileHandler, \
           java.util.logging.ConsoleHandler

1catalina.org.apache.juli.AsyncFileHandler.level = FINE
1catalina.org.apache.juli.AsyncFileHandler.directory = ${catalina.base}/logs
1catalina.org.apache.juli.AsyncFileHandler.prefix = catalina.
1catalina.org.apache.juli.AsyncFileHandler.maxDays = 30

Access Log

<!-- /opt/tomcat/conf/server.xml -->

<Valve className="org.apache.catalina.valves.AccessLogValve"
       directory="logs"
       prefix="access_log"
       suffix=".txt"
       pattern="%h %l %u %t &quot;%r&quot; %s %b %D" />

Log-Rotation

# /etc/logrotate.d/tomcat

/opt/tomcat/logs/catalina.out {
    copytruncate
    daily
    rotate 7
    compress
    missingok
    notifempty
}

Monitoring

JMX aktivieren

# /opt/tomcat/bin/setenv.sh

CATALINA_OPTS="$CATALINA_OPTS -Dcom.sun.management.jmxremote"
CATALINA_OPTS="$CATALINA_OPTS -Dcom.sun.management.jmxremote.port=9090"
CATALINA_OPTS="$CATALINA_OPTS -Dcom.sun.management.jmxremote.ssl=false"
CATALINA_OPTS="$CATALINA_OPTS -Dcom.sun.management.jmxremote.authenticate=false"

Server Status

URL: http://server-ip:8080/manager/status

Prometheus JMX Exporter

# Agent herunterladen
wget https://repo1.maven.org/maven2/io/prometheus/jmx/jmx_prometheus_javaagent/0.19.0/jmx_prometheus_javaagent-0.19.0.jar \
    -O /opt/tomcat/lib/jmx_exporter.jar
# /opt/tomcat/conf/jmx_exporter.yml
rules:
  - pattern: ".*"
# setenv.sh
CATALINA_OPTS="$CATALINA_OPTS -javaagent:/opt/tomcat/lib/jmx_exporter.jar=9404:/opt/tomcat/conf/jmx_exporter.yml"

Backup

Backup-Skript

#!/bin/bash
# /usr/local/bin/tomcat-backup.sh

DATE=$(date +%Y%m%d)
BACKUP_DIR="/backup/tomcat"
TOMCAT_HOME="/opt/tomcat"

mkdir -p $BACKUP_DIR

# Tomcat stoppen (optional)
# systemctl stop tomcat

# Konfiguration und Apps sichern
tar -czf $BACKUP_DIR/tomcat-$DATE.tar.gz \
    $TOMCAT_HOME/conf \
    $TOMCAT_HOME/webapps

# Tomcat starten (falls gestoppt)
# systemctl start tomcat

# Alte Backups löschen
find $BACKUP_DIR -type f -mtime +30 -delete

Troubleshooting

Tomcat startet nicht

# Logs prüfen
tail -f /opt/tomcat/logs/catalina.out

# Port belegt?
netstat -tlnp | grep 8080

# Java-Version
java -version

OutOfMemoryError

# Heap erhöhen
# setenv.sh
CATALINA_OPTS="-Xms1024M -Xmx4096M"

# Heap-Dump analysieren
jmap -dump:live,format=b,file=heap.hprof $(pgrep -f tomcat)

Deployment-Probleme

# WAR-Datei prüfen
jar -tvf myapp.war

# Berechtigungen
chown tomcat:tomcat /opt/tomcat/webapps/myapp.war

Zusammenfassung

| Verzeichnis | Inhalt | |-------------|--------| | conf/ | Konfiguration | | webapps/ | Anwendungen | | logs/ | Log-Dateien | | lib/ | Bibliotheken |

| Befehl | Funktion | |--------|----------| | startup.sh | Tomcat starten | | shutdown.sh | Tomcat stoppen | | catalina.sh run | Im Vordergrund starten |

Fazit

Apache Tomcat ist ein zuverlässiger Servlet-Container für Java-Anwendungen. Die Konfiguration über XML-Dateien ist flexibel, erfordert aber Einarbeitung. Für Produktivumgebungen empfiehlt sich ein Reverse Proxy (Nginx/Apache) vor Tomcat, SSL-Terminierung und angepasste JVM-Optionen. Entfernen Sie nicht benötigte Beispiel-Anwendungen und sichern Sie den Manager-Zugang.