AJP Connector Configuration and Security
AJP (Apache JServ Protocol) is a high-speed binary protocol between Apache HTTPD and Tomcat. This chapter covers how AJP works, the latest security settings (Ghostcat vulnerability mitigation), and when to use AJP vs. the modern alternative.
AJP Protocol Overview
AJP is a binary protocol designed for communication between a web server (Apache HTTPD) and a WAS (Tomcat).
[Client] ← HTTP/HTTPS → [Apache HTTPD :80/443]
↓ AJP (binary)
[Tomcat :8009]
↓
[Java Web Application]
HTTP Proxy vs AJP Comparison
| Item | HTTP Proxy | AJP |
|---|---|---|
| Protocol | HTTP (text) | Binary |
| Performance | Moderate | High (less parsing overhead) |
| Configuration | Simple | Medium complexity |
| Security issues | Standard HTTP security | Ghostcat vulnerability |
| Current recommendation | Recommended | Legacy systems only |
Modern recommendation: For new systems, use HTTP proxy (
mod_proxy_http) instead of AJP. AJP is a legacy approach for Apache+Tomcat setups.
Ghostcat Vulnerability (CVE-2020-1938)
Ghostcat, discovered in February 2020, is a critical vulnerability that allows reading arbitrary files within a Tomcat web application via the AJP connector.
Affected Versions
| Tomcat Version | Vulnerable | Patched |
|---|---|---|
| Tomcat 9 | 9.0.0.M1 ~ 9.0.30 | 9.0.31+ |
| Tomcat 8.5 | 8.5.0 ~ 8.5.50 | 8.5.51+ |
| Tomcat 7 | 7.0.0 ~ 7.0.99 | 7.0.100+ |
Remediation Options
Option 1: Disable AJP Connector (safest)
<!-- server.xml — Comment out the AJP connector -->
<!-- <Connector port="8009" protocol="AJP/1.3" redirectPort="8443"/> -->
Option 2: Enforce secretRequired (when AJP is necessary)
<Connector protocol="AJP/1.3"
address="127.0.0.1"
port="8009"
redirectPort="8443"
secretRequired="true"
secret="MyS3cr3tAJPK3y!2024"/>
Option 3: Restrict access by IP
<Connector protocol="AJP/1.3"
address="127.0.0.1" <!-- localhost only -->
port="8009"
redirectPort="8443"
secretRequired="true"
secret="MyS3cr3tAJPK3y!"/>
AJP Connector Configuration (with Security)
Tomcat Configuration
<!-- server.xml -->
<Connector protocol="AJP/1.3"
address="127.0.0.1"
port="8009"
redirectPort="8443"
maxThreads="150"
minSpareThreads="5"
connectionTimeout="10000"
secretRequired="true"
secret="YourSecureSecretHere"
allowedRequestAttributesPattern=".*"/>
| Attribute | Description | Secure Setting |
|---|---|---|
address | Listening IP | 127.0.0.1 (local only) |
port | AJP port | 8009 (default) |
secretRequired | Require secret | true |
secret | Shared secret | Strong random string |
allowedRequestAttributesPattern | Allowed request attribute patterns | Allow only what's needed |
Apache HTTPD Configuration (mod_proxy_ajp)
# Enable required modules
sudo a2enmod proxy
sudo a2enmod proxy_ajp
sudo systemctl reload apache2
# /etc/apache2/sites-available/myapp.conf
<VirtualHost *:80>
ServerName example.com
ProxyRequests Off
ProxyPreserveHost On
# AJP proxy (with secret)
<Proxy "ajp://localhost:8009/?secret=YourSecureSecretHere">
Require all granted
</Proxy>
ProxyPass / ajp://localhost:8009/?secret=YourSecureSecretHere
ProxyPassReverse / ajp://localhost:8009/?secret=YourSecureSecretHere
</VirtualHost>
AJP vs HTTP Proxy — When to Use Which
Use HTTP Proxy (Recommended)
# Using mod_proxy_http (recommended)
ProxyPass /api/ http://localhost:8080/api/
ProxyPassReverse /api/ http://localhost:8080/api/
# Advantages:
# - Simple configuration
# - Easier SSL/TLS termination management
# - No Ghostcat vulnerability
# - Compatible with various load balancers
When AJP Has Advantages
- Must maintain very legacy Apache+Tomcat configurations
- Internal environments with extremely limited network bandwidth
- During gradual migration away from
mod_jk(old AJP module)
Migrating from mod_jk to mod_proxy_ajp
If you're using the old mod_jk, switching to mod_proxy_ajp is recommended.
# Old mod_jk configuration (legacy)
# LoadModule jk_module modules/mod_jk.so
# JkWorkersFile /etc/httpd/conf/workers.properties
# JkMount /* worker1
# Replacement: mod_proxy_ajp
LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_ajp_module modules/mod_proxy_ajp.so
ProxyPass / ajp://localhost:8009/?secret=MySecret
ProxyPassReverse / ajp://localhost:8009/?secret=MySecret
Verifying AJP Connector Status
# Check AJP port listening
ss -tlnp | grep 8009
# Check Tomcat logs for AJP messages
tail -f /opt/tomcat/latest/logs/catalina.out | grep -i ajp
Complete Secure Configuration Example
Tomcat server.xml (AJP disabled — recommended)
<?xml version="1.0" encoding="UTF-8"?>
<Server port="-1" shutdown="SHUTDOWN">
<Service name="Catalina">
<!-- HTTP connector only -->
<Connector port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443"
address="127.0.0.1"/>
<!-- AJP disabled (Ghostcat prevention) -->
<!--
<Connector protocol="AJP/1.3"
address="127.0.0.1"
port="8009"
redirectPort="8443"
secretRequired="true"
secret="ChangeMe!"/>
-->
<Engine name="Catalina" defaultHost="localhost">
</Engine>
</Service>
</Server>
Apache HTTPD (HTTP proxy approach)
<VirtualHost *:443>
ServerName example.com
SSLEngine on
SSLCertificateFile /etc/letsencrypt/live/example.com/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/example.com/privkey.pem
ProxyRequests Off
ProxyPreserveHost On
# HTTP proxy (recommended over AJP)
ProxyPass / http://127.0.0.1:8080/
ProxyPassReverse / http://127.0.0.1:8080/
RequestHeader set X-Forwarded-Proto "https"
RequestHeader set X-Forwarded-For "%{REMOTE_ADDR}s"
</VirtualHost>
Summary
| Item | Recommended Setting |
|---|---|
| Ghostcat mitigation | Disable AJP connector (comment out) |
| Unavoidable AJP use | secretRequired="true" + strong secret |
| AJP listen address | address="127.0.0.1" (local only) |
| New systems | HTTP proxy (mod_proxy_http) recommended |
Legacy mod_jk | Migrate to mod_proxy_ajp |