Tomcat Kurulumu ve Java Web Uygulaması Yayınlama

Java ile bir web uygulaması geliştirdiniz, local’de mükemmel çalışıyor, şimdi sıra bunu gerçek bir sunucuda yayınlamaya geldi. İşte tam bu noktada Tomcat devreye giriyor. Apache Tomcat, Java Servlet ve JSP uygulamalarını çalıştırmak için kullanılan, endüstride onlarca yıldır kanıtlanmış bir uygulama sunucusudur. Bu yazıda sıfırdan Tomcat kurulumunu yapacak, güvenli bir şekilde yapılandıracak ve gerçek bir WAR dosyasını yayınlayacağız.

Ön Koşullar ve Ortam Hazırlığı

Tomcat’i kurmadan önce sistemde Java’nın kurulu olması gerekiyor. Tomcat 10.x için Java 11 veya üzeri önerilir. Önce mevcut Java kurulumunu kontrol edelim:

java -version
echo $JAVA_HOME

Eğer Java kurulu değilse Ubuntu/Debian için:

sudo apt update
sudo apt install -y openjdk-17-jdk

RHEL/CentOS/AlmaLinux için:

sudo dnf install -y java-17-openjdk-devel

Java kurduktan sonra JAVA_HOME değişkenini ayarlamak kritik önem taşıyor. Birçok Tomcat sorununun kökü eksik ya da yanlış JAVA_HOME tanımıdır:

# Java'nın nerede kurulu olduğunu bul
sudo update-alternatives --config java
# veya
readlink -f $(which java)

# /etc/environment veya /etc/profile.d/ altına ekle
echo 'JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64' | sudo tee -a /etc/environment
echo 'export JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64' | sudo tee /etc/profile.d/java.sh
source /etc/profile.d/java.sh

Tomcat İndirme ve Kurulum

Tomcat’i paket yöneticisi ile de kurabilirsiniz ama production ortamlarında resmi Apache sitesinden indirip elle kurmayı tercih ederim. Neden? Çünkü bu şekilde hangi versiyonu kullandığınızı tam olarak kontrol edersiniz ve güncellemeleri kendiniz yönetirsiniz.

Önce Tomcat için ayrı bir sistem kullanıcısı oluşturalım. Root ile Tomcat çalıştırmak ciddi bir güvenlik riskidir:

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

Şimdi Tomcat’i indirelim. Bu yazı yazılırken güncel versiyon 10.1.x’tir:

cd /tmp
wget https://downloads.apache.org/tomcat/tomcat-10/v10.1.20/bin/apache-tomcat-10.1.20.tar.gz

# Checksum doğrulaması yapmayı unutmayın
sha512sum apache-tomcat-10.1.20.tar.gz

# Arşivi aç ve taşı
sudo tar -xzf apache-tomcat-10.1.20.tar.gz -C /opt/tomcat --strip-components=1

# Sahipliği ayarla
sudo chown -R tomcat:tomcat /opt/tomcat
sudo chmod -R 750 /opt/tomcat

Systemd Servis Dosyası Oluşturma

Tomcat’i systemd servisi olarak tanımlamak; otomatik başlatma, log yönetimi ve izleme açısından işleri çok kolaylaştırır. Manuel startup.sh çalıştırmak production’da kabul edilemez:

sudo nano /etc/systemd/system/tomcat.service

Aşağıdaki içeriği yapıştırın:

[Unit]
Description=Apache Tomcat Web Application Container
After=network.target

[Service]
Type=forking
User=tomcat
Group=tomcat

Environment="JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64"
Environment="CATALINA_PID=/opt/tomcat/temp/tomcat.pid"
Environment="CATALINA_HOME=/opt/tomcat"
Environment="CATALINA_BASE=/opt/tomcat"
Environment="CATALINA_OPTS=-Xms512M -Xmx1024M -server -XX:+UseParallelGC"
Environment="JAVA_OPTS=-Djava.awt.headless=true -Djava.security.egd=file:/dev/./urandom"

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

