The Complete Guide on How to Install, Configure, Secure and Host Apache Tomcat 9 for Java Web Applications

For Java web developers and software architects seeking to build modern, scalable web apps on open standards, Apache Tomcat is likely a familiar name. Yet effectively installing, hardening, optimizing and hosting Tomcat for production use can still prove surprisingly tricky.

This comprehensive 3000+ word guide aims to condense over a decade of my real-world experience wrangling finicky Tomcats down to actionable best practices for old pros and newbies alike.

Whether you want to tinker with Java servlets locally or host blazing fast customer-facing sites globally, you’ll find plenty of hard-won tips ahead!

An Introduction to Apache Tomcat

Before we dig in, let‘s step back briefly to first understand…wtf is Tomcat anyway?

Apache Tomcat (or simply Tomcat) is open source software that implements specifications from Oracle‘s Java Enterprise Edition, providing a "container" to run Java based web applications that rely on components like Servlets and JSPs.

In simpler terms:

  • Tomcat lets developers write Java code that can handle HTTP network requests and serve dynamic web content
  • It manages the lifecycle of Java Servlets, handling things like request routing, session management, authentication etc behind the scenes
  • It serves as a handy local sandbox for testing Java web apps during development
  • It can also be deployed as a production server to host apps publicly facing customers 24/7

So in essence, Tomcat plays a similar role to something like PHP‘s Apache httpd, Node‘s Express framework, or Python‘s WSGI servers – a request handler/app runner that web apps utilize under the hood.

But there‘s a couple unique advantages:

Portability – Java‘s "write once, run anywhere" philosophy means apps running on Tomcat can deploy easily across many operating systems and cloud platforms with minimal changes

Performance – Tomcat utilizes tried and true Java Enterprise Edition standards when it comes to things like security, transaction handling and multi-threading – making it well suited for large scale apps

Ecosystem – Mature open source projects like Spring Boot have further simplified building scalable, resilient Tomcat hosted apps even for relative beginners

Simply put – if you plan to build Java based web applications, chances are very high you‘ll be interacting with Tomcat sooner rather than later!

Now let‘s go through the process of getting your own instance stood up…

Step 1 – Install Java Runtime Environment

Since Tomcat utilizes Java under the hood, having Java installed and configured is a must have prerequisite.

I recommend OpenJDK 8 or 11 for rock solid stability:

sudo apt update
sudo apt install openjdk-11-jdk

Double check the version to confirm the JDK is installed:

java -version

This should print out details like:

openjdk 11.0.17 2022-10-18 LTS
OpenJDK Runtime Environment (build 11.0.17+8-LTS)
OpenJDK 64-Bit Server VM (build 11.0.17+8-LTS, mixed mode, sharing)

If you don‘t see a similar output, your JAVA_HOME path may be misconfigured – so verify environment variables before proceeding.

Now that Java is squared away, we can download Tomcat itself…

Step 2 – Download and Extract Tomcat

Browse to tomcat.apache.org to view releases. I generally recommend sticking with a recent stable release like 9.0.x or 10.0.x over bleeding edge milestones for production use cases.

For this guide I‘ll demonstrate Tomcat 10 installation, but all instructions apply similarly to other supported versions too.

A) Download Binary Package

Download the Core zip/tar package for your system – such as apache-tomcat-10.0.27.tar.gz for Linux.

We‘ll handle the install using the command line. Open terminal and make sure you‘re in the intended install directory – I typically use /opt:

cd /opt

Download via wget (or curl) – using the mirror closest to your location for faster downloads:

wget https://dlcdn.apache.org//tomcat/tomcat-10/v10.0.27/bin/apache-tomcat-10.0.27.tar.gz

B) (Optional) Compile from Source

For added security or customization, compiling from source is another option. But it requires Maven & Java SDK installed.

Clone Tomcat base files from GitHub mirror:

git clone https://github.com/apache/tomcat.git

Checkout the version intended, then build a distribution from source:

cd tomcat 
git checkout -b v10.0.x
mvn clean install

