Using Tomcat for servlets

Apache Tomcat is a widely-used servlet container. A servlet container implements the servlet specification, and can serve Java Server Pages (JSPs).

The following is a collection of reminders regarding its use. It was created using Tomcat 8, but most of this should apply to later versions as well.

Getting Started

To start and stop the Tomcat server:

Tomcat comes with default configuration. When changing that config, you should change the file minimally, and do only what you need. Leave the comments alone, for example, and don't rearrange things unnecessarily. Only then will a simple diff with the default config show where you've deviated from the defaults.

To understand and use Tomcat effectively during development, you need to understand two important ideas:

  1. Tomcat instances
  2. the difference between reload and redeploy

Tomcat Instances

In Tomcat lingo, an instance is a directory that's separate from the Tomcat binary. It contains two things: There's not a huge difference between using an instance and not using an instance. But, using an instance does have these advantages: In the Tomcat docs, you'll see many references to two important environment variables: If you're not using an instance, then $CATALINA_BASE is the same as $CATALINA_HOME.

You can think of a Tomcat instance as a kind of mini-Tomcat. It mimics the same directory structure found in the binary install, and looks like this:

 startup.bat [short scripts that you create]
 shutdown.bat
 conf [start with the same conf folder in the Tomcat binary]
   server.xml [main config; each instance needs its own shutdown port]
   web.xml [settings amalgamated with app web.xml]
   context.xml [settings amalgamated with app's context xml file]
   catalina.properties
   logging.properties
   tomcat-users.xml [used for simple access control]
   Catalina
     localhost
      [app context xml files, that point to your web app]
      [add/delete an xml file here is one way to deploy/undeploy an app]
 lib [database jar; jars shared between apps]
 logs
 webapps 
   [not really needed for deployment, but it's an option]
   [instead, put a context file in conf/Catalina/localhost]
 work [compiled JSPs and whatnot]
So, the idea is that someone on your team sets up an instance, and all of its config, and then the Tomcat instance is shared with the team. The start-stop scripts are short. They simply set up environment variables, and then start the Tomcat binary.

Reload versus Redeploy

The second important idea is the distinction between reload and redeploy.

Reload of an app:

Redeploy of an app:

Summary of the possible operations: By default, app-reload and app-stop/start will preserve sessions. App-redeploy will never preserve sessions.

Avoiding Slow Development

To avoid slow development:

Context Files

A context is simply a web app. It forms part of a Tomcat instance. An app's context xml file instructs Tomcat how to deploy the app: Here's an example of a context xml file (note that its reloadable setting is not suitable for prod):
<Context docBase="/some/dir/" reloadable="true">
 <Resource 
 name="jdbc/MYDatabase" 
 auth="Container" 
 type="javax.sql.DataSource" 
 driverClassName="com.microsoft.sqlserver.jdbc.SQLServerDriver"
 username="someusername"
 password="somepassword"
 url="jdbc:sqlserver://my_database_server_url"
 maxTotal="10"
 maxIdle="5"
 />
</Context>
The file is located in ../conf/Catalina/localhost/mywar.xml. (It can also be embedded in war file itself, at the conventional location META-INF/context.xml.) This will map the app to the URL localhost:8080/mywar. By default, it simply takes the path from the name of the file. If the context points to a war file, instead of a directory, then by default Tomcat will explode the war into its webapps directory.

Note the default naming convention used by Tomcat uses the same name (blah, in the following example) in 3 places:

Manager Application

Tomcat's Manager application lets you If you want to use Tomcat's Manager application, you will need to edit two files. First, conf/tomcat-users.xml. Add the following:
<?xml version='1.0' encoding='utf-8'?/>
<tomcat-users>
  <role rolename="manager-gui"/>
  <role rolename="manager-script"/>
  <role rolename="manager-jmx"/>
  <role rolename="manager-status"/>
  <user username="admin" password="admin" roles="manager-gui, manager-script, manager-jmx, manager-status"/>
</tomcat-users/>
Next is the Manager app's context file. By default, it's located in /webapps/manager/META-INF/context.xml, and it defines an IP filter, that restricts it to the localhost only. You may need to change or remove that restriction.
<?xml version="1.0" encoding="UTF-8"?>
<Context docBase="${catalina.home}/webapps/manager" antiResourceLocking="false" privileged="true">
  <Valve className="org.apache.catalina.valves.RemoteAddrValve" allow="127\.0\.0\.1" />
</Context>
Here, the allow param is actually a regular expression.

Useful Configuration Items

Ideally, these setting should be done once, by a single developer, and then shared with the others on the team. Tomcat is configured using xml files and properties files: Some settings to consider in server.xml ('#' means it's a default setting):

Some settings in context.xml:

Parallel deployment

Parallel deployment means you deploy two versions of the app side by side, with a version number in the name of the war file (myapp##001.war). Existing sessions continue to be handled by the old version of the app, while new sessions go to the new version of the app. Users migrate over from the old world to the new world, simply by logging in again. Of course, the idea is to have zero downtime during a production upgrade.

Things to consider:

Setting up HTTPS and SSL

Ideally, this should be done only once, by a single developer, and then just distributed to the others on the team.

Once you have a certificate in a local keystore file, edit server.xml, and add a second Connector, for use with SSL.

<Connector port="8443" protocol="org.apache.coyote.http11.Http11NioProtocol"
    maxThreads="150" SSLEnabled="true" scheme="https" secure="true"
    clientAuth="false" sslProtocol="TLS" keystoreFile="conf/mykeystorefile" keystorePass="changeIt"/>
The above Connector is a second Connector. You leave the existing non-SSL Connector in place. The non-SSL Connector will be used for apps that don't require SSL. In addition, if an app does require SSL, and a request URL for that app erroneously uses HTTP (and not HTTPS), then Tomcat will use the Connector.redirectPort setting of the non-SSL Connector, and the browser gets redirected to the secured Connector, running on a different port.

The keystoreFile path can be absolute; if relative, it's relative to $CATALINA_BASE. Self-signed certificates can be used only informally: they encrypt traffic, but they can't help with authentication or authorization. When you use them, your browser will give you a warning, and you'll need to explicitly instruct the browser to accept the certificate.

The default HTTPS port is 443, not 8443. A warning from the docs:
"special setup (outside the scope of this document) is necessary to run Tomcat on port numbers lower than 1024 on many operating systems [eg Linux]."

After you've finished configuring Tomcat for SSL, restart Tomcat, and navigate to a URL in your app (changing http to https).