Basic Apache Tomcat Features

Hello dear readers!

Apache Tomcat is open source software that implements the specifications Java Servlet, JSP And Java WebSocket thus providing a platform for running web applications written in Java. Developed and maintained by the Apache Software Foundation, Tomcat serves as a servlet container that allows web applications to use Java to create dynamic web pages.

Tomcat can run as a standalone web server, where it processes both static pages and dynamic requests via Servlets And JSP. However, Tomcat is often used in combination with traditional web servers such as Apache HTTP Server or Nginx to process static content, while dynamic content is processed through Tomcat.

In this article we will look at the main functionality of Tomcat.

Let's install

Download Apache Tomcat from the official website. Select the version suitable for the OS. After downloading, unpack the archive.

Open a terminal and go to the directory bin inside the unpacked Tomcat directory and run startup.sh (on Linux) or startup.bat (on Windows). If everything is done correctly, your server will come up and you will see the Tomcat welcome page by opening localhost:8080 in your browser.

Setting up Tomcat

File server.xmlmanages the entire configuration.

Let's look at the connector configuration, which is often used for HTTP/1.1:

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

maxThreads And minSpareThreads — parameters for optimization. Increase maxThreads allows you to process more parallel requests, but requires more resources.

To enhance security, you can make changes to the same file server.xmlrestricting access to certain functions:

<Valve className="org.apache.catalina.valves.RemoteAddrValve"
       allow="^.*[your-trusted-ip].*$" />

The setup ensures that only certain IP addresses are allowed to access your server.

Apache Tomcat uses JDBC connection pools to improve performance when working with the database. Example of setting up a connection pool in context.xml:

<Resource name="jdbc/YourDB" 
          auth="Container"
          type="javax.sql.DataSource"
          maxTotal="100"
          maxIdle="30"
          maxWaitMillis="10000"
          username="dbuser"
          password="dbpassword"
          driverClassName="com.mysql.jdbc.Driver"
          url="jdbc:mysql://localhost:3306/yourdb"/>

JMX is a standard that allows real-time monitoring and control of an application. To enable JMX in Tomcat, you will need to run it with certain JVM parameters:

-Dcom.sun.management.jmxremote
-Dcom.sun.management.jmxremote.port=12345
-Dcom.sun.management.jmxremote.ssl=false
-Dcom.sun.management.jmxremote.authenticate=false

Tomcat uses JULI, an extension to standard Java logging, but it can be integrated with cooler logging systems such as Log4j or SLF4J:

Adding a file log4j.properties in classpat.

We indicate log4j as a logging factory by adding the following JVM options when starting Tomcat:

-Dorg.apache.catalina.logging.log4j.Log4jContextFactory
-Dlog4j.configurationFile=path/to/log4j.properties

Tomcat performance directly depends on JVM settings. You can optimize some parameters:

Xmx и Xms: set the maximum and initial heap size respectively

-Xmx4G -Xms4G

XX:+UseG1GC: Enables G1 garbage collector

XX:+UseStringDeduplication: reduces the number of duplicate rows in the heap

Safety

Implementation of SSL/TLS for data protection

First you need a Keystore with a key and a certificate, this can be done keytoolbuilt into the JDK:

keytool -genkey -alias tomcat -keyalg RSA -keystore /path/to/your/keystore.jks

During the Keystore creation process, keytool will ask several identification questions. Remember your Keystore password; it will be needed later.

Open the file conf/server.xml and find the Connector configuration. Let's modify it to enable SSL as shown below:

<Connector port="8443" protocol="org.apache.coyote.http11.Http11NioProtocol"
           maxThreads="150" SSLEnabled="true" scheme="https" secure="true"
           clientAuth="false" sslProtocol="TLS" keystoreFile="/path/to/your/keystore.jks"
           keystorePass="your_keystore_password" />

We replace keystoreFile And keystorePass to the path to the Keystore and password, respectively.

Setting up security filters and CORS

Editing a file web.xml applications or global conf/web.xml in Tomcat to add a CORS filter:

<filter>
    <filter-name>CorsFilter</filter-name>
    <filter-class>org.apache.catalina.filters.CorsFilter</filter-class>
    <init-param>
        <param-name>cors.allowed.origins</param-name>
        <param-value>*</param-value>
    </init-param>
    <init-param>
        <param-name>cors.allowed.methods</param-name>
        <param-value>GET,POST,PUT,DELETE,OPTIONS</param-value>
    </init-param>
    <init-param>
        <param-name>cors.allowed.headers</param-name>
        <param-value>Content-Type,Authorization</param-value>
    </init-param>
</filter>
<filter-mapping>
    <filter-name>CorsFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

This is a basic CORS setup that allows requests from any origin. In production, of course, it is recommended to set more strict rules.

For additional application, you can use<security-constraint> V web.xml:

<security-constraint>
    <web-resource-collection>
        <web-resource-name>Protected Area</web-resource-name>
        <url-pattern>/*</url-pattern>
    </web-resource-collection>
    <auth-constraint>
        <role-name>user</role-name>
    </auth-constraint>
    <user-data-constraint>
        <transport-guarantee>CONFIDENTIAL</transport-guarantee>
    </user-data-constraint>
</security-constraint>

All requests will now require authentication and use of SSL.

Secure headers

You can add secure HTTP headers using a filter web.xml:

<filter>
    <filter-name>HttpHeaderSecurityFilter</filter-name>
    <filter-class>org.apache.catalina.filters.HttpHeaderSecurityFilter</filter-class>
    <init-param>
        <param-name>antiClickJackingOption</param-name>
        <param-value>SAMEORIGIN</param-value>
    </init-param>
    <init-param>
        <param-name>xssProtectionOption</param-name>
        <param-value>1; mode=block</param-value>
    </init-param>
</filter>
<filter-mapping>
    <filter-name>HttpHeaderSecurityFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

Also, do not forget to limit access to /manager And /host-manager with strict rules in conf/tomcat-users.xml.

Scaling

Configuring Tomcat Clusters

Clustering in Tomcat is the process of combining multiple Tomcat instances to process requests to the same web application as a single unit.

All Tomcat instances on different servers must have the same web application version and configuration.

In file conf/server.xml Each Tomcat instance will need to be configured with a cluster. Insert the following snippet into the element <Engine>:

<Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster"/>

This configuration enables a clustering mechanism using a simple TCP cluster.

Load balancing with Apache HTTP or Nginx

You can use Apache HTTP Server or Nginx as a reverse proxy to distribute incoming requests among Tomcat cluster nodes.

Setting up Apache HTTP with mod_jk:

Need to install mod_jk and configure workers.properties to specify cluster nodes:

worker.list=loadbalancer
worker.tomcat1.type=ajp13
worker.tomcat1.host=server1.example.com
worker.tomcat1.port=8009
worker.tomcat2.type=ajp13
worker.tomcat2.host=server2.example.com
worker.tomcat2.port=8009
worker.loadbalancer.type=lb
worker.loadbalancer.balance_workers=tomcat1,tomcat2

Add the configuration to httpd.conf to redirect requests to the balancer:

LoadModule jk_module modules/mod_jk.so
JkWorkersFile conf/workers.properties
JkMount /* loadbalancer

In the Nginx configuration file (nginx.conf) you need to define an upstream for Tomcat nodes and configure the server to redirect requests:

upstream tomcat_cluster {
    server server1.example.com:8080;
    server server2.example.com:8080;
}

server {
    listen 80;

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

Session replication and sticky sessions

In clustered environments, session replication keeps session data synchronized between nodes.

In file conf/server.xml add cluster configuration with DeltaManager for session replication:

<Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster">
    <Manager className="org.apache.catalina.ha.session.DeltaManager"
             expireSessionsOnShutdown="false"
             notifyListenersOnReplication="true"/>
    <!-- можно включить прочие настройки кластера и канала -->
</Cluster>

DeltaManager replicates only changes in the session, making replication resource efficient.

Sticky sessions allow you to “stick” a user session to a specific server to ensure data consistency. In Apache or Nginx this is achieved through the balancer settings.

Nginx:

http {
    upstream backend {
        server backend1.example.com;
        server backend2.example.com;
        sticky;
    }

    server {
        location / {
            proxy_pass http://backend;
        }
    }
}

Apache HTTP Server with mod_proxy_balancer:

<Proxy "balancer://mycluster">
    BalancerMember "http://backend1.example.com" route=1
    BalancerMember "http://backend2.example.com" route=2
    ProxySet stickysession=JSESSIONID
</Proxy>

ProxyPass / balancer://mycluster/
ProxyPassReverse / balancer://mycluster/

Apache ZooKeeper

ZooKeeper can be used to manage the configuration and state of a cluster.

Let's install ZooKeeper on a separate server or group of servers and create a configuration file conf/zoo.cfg with basic settings:

tickTime=2000
dataDir=/var/lib/zookeeper
clientPort=2181
initLimit=5
syncLimit=2
server.1=zk1.example.com:2888:3888
server.2=zk2.example.com:2888:3888

For integration you can Apache Curator. Let's register the node:

CuratorFramework client = CuratorFrameworkFactory.newClient(zookeeperConnectionString, new ExponentialBackoffRetry(1000, 3));
client.start();

String path = "/tomcat/nodes/" + nodeId;
byte[] payload = "Some node data".getBytes();

client.create().creatingParentsIfNeeded().forPath(path, payload);

The code creates a node in ZooKeeper for each Tomcat instance.

Integrating Apache Tomcat with web servers

Integration with Tomcat is often done using a module mod_jkwhich allows the HTTP Server to communicate with Tomcat via AJP.

Let's install mod_jk and download the corresponding OS binary file or build it from source, and then add it to the Apache configuration:

LoadModule jk_module modules/mod_jk.so

File workers.properties defines how the server will interact with Tomcat instances. Let's create this file and configure the worker in it:

worker.list=worker1
worker.worker1.type=ajp13
worker.worker1.host=localhost
worker.worker1.port=8009

IN httpd.conf or in a separate configuration file we will add an indication of workers.properties and configure routing:

JkWorkersFile /path/to/your/workers.properties
JkMount / worker1

This will redirect all requests to Apache HTTP Server to Tomcat via AJP.


You can get more practical skills in application architecture as part of practical online courses from industry experts.

Similar Posts

Leave a Reply

Your email address will not be published. Required fields are marked *