Tomcat With No Context Path and Behind Apache

We develop locally using Eclipse and deploy to Tomcat 7 in AWS Elastic Beanstalk. Those who have already worked with AWS Elastic Beanstalk knows that once you deploy your WAR file, it will have not have a context path. For example, your web app’s root URL will look like http://webapp.com, instead of http://webapp.com/webapp/. Here we will mimic this setup on our local development environment. We have Apache running on port 80 and we want to keep it that way. We don’t want to change Tomcat to run on port 80.

1. Since we want to make our local look like production as much as possible, we will be using the URL http://local.webapp.com. Either configure local.webapp.com to point to 127.0.01 in your DNS provider, or just add 127.0.0.1 local.webapp.com to your hosts file. See %WINDIR%system32driversetchosts on Windows and /etc/hosts on Linux.

127.0.0.1 local.webapp.com

2. Edit Apache httpd.conf and enable mod_proxy and mod_proxy_http. On Apache 2.2, just uncomment these 2 lines.

LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_http_module modules/mod_proxy_http.so

3. Add the following at the end of the Apache httpd.conf file.

ProxyPass / http://local.webapp.com:8080/
ProxyPassReverse / http://local.webapp.com:8080/

You could also use an include file, instead of changing httpd.conf directly, for easier management. Create a file called conf/extra/webapp.conf under the Apache root directory, with the ProxyPass and ProxyPassReverse lines above. Then add this at the end of httpd.conf.

Include conf/extra/webapp.conf

4. Last piece of the puzzle is Tomcat. We remove the default context path and specify the proxy port. In Tomcat server.xml, change the context path from path=”webapp/” to “/”. If you run Tomcat from inside Eclipse, make sure you change that Tomcat install, which can be found under the Servers folder in Project Explorer. Then look for the Connector element with port=”8080″ and insert proxyPort=”80″. This tells Tomcat there’s a proxy in front of it.

...
<Connector port="8080" proxyPort="80" ... />

...
<Engine>
  <Context path="/" ... />
</Engine>

5. That should be it. Restart Apache and Tomcat and you should be able to go to http://local.webapp.com and see your web application in action.

If you would like to setup SSL, then here are the extra steps you need to take.

1. Enable SSL on Apache by editing httpd.conf and uncommenting these two lines.

LoadModule ssl_module modules/mod_ssl.so

Include conf/extra/httpd-ssl.conf

2. Install the certificate. You can use a real certificate or use a self signed one. How to get a certificate is out of scope for this post, but I’m sure there’s a lot of blog posts that can help you.

Once you have the certificate ready, rename the certificate to server.crt. If you got one, rename the intermediate certificate to server-ca.crt. If you got 2 intermediate certificates, combine them into one file. Also rename the private key used to generate the certificate to server.key. Place the renamed files server.crt, server-ca.crt and server.key in the Apache conf directory.

If you don’t like the idea of renaming your certificates, keep them as is and just make the filename changes inside httpd-ssl.conf.

3. In Tomcat server.xml, change the Connector element to use proxyPort=”443″ scheme=”https”, instead of the earlier proxyPort=”80″ change.

4. On 64-bit Windows, you might encounter the error:

SLSessionCache: Invalid argument: size has to be >= 8192 bytes

You can read more about this problem, and the solution, from the SSLSessionCache wiki page. If this is a local development environment, also try simply commenting out the SSLSessionCache and SSLSessionCacheTimeout lines in httpd-ssl.conf.

5. That’s it. Restart Tomcat and Apache and you should now be able to see your web application under https://local.webapp.com.

Here’s an extra tip. If you are running under Linux and want to block external access to port 8080, so you can only access your web application through Apache, you can run a few iptable commands. Here are the commands we use on Red Hat/CentOs.

iptables -A INPUT -p tcp -s IP_ADDRESS_HERE --dport 8080 -j ACCEPT
iptables -A INPUT -p tcp --dport 8080 -j DROP
service iptables save

Java Time API in JDK 8