RestartSec=10
Restart=always

[Install]
WantedBy=multi-user.target

CATALINA_OPTS içindeki JVM parametrelerine dikkat edin. -Xms512M başlangıç heap boyutu, -Xmx1024M maksimum heap boyutudur. Sunucunuzun RAM’ine göre bu değerleri ayarlayın. Genel kural olarak toplam RAM’in yüzde 50-70’ini Tomcat’e verebilirsiniz.

sudo systemctl daemon-reload
sudo systemctl start tomcat
sudo systemctl enable tomcat
sudo systemctl status tomcat

Tomcat varsayılan olarak 8080 portunda çalışır. Tarayıcıdan http://sunucu-ip:8080 adresine giderek kurulumu doğrulayabilirsiniz.

Güvenlik Yapılandırması

Varsayılan Tomcat kurulumu production için hazır değildir. Birkaç kritik ayarı yapmadan uygulamanızı yayınlamayın.

Manager ve Host-Manager Uygulamalarını Koruma

/opt/tomcat/conf/tomcat-users.xml dosyasını düzenleyin:

sudo nano /opt/tomcat/conf/tomcat-users.xml

tagından önce şunları ekleyin:

<role rolename="manager-gui"/>
<role rolename="manager-script"/>
<role rolename="admin-gui"/>
<user username="tomcatadmin" 
      password="GucluBirSifre123!" 
      roles="manager-gui,manager-script,admin-gui"/>

Önemli: Manager uygulamasına sadece localhost’tan erişimi kısıtlayın. Production’da manager uygulamasının internete açık olması saldırganların favori hedeflerinden biridir:

sudo nano /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|10.0.0.d+" />
</Context>

server.xml Güvenlik Ayarları

sudo nano /opt/tomcat/conf/server.xml

Dikkat etmeniz gereken noktalar:

  • 8005 shutdown portu: Varsayılan SHUTDOWN komutunu değiştirin. satırını bulup anlamlı olmayan bir string yazın.
  • AJP connector’ı devre dışı bırakın: Nginx veya Apache reverse proxy kullanmıyorsanız AJP portunu (8009) kapatın. <Connector protocol="AJP/1.3" ile başlayan satırı yorum satırına alın.
  • X-Powered-By header’ını gizleyin: Connector tanımına xpoweredBy="false" ekleyin.

Nginx ile Reverse Proxy Kurulumu

Production ortamında Tomcat’i direkt olarak internete açmak yerine önüne Nginx koymanızı kesinlikle öneririm. Hem 80/443 portlarından erişim sağlar hem de SSL termination, rate limiting ve statik dosya servisi gibi avantajlar sunar:

sudo apt install -y nginx
sudo nano /etc/nginx/sites-available/myapp
upstream tomcat {
    server 127.0.0.1:8080;
    keepalive 32;
}

server {
    listen 80;
    server_name myapp.example.com;
    
    # HTTP'den HTTPS'e yönlendir
    return 301 https://$host$request_uri;
}

server {
    listen 443 ssl http2;
    server_name myapp.example.com;
    
    ssl_certificate /etc/letsencrypt/live/myapp.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/myapp.example.com/privkey.pem;
    
    # Güvenlik header'ları
    add_header X-Frame-Options "SAMEORIGIN" always;
    add_header X-Content-Type-Options "nosniff" always;
    add_header X-XSS-Protection "1; mode=block" always;
    
    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;
        
        proxy_connect_timeout 60s;
        proxy_read_timeout 300s;
        proxy_send_timeout 300s;
        
        # Büyük dosya yükleme için
        client_max_body_size 100M;
    }
    
    # Statik dosyalar için cache
    location ~* .(js|css|png|jpg|jpeg|gif|ico|svg)$ {
        proxy_pass http://tomcat;
        proxy_cache_valid 200 1d;
        expires 1d;
        add_header Cache-Control "public, immutable";
    }
}
sudo ln -s /etc/nginx/sites-available/myapp /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx

