How to Install and Configure Apache Tomcat on Windows Server 2025
Apache Tomcat is the most widely deployed open-source Java Servlet container in the world, used to host Java EE web applications packaged as WAR files, Spring Boot embedded applications, and Jakarta EE workloads. On Windows Server 2025, Tomcat can be installed as a native Windows Service, configured for production-grade performance, integrated with IIS through Application Request Routing as a reverse proxy, and secured with TLS certificates stored in a PKCS12 keystore. This tutorial covers installing Tomcat 10.x using the Windows Service Installer, verifying the JAVA_HOME prerequisite, configuring Tomcat as a Windows service, tuning server.xml for production use, deploying WAR applications through the Manager web application, setting up an IIS reverse proxy using ARR, configuring SSL directly on Tomcat, and applying JVM performance tuning through CATALINA_OPTS.
Prerequisites
- Windows Server 2025 with administrative privileges
- Java Development Kit (JDK) 21 LTS or later installed and
JAVA_HOMEconfigured - PowerShell 5.1 or PowerShell 7.x
- At least 1 GB of free disk space
- IIS installed if using the reverse proxy configuration (optional)
- A valid TLS certificate in PKCS12 format for SSL configuration (optional)
Step 1: Verify JAVA_HOME Before Installation
Tomcat’s Windows Service Installer and startup scripts depend on JAVA_HOME being set to a valid JDK directory. Verify this before running the installer to avoid service startup failures.
# Verify JAVA_HOME is set at the machine level
$javaHome = [Environment]::GetEnvironmentVariable("JAVA_HOME", "Machine")
Write-Host "JAVA_HOME: $javaHome"
# Confirm the JDK binary exists
if (Test-Path "$javaHomebinjava.exe") {
Write-Host "java.exe found."
& "$javaHomebinjava.exe" -version
} else {
Write-Error "JAVA_HOME is incorrect. Set it before installing Tomcat."
}
# If JAVA_HOME is missing, set it now
$jdkPath = "C:Program FilesEclipse Adoptiumjdk-21.0.5.11-hotspot"
[Environment]::SetEnvironmentVariable("JAVA_HOME", $jdkPath, "Machine")
$env:JAVA_HOME = $jdkPath
Step 2: Download and Install Tomcat 10.x Using the Windows Service Installer
The Apache Tomcat project provides a dedicated Windows Service Installer (.exe) that installs Tomcat as a native Windows Service and creates start menu shortcuts, making it straightforward to manage through the Services MMC snap-in.
# Download Tomcat 10.1 Windows Service Installer
$tomcatVersion = "10.1.34"
$installerUrl = "https://dlcdn.apache.org/tomcat/tomcat-10/v$tomcatVersion/bin/apache-tomcat-$tomcatVersion.exe"
$installerPath = "C:Tempapache-tomcat-$tomcatVersion.exe"
Invoke-WebRequest -Uri $installerUrl -OutFile $installerPath -UseBasicParsing
# Run interactive installer — choose "Service" component during setup
# Or run silently with /S flag and default options
Start-Process -FilePath $installerPath -ArgumentList "/S" -Wait
# Default install path is C:Program FilesApache Software FoundationTomcat 10.1
$catalinaHome = "C:Program FilesApache Software FoundationTomcat 10.1"
[Environment]::SetEnvironmentVariable("CATALINA_HOME", $catalinaHome, "Machine")
$env:CATALINA_HOME = $catalinaHome
# Verify service was created
Get-Service -Name "Tomcat10*"
Step 3: Configure Tomcat as a Windows Service
Tomcat ships with service.bat for managing its Windows Service registration. You can use this to install, remove, start, and stop the service, and to configure service-level JVM parameters.
# Navigate to Tomcat bin directory
Set-Location "$env:CATALINA_HOMEbin"
# Install the Tomcat Windows Service manually (if not done by installer)
.service.bat install Tomcat10
# Configure service startup type and start it
Set-Service -Name "Tomcat10" -StartupType Automatic
Start-Service -Name "Tomcat10"
Get-Service -Name "Tomcat10"
# Use Tomcat's native service manager to configure JVM memory
# tomcat10w.exe is the Windows Service Manager GUI
Start-Process ".tomcat10w.exe" -ArgumentList "//ES//Tomcat10"
# Or configure JVM options directly via the registry / tomcat10w.exe CLI
.tomcat10w.exe //US//Tomcat10 `
--JvmMs 512 `
--JvmMx 2048 `
--JvmSs 512 `
--Startup auto
# Stop, remove, and reinstall the service
.service.bat stop Tomcat10
.service.bat remove Tomcat10
.service.bat install Tomcat10
Step 4: Configure server.xml for Production
Tomcat’s primary configuration file is server.xml, located in the conf directory. Key production settings include the HTTP Connector port, URI encoding, connection timeout, and thread pool size.
# View the current server.xml
Get-Content "$env:CATALINA_HOMEconfserver.xml"
# Key Connector element for production (edit server.xml):
#
#
# Apply changes using PowerShell XML manipulation
$serverXmlPath = "$env:CATALINA_HOMEconfserver.xml"
[xml]$xml = Get-Content $serverXmlPath
$connector = $xml.Server.Service.Connector |
Where-Object { $_.protocol -eq "HTTP/1.1" }
$connector.SetAttribute("URIEncoding", "UTF-8")
$connector.SetAttribute("maxThreads", "200")
$connector.SetAttribute("acceptCount", "100")
$connector.SetAttribute("compression", "on")
$xml.Save($serverXmlPath)
Write-Host "server.xml updated."
# Restart Tomcat to apply changes
Restart-Service -Name "Tomcat10"
Step 5: Deploy WAR Files via the Manager Web Application
Tomcat’s Manager application provides both a web UI and a REST API for deploying, undeploying, starting, and stopping web applications without restarting the server. Access is controlled by tomcat-users.xml.
# Configure tomcat-users.xml with manager roles
$usersXml = @'
'@
$usersXml | Set-Content "$env:CATALINA_HOMEconftomcat-users.xml" -Encoding UTF8
# Allow Manager access from remote IPs (edit context.xml in webappsmanagerMETA-INF)
$contextPath = "$env:CATALINA_HOMEwebappsmanagerMETA-INFcontext.xml"
[xml]$ctx = Get-Content $contextPath
# Comment out or remove the Valve that restricts to 127.d+.d+.d+|::1|0:0:0:0:0:0:0:1
# Deploy a WAR file via curl/Invoke-WebRequest (Manager API)
$warPath = "C:AppsMyApp.war"
Invoke-WebRequest -Uri "http://localhost:8080/manager/text/deploy?path=/myapp&update=true" `
-Method Put `
-InFile $warPath `
-Credential (Get-Credential) `
-ContentType "application/octet-stream"
# Or simply drop the WAR into the webapps directory for auto-deploy
Copy-Item "C:AppsMyApp.war" "$env:CATALINA_HOMEwebappsMyApp.war"
Step 6: Configure IIS as a Reverse Proxy to Tomcat Using ARR
Placing IIS in front of Tomcat allows you to handle SSL termination at IIS, use IIS authentication, and serve static files efficiently while forwarding dynamic requests to Tomcat on port 8080.
# Install Application Request Routing (ARR) and URL Rewrite
winget install Microsoft.IISUrlRewrite --silent --accept-package-agreements
winget install Microsoft.ARR --silent --accept-package-agreements
# Enable ARR proxy in IIS
Import-Module WebAdministration
Set-WebConfiguration -PSPath "IIS:" `
-Filter "system.webServer/proxy" `
-Value @{ enabled = $true }
# Create a URL Rewrite rule to proxy requests to Tomcat
$rewriteXml = @'
'@
# Apply via web.config or IIS Manager
# In web.config under system.webServer/rewrite/rules, add the rule above
# Set the ARR server farm timeout
Add-WebConfiguration -PSPath "IIS:" `
-Filter "system.webServer/proxy" `
-Value @{ timeout = "00:01:00" }
Write-Host "IIS reverse proxy to Tomcat:8080 configured."
Step 7: Configure Tomcat SSL with a PKCS12 Keystore
For environments where Tomcat handles HTTPS directly (without an IIS reverse proxy), configure a PKCS12 keystore and enable the HTTPS Connector in server.xml.
# Convert a PFX/P12 certificate to confirm it is valid
$pfxPath = "C:Certsmyapp.pfx"
$keystorePw = "keystorePassword123!"
# Import PFX to verify it loads (PowerShell)
$cert = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2(
$pfxPath, $keystorePw,
[System.Security.Cryptography.X509Certificates.X509KeyStorageFlags]::PersistKeySet
)
Write-Host "Certificate subject: $($cert.Subject)"
Write-Host "Expires: $($cert.NotAfter)"
# Copy PFX to Tomcat conf directory
Copy-Item $pfxPath "$env:CATALINA_HOMEconfmyapp.p12"
# Add HTTPS Connector to server.xml:
#
#
#
#
#
#
Restart-Service -Name "Tomcat10"
# Test: Invoke-WebRequest https://localhost:8443 -SkipCertificateCheck
Step 8: JVM Performance Tuning with CATALINA_OPTS
Tomcat’s JVM startup parameters are controlled by the CATALINA_OPTS environment variable. Setting appropriate heap sizes, garbage collector options, and diagnostic flags significantly improves throughput and stability under production load.
# Set CATALINA_OPTS system-wide for the Tomcat service
$catalinaOpts = "-server " +
"-Xms1g -Xmx4g " +
"-XX:+UseG1GC " +
"-XX:MaxGCPauseMillis=200 " +
"-XX:+UseStringDeduplication " +
"-XX:+HeapDumpOnOutOfMemoryError " +
"-XX:HeapDumpPath=C:Logstomcat-heapdump.hprof " +
"-Djava.awt.headless=true " +
"-Dfile.encoding=UTF-8 " +
"-Djava.net.preferIPv4Stack=true"
[Environment]::SetEnvironmentVariable("CATALINA_OPTS", $catalinaOpts, "Machine")
# For the Tomcat10 Windows Service, set JVM parameters via tomcat10w.exe
.tomcat10w.exe //US//Tomcat10 `
--JvmOptions "-server;-Xms1g;-Xmx4g;-XX:+UseG1GC;-XX:MaxGCPauseMillis=200" `
--JvmMs 1024 `
--JvmMx 4096
# Restart service to apply JVM settings
Restart-Service -Name "Tomcat10"
# Monitor JVM GC in real-time (get Tomcat PID first)
$tomcatPid = (Get-Process -Name "tomcat10" -ErrorAction SilentlyContinue).Id
if ($tomcatPid) {
jstat -gcutil $tomcatPid 2000 20
}
Conclusion
Apache Tomcat on Windows Server 2025 is a powerful and production-ready hosting environment for Java web applications when configured correctly. Starting with the Windows Service Installer ensures Tomcat integrates cleanly with the Windows Services infrastructure, enabling automatic startup and restart-on-failure policies. Tuning server.xml with appropriate thread counts, URI encoding, and compression settings prepares Tomcat for real-world traffic. The Manager web application enables zero-downtime WAR deployments without touching the service itself. Placing IIS with ARR in front of Tomcat offloads SSL termination and static file serving while maintaining the flexibility of Java backends. And careful CATALINA_OPTS tuning — particularly heap sizing and G1GC configuration — prevents the out-of-memory errors and long GC pauses that plague under-tuned JVM environments. With these fundamentals in place, Tomcat on Windows Server 2025 can reliably serve high-concurrency Java applications in enterprise production settings.