The Java Time API is finally part of the early access releases of JDK 8. Most of us have been using Joda-Time, and soon we will have a nice Date and Time API built in Java. Here we’ll download JDK 8 build 75 and play around with the new API. If you wish to use an IDE with JDK 8, you can use the latest versions of IntelliJ or Netbeans. Eclipse does not support JDK 8 at this time.

Here are a few code snippets to help us quickly understand the new API. Note the package is java.time, and not javax.time.

Instant. An instantaneous point on the time-line. This is the closest equivalent to java.util.Date.

	Instant instant = Instant.now();
	System.out.println(instant.toString()); // prints 2013-02-08T18:47:15.937Z

LocalDate. A date without a time-zone in the ISO-8601 calendar system, such as 2000-12-31.

	LocalDate localDate = LocalDate.now();
	System.out.println(localDate.toString()); // prints 2013-02-08

LocalTime. A time without time-zone in the ISO-8601 calendar system, such as 12:30:00.

	LocalTime localTime = LocalTime.now();
	System.out.println(localTime.toString()); // prints 13:47:16.734

LocalDateTime. A date-time without a time-zone in the ISO-8601 calendar system, such as 2000-12-31T12:30:00.

	LocalDateTime localDateTime = LocalDateTime.now();
	System.out.println(localDateTime.toString()); // prints 2013-02-08T13:47:16.734

ZonedDateTime. A date-time with a time-zone in the ISO-8601 calendar system, such as 2000-12-31T12:30:00-05:00 America/New_York. This is the closest equivalent to java.util.GregorianCalendar.

	ZonedDateTime zonedDateTimeNow = ZonedDateTime.now();
	System.out.println(zonedDateTimeNow.toString()); // prints 2013-02-08T14:00:13.796-05:00[America/New_York]

Clock. A clock providing access to the current instant, date and time using a time-zone. If injected in code, simplifies testing as you can change the application clock without changing the system clock.

	Clock clock = Clock.systemUTC();
	long millis = clock.millis();
	System.out.println(millis);	// prints 1360348116109

Duration. A duration between two instants on the time-line, not tied to an instant.

	Duration duration = Duration.ofHours(1);
	System.out.println(duration.toString()); // prints PT3600S

Period. A period of time, in units meaningful to humans, such as ‘1 Year, 2 Months and 3 Days’.

	int year = 1, month = 2, days = 3;
	Period period = Period.ofDate(year, month, days);
	System.out.println(period.toString()); // prints P1Y2M3D

ZoneId. A time-zone ID, such as America/New_York.

	ZoneId zoneId = ZoneId.systemDefault();
	System.out.println(zoneId.toString()); // prints America/New_York

ZoneOffset. A time-zone offset from Greenwich/UTC, such as -05:00.

	ZoneOffset zoneOffset = ZoneOffset.ofHours(1);
	System.out.println(zoneOffset.toString()); // prints +01:00

Please note the Java API is still expected to change, until the official release of JDK 8 in October 2013.


Renewing GoDaddy SSL on AWS Elastic Beanstalk

We previously wrote about installing a GoDaddy SSL on AWS Elastic Beanstalk. Now it’s time to renew our certificate. You will need the file decrypted-private-key.pem from when we installed the certificate the first time.

1. Go to the GoDaddy Manage Certificates page, and renew the certificate. Once the certificate is ready, download the certificate. Unzip the downloaded file and you will get gd_bundle.crt and yourdomain.crt.

2. Last time, we used iam-servercertupload to upload the certificate. This time, we will use the AWS Management Console to upload, and make active, our renewed certificate. Go to Amazon EC2 Dashboard -> Load Balancers. Select your load balancer and go to the Listeners tab. Click Change in the SSL Certificate column and upload a new SSL certificate.

3. Enter the certificate name, private key, certificate and certificate chain. The certificate name should be unique, and since we called it yourcertificatename last time, we can now call it yourcertificatename2013. The private key is the contents of decrypted-private-key.pem. The certificate is the contents of yourdomain.crt. The certificate chain is the contents of gd_bundle.crt.

Renewing_GoDaddy_SSL_on_AWS_Elastic_Beanstalk

4. Save and choose the newly uploaded certificate.

That’s should be it. Verify the new certificate in your browser or use SSL Shopper’s SSL Checker.