WAR Dosyasını Yayınlama

Asıl amacımıza geldik. Java web uygulamanızı WAR dosyası olarak paketleyip Tomcat’e deploy etmenin birkaç yöntemi var.

Yöntem 1: Webapps Dizinine Kopyalama

En basit yöntem WAR dosyasını doğrudan webapps dizinine atmak. Tomcat çalışırken otomatik olarak algılar ve deploy eder:

# Uygulamanızı build edin (Maven örneği)
mvn clean package -DskipTests

# WAR dosyasını kopyalayın
sudo cp target/myapp-1.0.0.war /opt/tomcat/webapps/myapp.war
sudo chown tomcat:tomcat /opt/tomcat/webapps/myapp.war

Tomcat WAR dosyasını otomatik extract edecek ve webapps/myapp/ dizini oluşacaktır. Uygulamaya http://sunucu:8080/myapp adresinden erişebilirsiniz.

ROOT context’te (yani / path’inde) çalıştırmak istiyorsanız WAR dosyasını ROOT.war olarak kopyalayın. Mevcut ROOT uygulamasını önce silmeyi unutmayın:

sudo rm -rf /opt/tomcat/webapps/ROOT
sudo cp target/myapp-1.0.0.war /opt/tomcat/webapps/ROOT.war
sudo chown tomcat:tomcat /opt/tomcat/webapps/ROOT.war

Yöntem 2: Manager API ile Uzak Deploy

CI/CD pipeline’larında çok işe yarayan bu yöntem, Tomcat’i yeniden başlatmadan uygulamayı güncelleyebilmenizi sağlar:

# Mevcut uygulamayı undeploy et
curl -u tomcatadmin:GucluBirSifre123! 
  "http://localhost:8080/manager/text/undeploy?path=/myapp"

# Yeni versiyonu deploy et
curl -u tomcatadmin:GucluBirSifre123! 
  -T target/myapp-1.0.0.war 
  "http://localhost:8080/manager/text/deploy?path=/myapp&update=true"

# Deploy durumunu kontrol et
curl -u tomcatadmin:GucluBirSifre123! 
  "http://localhost:8080/manager/text/list"

Yöntem 3: Context XML ile Yapılandırmalı Deploy

Daha fazla kontrol istiyorsanız conf/Catalina/localhost/ altına context XML dosyası oluşturun:

sudo nano /opt/tomcat/conf/Catalina/localhost/myapp.xml
<Context path="/myapp" 
         docBase="/opt/apps/myapp-1.0.0.war"
         reloadable="false"
         unpackWAR="true">
    
    <!-- Veritabanı bağlantı havuzu örneği -->
    <Resource name="jdbc/MyDB"
              auth="Container"
              type="javax.sql.DataSource"
              maxTotal="20"
              maxIdle="10"
              maxWaitMillis="10000"
              username="dbuser"
              password="dbpassword"
              driverClassName="org.postgresql.Driver"
              url="jdbc:postgresql://localhost:5432/mydb"/>
</Context>

Bu yöntemin güzel tarafı WAR dosyasını webapps dışında bir yerde tutabilmeniz ve JNDI kaynakları gibi ortama özgü yapılandırmaları uygulama kodundan ayırabilmenizdir.

Log Yönetimi ve Sorun Giderme

Tomcat deploy sırasında sorun yaşandığında ilk bakılacak yer log dosyalarıdır:

# Catalina ana log
sudo tail -f /opt/tomcat/logs/catalina.out

# Tarihli loglar
sudo ls -la /opt/tomcat/logs/
sudo tail -f /opt/tomcat/logs/localhost.$(date +%Y-%m-%d).log

