As a part of my development work, I often need to work with customers with a wide variety of systems. Usually when someone is having an unusual problem I end up trying to replicate their environment as closely as possible to troubleshoot. So I thought I would share my process for installing Tomcat and Jetty and configuring each to use multiple versions of Solr (at the moment, just 3 and 4).
A little bit of background Solr is an open source search platform derived from the Apache Lucene project. It supports full-text search, highlighting, facets, rich document (e.g., Word, PDF) handling and more. It’s highly scalable and one of the most popular search platforms our there. Unlike Perl/PHP or ASP.NET and the web applications/frameworks based on them, Solr is written in Java. This means it can’t run on any old HTTP server; Solr needs a servlet container. Enter Tomcat and Jetty.
Both Tomcat (developed by ASF) and Jetty (developed by Eclipse) are cross-platform, “pure Java” HTTP servers and Java Servlet containers. Not only can they respond to requests like a regular HTTP server (Apache or IIS), but that they can extend the applications hosted by web servers, so they can be thought of as Java Applets that run on servers instead of in web browsers (see Wikipedia). One or the other (or an alternative like Resin or Glassfish) is needed in order to run Solr services. The nice thing about these servers is that they typically communicate over their own ports and not the HTTP standard of port 80. The consequence of this is that a developer or server admin can run Apache, Tomcat and Jetty side by side without worry. It also means that they don’t have to agonize over choosing just one.
Of course, most admins don’t want to have two servlet containers to do one job - run Solr. So which one to choose? Well, like everything on the Internet, that is a hotly-debated topic. I planned to make a comparison of pros and cons of each, but after an hour of Googling, I wasn’t able to find enough substantive differences for such a table. Let’s just say everyone’s a winner and move on.
Prerequisites
- Minimum Java Version: 1.5 (supports Tomcat 6, Jetty 7)
- Recommended Java Version: 1.7 (supports Tomcat 7, Jetty 9)
- Recommended OS: Ubuntu 12.04, or enough Linux knowledge to adapt these instructions to your own system
My dev machine is actually a laptop - a customized Acer V5 that actually runs faster and cooler than my desktop. It’s running Xfce on top of Ubuntu Server 12.04LTS. It utilizes a 1.33GHz processor, 8GB DDR3 RAM and a 256GB SSD drive. Not especially impressive or anything, but it works well for my purposes. For development and testing, it’s actually a bit overpowered; however, I wouldn’t trust these specs to a production machine. Make sure your server is capable of handling whatever load you intend to put on it.
Getting Java I checked my version of Java by running “java -version” and got “java version 1.6.0_27” in response. I want to be able to run both Tomcat 6 (which is more of an industy standard) AND Tomcat 7, which is ready for production but not yet as widespread. To do that, I needed at least Java 1.7. To get that, I ran:
sudo apt-get install openjdk-7-jre
This installed the OpenJDK Java environment next to the preexisting one, but version 1.6 was still the default. I fixed this by running “sudo update-alternatives –config java” and setting the default to OpenJDK 7. Now running “java -version” gives “java version 1.7.0_21,” which is perfect. This allows me to run both Tomcat 7 and Jetty 9.
Getting Tomcat Ubuntu Server 12.04 comes with Tomcat 6 preinstalled, but I want to be able to run Tomcat 7 as well. Tomcat 6 is more widely used at the moment, but it will eventually give way to Tomcat 7. I want any apps I build to be “future-proofed” by testing on both current and upcoming releases. Unfortunately, Ubuntu won’t let users install Tomcat 7 via apt-get due to a package dependency thing. Users have to remove tomcat6-common first, but doing so results in the complete removal of Tomcat 6. Basically, I can only manage one version with a package manager, but any other version will need to be managed manually. Oh well.
I decided to leave Tomcat 6 in place and simply install Tomcat 7 manually. I downloaded a tarball of Tomcat 7.0.40 from here and ran the following commands:
tar xvzf apache-tomcat-7.0.40.tar.gz
sudo mv apache-tomcat-7.0.40 /usr/share/tomcat7
This unpacked the tarball and moved it into the /usr/share directory next to the tomcat6 code. In order to manage it, I had to add an administrative user. So I ran sudo nano /usr/share/tomcat7/conf/tomcat-users.xml and added the following to the tomcat-users section:
<role rolename="manager-gui"/>
<user username="admin" password="mypassword" roles="manager-gui"/>
This created a manager account with a username of admin and a password of “mypassword” (not my real password, obvs). Finally, I had to point Tomcat to the java version I want to use. The java libraries are located in /usr/lib/jvm. I listed the contents of this directory and found the directory for OpenJDK 7, which is basically Java 1.7 (needed for Tomcat 7). I ran sudo nano /usr/share/tomcat7/bin/catalina.sh and added:
JAVA_HOME="/usr/lib/jvm/java-7-openjdk-amd64"
JRE_HOME="/usr/lib/jvm/java-7-openjdk-amd64/jre"
I want Tomcat 7 to be able to run alongside Tomcat 6 so I can check differences in performance easily. In order to do this, I need to reconfigure it to run on a different port. Turns out that part is pretty easy. I just ran “sudo nano /usr/share/tomcat7/conf/server.xml” and changed “Connector port=”8080”” to “Connector port=”8181”” Now Tomcat 6 will be on 8080 and Tomcat 7 will be on 8181. That’s not the only change, however; both Tomcat 6 and 7 rely on additional ports to operate. If these overlap, then one or neither of the servers will operate. To account for this, I scanned the Tomcat 7 server.xml for all references to ports and added 101 to each. This just gives me a consistent convention that I can revisit later if necessary.
The last thing is that I wanted to be able to manage Tomcat 7 as a service, like “sudo service tomcat7 restart” To do this, there needs to be a BASH script called tomcat7 in /etc/init.d/. The corresponding one for Tomcat 6 contains all manner of checks and variable setting. But since I already have the settings I want in /usr/share/tomcat7/conf/, it’s not really necessary for me. So, I simply ran “sudo nano /etc/init.d/tomcat7” and entered the following:
/usr/share/tomcat7/bin/catalina.sh run &> /var/log/tomcat7/catalina.log
echo "Starting Tomcat 7 Server"
I changed the permissions of this by running sudo chmod ugo+x /etc/init.d/tomcat7 so that it could execute and ran “sudo mkdir /var/log/tomcat7”. Basically, the script just launches Tomcat 7 using the supplied catalina.sh script and pushes all of the output to catalina.log. I then made the script executable so it could be accessed by service, and created the log file directory for Tomcat 7. This is really basic, but it works.
Finally, I ran:
sudo service tomcat6 restart
sudo service tomcat7 start
Everything indicated success, so I navigated to localhost:8080 and localhost:8181 to find the homepages of Tomcat 6 and Tomcat 7, respectively. Yay!
Getting Jetty For brevity, I’m only going to install Jetty 9, and I’m going to do it the manual way. The repositories for Ubuntu 12.04 offer Jetty 6.1, which is kind of ridiculous since, as of this writing, Jetty 6 has been considered depreciated for like a year. If I find I need to use Jetty 7 or 8, I’ll pretty much just repeat the process outlined below.
I downloaded Jetty 9 from Eclipse and extracted it to a folder called jetty-distribution-9.0.3.v20130506. I then moved the folder to the /usr/share directory so it could sit next to Tomcat: sudo mv jetty-distribution-9.0.3.v20130506 /usr/share/jetty9
I then created a user called jetty that will have control over anything and everything Jetty-related:
sudo useradd jetty -M -U -s /bin/false
sudo chown -R jetty:jetty /usr/share/jetty9
sudo usermod -u 140 jetty
The last line, usermod, sets the jetty user to UID 140; any UID values below 1000 are treated as “system users” and are not shown at login. This is mostly to keep my login experience “clean.” I then copied the Jetty script to run as a service, pretty much like I did with Tomcat 7:
sudo cp /usr/share/jetty9/bin/jetty.sh /etc/init.d/jetty9
Finally, I created the Jetty configuration flle in /etc/default/jetty9:
JAVA_HOME=/usr/java/default # Path to Java
NO_START=0 # Start on boot
JETTY_HOST=0.0.0.0 # Listen to all hosts
#JETTY_PORT=8085 # Run on this port. Depreciated in 9.0.3
JETTY_ARGS=jetty.port=8085 # Jetty 9.0.3+ port
JETTY_USER=jetty # Run as this user
I also had to go through /usr/share/jetty9/start.ini and add 202 to all the 8443 ports. 8443 is a port common to both Tomcat and Jetty, and is used for things like SSL. I added 202 (2 * 101) per my established convention, so that these ports are now 8645. This allows me to run Tomcat 6, Tomcat 7, and Jetty 9 simultaneously if I so desire. But it’s not strictly necessary to get things working.
That was pretty much it. I then started Jetty by running “sudo service jetty9 start” and it loaded up. I navigated to localhost:8085 and it came right up. Yay!
Setting up Solr I’m going to start by installing the latest version of Solr 3, which at the moment happens to be Solr 3.6.2, and Solr 4. Setting up multiple versions of Solr across different Java servlets can cause some weird permissions errors, so I am going to start by creating a group called “solr” and will make sure that all relevant files’ permissions map to this group. That way, things like solrconfig.xml can be accessed by the tomcat or jetty user simultanteously:
sudo groupadd solr
sudo usermod -G solr jetty
sudo usermod -G solr tomcat6
sudo chown -R jetty:solr jetty9/
sudo chown -R tomcat6:solr tomcat6/
sudo chown -R tomcat6:solr tomcat7/
sudo chown -R rob:solr solr-3.6.2/
Once this was done, I navigated to my trusty old /usr/share/ folder and ran wget to get the files I needed:
cd /usr/share
sudo wget http://www.bizdirusa.com/mirrors/apache/lucene/solr/3.6.2/apache-solr-3.6.2.tgz
sudo tar xvzf apache-solr-3.6.2.tgz
sudo rm apache-solr-3.6.2.tgz
sudo mv apache-solr-3.6.2 solr-3.6.2
To get Solr 3.6.2 going on Jetty, I had to download the Eclipse Java Compiler (ecj.jar) and put it in /usr/share/jetty9/lib/jsp, then add the following to /etc/default/jetty9:
JAVA_OPTIONS="-Dsolr.solr.home=/usr/share/solr-3.6.2/example/solr/conf $JAVA_OPTIONS "
JAVA_OPTIONS="-Dorg.apache.jasper.compiler.disablejsr199=true $JAVA_OPTIONS "
I then copied the solr.war file from to Jetty’s webapps directory. However, when I copied this, I made sure to call it “solr-3.6.2.war”; this allows me to access it by navigating to http://localhost:8085/solr-3.6.2/. The benefit here is that I can install multiple versions of Solr in the webapps directory and access them directly through the browser. I also used chown to set the permissions and allow the jetty user to access and run the WAR file:
sudo cp /usr/share/solr-3.6.2/example/webapps/solr.war /usr/share/jetty9/webapps/solr-3.6.2.war
sudo chown jetty:jetty /usr/share/jetty9/webapps/solr-3.6.2.war
My next step was to copy the Jetty configuration files into the Jetty folder:
sudo cp /usr/share/solr-3.6.2/example/etc/* /usr/share/jetty9/
sudo chown jetty:jetty /usr/share/jetty9/*
The last step was to copy the Solr configuration files (schema.xml, solrconfig.xml, etc) to /usr/share/jetty9/
sudo cp /usr/share/solr-3.6.2/example/solr/conf/schema.xml schema.xml
sudo cp /usr/share/solr-3.6.2/example/solr/conf/solrconfig.xml solrconfig.xml
sudo cp /usr/share/solr-3.6.2/example/solr/conf/stopwords.txt stopwords.txt
sudo cp /usr/share/solr-3.6.2/example/solr/conf/synonyms.txt synonyms.txt
sudo mkdir -p /var/lib/solr/sitename/data
sudo wget http://www.bizdirusa.com/mirrors/apache/lucene/solr/4.2.1/solr-4.2.1.tgz
sudo tar xvzf apache-solr-3.6.2.tgz
sudo rm apache-solr-3.6.2.tgz
sudo mv apache-solr-3.6.2 solr-3.6.2
sudo wget http://www.bizdirusa.com/mirrors/apache/lucene/solr/4.3.0/solr-4.3.0.tgz
sudo tar xvzf apache-solr-3.6.2.tgz
sudo rm apache-solr-3.6.2.tgz
sudo mv apache-solr-3.6.2 solr-3.6.2