Either way, once you have a apache-tomcat-10* package downloaded or compiled, extract contents:

tar -zxvf apache-tomcat-*

This unpacks everything into a new Tomcat folder we‘ll configure next.

Step 3 – Configure Users, File Permissions and Folders

For security best practices, Tomcat should always run under a unique non-root user account without unnecessary permissions granted.

Create a local ‘tomcat‘ user:

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

Ensure the ‘tomcat‘ user/group owns the Tomcat directory, with read/execute access only:

sudo chown -RH tomcat:tomcat /opt/apache-tomcat-10.0.27 
sudo chmod -R 550 /opt/apache-tomcat-10.0.27

No need for anyone but the Tomcat user itself to write after installation.

Define folders for app deployment and logging:

sudo mkdir /opt/tomcat/webapps
sudo mkdir /opt/tomcat/logs

Then lock those down too:

sudo chown -R tomcat:tomcat /opt/tomcat
sudo chmod -R g+r conf 
sudo chmod g+x conf 

With security policies and folders configured, let‘s configure environment variables next…

Step 4 – Configure Environment Variables

Tomcat requires a few key ENV variables to be defined – namely pointers where Java and the Tomcat install resides within the filesystem.

There‘s a couple ways we could approach this.

For testing, export them ad-hoc from terminal prefaced with every command:

export JRE_HOME=/usr/lib/jvm/default-java  
export CATALINA_HOME=/opt/apache-tomcat-10.0.27

But for persistent usage, it‘s best to define once globally within shell resource files like /etc/environment:

sudo nano /etc/environment

Then add:

CATALINA_HOME="/opt/apache-tomcat-10.0.27"  
JRE_HOME="/usr/lib/jvm/default-java"

Save and exit editor. Lastly reload changes from the file with:

source /etc/environment

And we can confirm values are now available:

echo $CATALINA_HOME $JRE_HOME

With minimum prerequisites covered, let‘s walk through starting up Tomcat next.

Step 5 – Start and Stop Tomcat

Alright, finally time for the moment of truth – let‘s fire up our freshly installed Tomcat!

Recall from earlier we created a ‘tomcat‘ user that the server process will run under for security isolation.

So to start Tomcat:

sudo -E -u tomcat $CATALINA_HOME/bin/startup.sh

The -E flag passes defined environment variables into the subprocess.

To gracefully shut down the server:

sudo -E -u tomcat $CATALINA_HOME/bin/shutdown.sh

You can verify Tomcat booted successfully by accessing the default home page:

http://your_ip_address:8080

And you should see a page similar to:

Tomcat homepage

Hooray! Our Tomcat server is running and ready to host applications.

But before we move onto production deployments, let‘s configure a few more things for running as a persistent service…

Step 6 – Configure Tomcat as a Service

The startup.sh and shutdown.sh scripts are handy for testing, but fairly useless for running persistently in production.

Instead we want Tomcat to function like a proper daemon service that handles things like:

  • Starting automatically when the server boots
  • Restarting on failures
  • Logging to system log files
  • Enabling security policies

On Linux, we can leverage systemd to achieve this quite smoothly.

Create a tomcat service unit file:

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

Populate with the following – updating any directory paths as needed:

[Unit]
Description=Apache Tomcat 10.0.x Servlet Container
After=network.target

[Service]  
Type=forking
User=tomcat
Group=tomcat
Environment="JAVA_HOME=/usr/lib/jvm/default-java"
Environment="CATALINA_HOME=/opt/apache-tomcat-10.0.27"
ExecStart=/opt/apache-tomcat-10.0.27/bin/startup.sh
ExecStop=/opt/apache-tomcat-10.0.27/bin/shutdown.sh 

[Install]
WantedBy=multi-user.target

This defines metadata like the service description, adds proper path + permssion settings for our tomcat user, and specifies the start/stop logic.

Let systemd reload units from disk to pick up the new service:

sudo systemctl daemon-reload

Then we can start it and enable auto-launch on reboots like any other service:

sudo systemctl start tomcat
sudo systemctl enable tomcat

Now check status with:

systemctl status tomcat

And Tomcat can be controlled system-wide using familiar systemctl commands for starting, stopping, restarting etc.

Much cleaner than needing console access and fiddling with shell scripts!

Now with Tomcat running as a managed service, let‘s look at some recommended optimizations and security hardening tweaks next…

Securing and Optimizing Tomcat for Production

The default out-of-box configs are great for development sandboxes. But when running Tomcat in business critical production facing customer traffic, here‘s some key steps I always follow to dial things in…

A) Lock Down Users and Permissions

Limit accounts that can access Tomcat, disable defaults, and remove unnecessary privileges:

  • Delete any sample users in tomcat-users.xml
  • Don‘t assign Manager webapp access at all
  • double check the OS tomcat user has no sudo rights

B) Enable SSL/TLS Everywhere

Encryption is non-negotiable for security and PCI compliance.

Redirect all HTTP to HTTPS and terminate connections at the edge through a proxy or dedicated cert manager handling TLS offloading.

For internal Tomcat communications, utilize SSL connectors over APR if possible.

C) Audit Request Logs

Application logging is useful, butmake sure access logging at the Tomcat engine level is enabled for security auditing:

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

D) Enable Remote Shutdown Authentication

Restrict who can remotely shut down the Tomcat process gracefully:

<Listener className="org.apache.catalina.security.SecurityListener"
          strictShutdown="true" />

E) Configure Resource Limits Via SecurityManager

The security manager denies unsafe actions by untrusted code – sandbox your apps!

For instance:

java.lang.RuntimePermission "modifyThreadGroup"

F) Prefer Virtualization Over Shared Hosts

Neighbors behaving badly on shared hardware can impact security, disk I/O, network contention etc.

So for production apps isolate environments using containers, private cloud hosts or dedicated hardware with virtualization.

Moving to Managed Tomcat Hosting Providers

Even with optimizations, the operational overhead of handling infrastructure security, high availability redundancy, failovers, scaling etc may become burdensome.

So another option gaining popularity is leveraging managed PaaS providers specializing in taking care of Tomcat hosting operations for you. Some prominent names include:

AWS Elastic Beanstalk

  • Deploy preconfigured Tomcat platforms
  • Auto-scaling capabilities
  • Supports Docker containers
  • Integrates with other AWS services

Microsoft Azure App Service

  • Web app + hosted Tomcat container
  • Continuous deployment from GitHub etc
  • Auto-scale up for traffic spikes
  • Load balancing and traffic manager

Google Cloud Run

  • Serverless container platform
  • Pay only for actual compute used
  • Auto-scaling built-in
  • Leverage other Google Cloud services

Red Hat OpenShift

  • Enterprise Java & Tomcat focused
  • On-premise or cloud hosted
  • Integrates with JBoss
  • Rich DevOps capabilities

The benefits of hosted PaaS certainly can‘t be understated – notably transferring infrastructure security, high availability, failover testing, horizontal scaling etc over to specialized teams.

This frees developers up to focus on just the application logic and business needs rather than racking servers or patching libs.

However, vendor platform lock-in is definitely a drawback to weigh carefully as app complexity and data gravity takes hold.

Closing Recommendations

Hopefully this guide has given you a comprehensive overview of Apache Tomcat – from understanding the technology landscape and use cases driving its prevalence, to configured secured instances yourself start to finish on bare metal or cloud hosts.

We covered key performance, security and maintenance best practices in depth along with factoring when it might make sense to offload operations completely to dedicated PaaS providers.

If one thing‘s clear, it‘s that Tomcat remains as relevant as ever in the modern Java web ecosystem thanks to its portability and tight integration with popular open standards like Servlets and JSPs.

For further reading beyond this introduction, I highly recommend the Official Apache Tomcat Documentation for far more nitty details across all aspects of administration.

Any questions you run into on your Java journey? Feel free to drop them in the comments below!