I recently had to configure HTTPS on a wildcard subdomain with Apache HTTP server as reverse proxy to a Tomcat backend. I had few more requirements:
- Redirect all http traffic to https and preserve the subdomain (hostname). For instance:
- http://sub1.example.com/ -> redirect to -> https://sub1.example.com/
- http://sub2.example.com/ -> redirect to -> https://sub2.example.com/
- etc.
- I want to have a PHP wiki on the subdirectory
/wiki
and I want to send the rest of the traffic to Tomcat. - Tomcat needs to know the subdomain (hostname) and will serve content accordingly.
- I don’t know the subdomains in advance because they are chosen by users, just like *.wordpress.com
Few parts were not trivial, so I will share my setup.
DNS Wildcard Subdomain Configuration
DNS is probably the easiest part. Nowadays, most domain registrar offer good DNS support for free with your domain. If that is not the case of your registrar, you may want to consider namecheap. Their DNS also support wildcard entries. Otherwise, you can use the popular Bind DNS server. Here is how to configure a wildcard entry in BIND. Change 55.55.55.55 with your IP address.
* IN A 55.55.55.55
Apache Wildcard Subdomain Configuration
This was trickier. The Apache HTTP server configuration has 2 main parts.
- HTTP (port 80): We use mod_rewrite to redirect all traffic for *.example.com to https (port 443) and we preserve the hostname with the %{HTTP_HOST} variable.
- HTTPS (port 443): Except for the PHP subdirectory (/wiki), we reverse proxy all traffic to Tomcat, which listen on port 9090 of localhost.
# Allow non-SNI clients
SSLStrictSNIVHostCheck off
# HTTP configuration
<VirtualHost *:80>
ServerName example.com
# Wildcard subdomain
ServerAlias *.example.com
ServerAdmin info@example.com
# Permanent redirect (301) to HTTPS and preserve
# hostname (but do not preserve path)
RewriteEngine On
RewriteRule .* https://%{HTTP_HOST}/? [R=301,L]
</VirtualHost>
# HTTPS configuration
<VirtualHost *:443>
ServerName example.com
# Wildcard subdomain
ServerAlias *.example.com
ServerAdmin info@example.com
# PHP Wiki on path /wiki
Alias /wiki /opt/example.com/php/wiki
<Directory /opt/example.com/php/wiki>
AllowOverride All
Require all granted
</Directory>
# Reverse proxy everything to Tomcat except for /wiki
ProxyRequests Off
ProxyPass /wiki !
ProxyPass / http://localhost:9090/
ProxyPassReverse / http://localhost:9090/
# Logs
ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
# Wildcard SSL/TLS Certificate files
SSLEngine on
SSLCertificateFile /etc/ssl/certs/STAR_example_com.crt
SSLCertificateKeyFile /etc/ssl/private/example.key
SSLCertificateChainFile /etc/ssl/certs/example.ca-bundle
# Standard script config
<FilesMatch "\.(cgi|shtml|phtml|php)$">
SSLOptions +StdEnvVars
</FilesMatch>
<Directory /usr/lib/cgi-bin>
SSLOptions +StdEnvVars
</Directory>
# Standard config for Internet Explorer
BrowserMatch "MSIE [2-6]" \
nokeepalive ssl-unclean-shutdown \
downgrade-1.0 force-response-1.0
BrowserMatch "MSIE [17-9]" ssl-unclean-shutdown
</VirtualHost>
Tomcat Wildcard Subdomain Configuration
Below you’ll find the configuration of Tomcat (in server.xml), which is quite standard. Actually, we do not need to define any “wildcard”, we just define a defaultHost
in the Engine
element. Then we deploy a ROOT.war
in the webapps directory (/opt/example.com/tomcat7/webapps
) to serve all content at the root context path.
<Service name="example">
<Connector port="9090" protocol="HTTP/1.1" connectionTimeout="20000"
URIEncoding="UTF-8" />
<Engine name="example" defaultHost="localhost">
<Host name="localhost" appBase="/opt/example.com/tomcat7/webapps"
unpackWARs="true" autoDeploy="true">
<Valve className="org.apache.catalina.valves.AccessLogValve"
directory="logs" prefix="example.com_access_log."
suffix=".txt" pattern="%h %l %u %t "%r" %s %b" />
</Host>
</Engine>
</Service>
How does Tomcat Know the Subdomain?
With this configuration, all content will be sent to Tomcat with “localhost” as the hostname. Fortunately, the Apache reverse proxy will send extra request headers to Tomcat, namely:
X-Forwarded-For
: The IP address of the client.X-Forwarded-Host
: The original host requested by the client in the Host HTTP request header.X-Forwarded-Server
: The hostname of the proxy server.
So in Tomcat (or any other servlet container), just use the Java code below to get the value of that header X-Forwarded-Host
and you’ll know the subdomain.
String subdomain = request.getHeader("X-Forwarded-Host");
Alternatively, you may also use the ProxyPreserveHost On directive in Apache configuration and you should be able to get the hostname (subdomain) normally in Tomcat. NOTE: I haven’t tested that setup.
String subdomain = request.getServerName();
Bonus: Wildcard SSL Certificate
Of course you’ll need a wildcard SSL certificate. Those are usually very expensive, but Namecheap resells Comodo wildcard certificate at very good price. No, I do not have any interest in namecheap, they just happen to be very good at what they do 🙂
Author: Jonathan Demers