# systemd journal üzerinden
sudo journalctl -u tomcat -f --since "10 minutes ago"

Sık karşılaşılan sorunlar ve çözümleri:

  • ClassNotFoundException: Uygulama bağımlılığı WAR içinde yok demektir. WEB-INF/lib/ dizinini kontrol edin.
  • OutOfMemoryError: Java heap space: CATALINA_OPTS içindeki -Xmx değerini artırın.
  • Port already in use: sudo ss -tlnp | grep 8080 ile hangi process’in portu kullandığını bulun.
  • Permission denied on logs: Log dizini sahipliğini kontrol edin: sudo chown -R tomcat:tomcat /opt/tomcat/logs

Deploy sonrası uygulamanın gerçekten ayakta olup olmadığını kontrol etmek için basit bir health check scripti yazabilirsiniz:

#!/bin/bash
# /usr/local/bin/tomcat-health-check.sh

APP_URL="http://localhost:8080/myapp/health"
HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" --max-time 10 $APP_URL)

if [ "$HTTP_CODE" -eq 200 ]; then
    echo "$(date): Uygulama saglıklı - HTTP $HTTP_CODE"
    exit 0
else
    echo "$(date): UYARI - Uygulama yanıt vermiyor, HTTP kodu: $HTTP_CODE"
    # Buraya bildirim mekanizması ekleyebilirsiniz
    # systemctl restart tomcat  # Otomatik yeniden başlatma
    exit 1
fi
sudo chmod +x /usr/local/bin/tomcat-health-check.sh
# Cron ile her 5 dakikada bir çalıştır
echo "*/5 * * * * root /usr/local/bin/tomcat-health-check.sh >> /var/log/tomcat-health.log 2>&1" | sudo tee /etc/cron.d/tomcat-health

Performans Tuning İpuçları

Production’da Tomcat’in performansını artırmak için birkaç kritik ayar:

server.xml içindeki Connector tanımını optimize edin:

<Connector port="8080" 
           protocol="org.apache.coyote.http11.Http11NioProtocol"
           connectionTimeout="20000"
           maxThreads="200"
           minSpareThreads="25"
           maxConnections="8192"
           acceptCount="100"
           compression="on"
           compressionMinSize="2048"
           compressibleMimeType="text/html,text/xml,text/plain,text/css,
                                  application/javascript,application/json"
           redirectPort="8443"/>
  • maxThreads: Eşzamanlı istek sayısı. Genellikle 200-400 arası uygundur.
  • minSpareThreads: Hazırda bekleyen minimum thread sayısı.
  • compression: Gzip sıkıştırma, bant genişliği kullanımını yüzde 60-70 azaltabilir.
  • maxConnections: Açık tutulabilecek maksimum bağlantı sayısı.

Sonuç

Tomcat kurulumu ve Java uygulaması deploy etmek, doğru adımları takip ettiğinizde oldukça sistematik bir süreçtir. Bu yazıda anlattıklarımızı özetleyecek olursak: ayrı bir sistem kullanıcısıyla güvenli kurulum, systemd entegrasyonu, Nginx reverse proxy ile üretim kalitesi bir yapı ve birden fazla deploy yöntemi.

En çok gördüğüm hata, insanların geliştirme ortamı yapılandırmasını production’a olduğu gibi taşımasıdır. Manager uygulamasını internete açık bırakmak, varsayılan şifreler kullanmak ve JVM parametrelerini hiç dokunmadan geçmek gereksiz sorunlara yol açar.

Bir sonraki adım olarak uygulamanızın deploy sürecini bir CI/CD aracına bağlamanızı öneririm. Jenkins veya GitLab CI ile Maven build ve Tomcat Manager API deploy adımlarını birleştirdiğinizde, kod push etmeniz yeterli olacak ve geri kalanı otomatik halledilecektir. Bu da geceleri rahat uyumanızı sağlar.

Bir yanıt yazın

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir