Traditionally, I used to go with Apache, Mod Jk and Tomcat to host any Java web apps. But this time I was working on a small hobby project written in Groovy on Grails and had to deploy it to a VPS with a very limited resources. So I had to make the most of the server configuration that I had. So I went with a combination of Nginx and Jetty.
If you’ve never heard of Nginx, it is a very simple HTTP server that is known for its high-performance, low and predictable resource consumption and low memory footprint under load. It uses an asynchronous even-driven model to handle requests which enables it to efficiently handle a large no of requests concurrently.
Similarly, Jetty provides a very good Java Servlet Container. Jetty can be used either as a Standalone application server or can be embedded into an application or framework as a HTTP Component or a servlet engine. It servers as a direct alternative to Tomcat in many cases. Because of its use of advanced NIO and small memory footprint, it provides very good scalability.
Below, I will jot down the steps I went through to configure Nginx as a frontend to Jetty on my VPS running Ubuntu Hardy.
Install Java:
$sudo apt-get install openjdk-6-jdk $ java -version java version "1.6.0_0" OpenJDK Runtime Environment (build 1.6.0_0-b11) OpenJDK 64-Bit Server VM (build 1.6.0_0-b11, mixed mode) $ which java /usr/bin/java
Install Jetty:
Download the latest version of Jetty, and upload the tar file to your directory of chose on your server.
$ scp jetty-6.1.22.tar user@sacharya.com:/user/java
Now login to your server, go to the directory where you uploaded Jetty above.
$ cd /user/java $ tar xvf jetty-6.1.22.tar
Now you can start or stop the Jetty server using the following commands:
$ cd /user/java/jetty-6.1.22/bin $./jetty.sh start
ps aux | grep java root 21766 1.2 72.4 1085176 387196 ? Sl Mar27 1:12 /usr/lib/jvm/java-6-openjdk/ /bin/java -Djetty.home=/user/java/jetty-6.1.22 -Djava.io.tmpdir=/tmp -jar /user/java/jetty-6.1.22/start.jar /user/java/jetty-6.1.22/etc/jetty-logging.xml /user/java/jetty-6.1.22/etc/jetty.xml
The jetty logs are under jetty-6.1.22/logs if you are interested.
Open up your bash profile and set the following paths:
$ vi ~/.bash_profile JAVA_HOME=/usr/lib/jvm/java-6-openjdk/ JETTY_HOME=/user/java/jetty-6.1.22/ PATH=$JETTY_HOME/bin:$PATH export JAVA_HOME JETTY_HOME
Now that Jetty is running, you can go the its default port 8080 and verify that everything is working as expected.
Now that you have Jetty, its time to deploy your app to the Jetty container.
$ scp myapp.war root@sacharya.com:/user/java/jetty-6.1.22/webapps $ tar -xvf myapp.war
$ vi /user/java/jetty-6.1.22/contexts/myapp.xml
<?xml version="1.0"?> <!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://jetty.mortbay.org/configure.dtd"> <Configure class="org.mortbay.jetty.webapp.WebAppContext"> <Set name="configurationClasses"> <Array type="java.lang.String"> <Item>org.mortbay.jetty.webapp.WebInfConfiguration</Item> <Item>org.mortbay.jetty.plus.webapp.EnvConfiguration</Item> <Item>org.mortbay.jetty.plus.webapp.Configuration</Item> <Item>org.mortbay.jetty.webapp.JettyWebXmlConfiguration</Item> <Item>org.mortbay.jetty.webapp.TagLibConfiguration</Item> </Array> </Set> <Set name="contextPath">/</Set> <Set name="resourceBase"><SystemProperty name="jetty.home" default="."/>/webapps/myapp</Set> </Configure>
Restart jetty and go to http://ipAddress:8080/myapp, and you should be getting your app.
Install Nginx:
$ sudo aptitude install nginx
This will install Nginx under /etc/nginx
You can start, stop or restart the Nginx server using the commands:
$ sudo /etc/init.d/nginx start $ sudo /etc/init.d/nginx stop $ sudo /etc/init.d/nginx restart
Go to your server ip address (or locahost of local) in your browser, and you should be able to see the default welcome page.
Nginx Proxy to Jetty:
Now, lets point configure Nginx as a proxy to our Jetty Server:
$ cd /etc/nginx/sites-available
$ vi default
Point your proxy_pass to:
location / {
proxy_pass http://127.0.0.1:8080;
}
Basically, nginx listens on port 80 and forwards it to port 8080. Jetty sets anything on / to /webapps/myapp which means any request to http://127.0.0.1 from nginx is served from http://127.0.0.1:8080/myapp.
Now if you type your IP address or domain name in the browser, content will be served from your application in Jetty. Right now, you are serving everything through Jetty including the scatic files like images, javascript and css. But you can easily serve the static files directly through Nginx: Just add a couple of locations in there:
location /images {
root /user/java/jetty-6.1.22/webapps/myapp;
}
location /css {
root /user/java/jetty-6.1.22/webapps/myapp;
}
location /js {
root /user/java/jetty-6.1.22/webapps/myapp;
}
My final configuration is:
server {
listen 80;
server_name sacharya.com;
access_log /var/log/nginx/localhost.access.log;
location / {
proxy_pass http://127.0.0.1:8080;
}
location /images {
root /user/java/jetty-6.1.22/webapps/myapp;
}
location /css {
root /user/java/jetty-6.1.22/webapps/myapp;
}
location /js {
root /user/java/jetty-6.1.22/webapps/myapp;
}
# redirect server error pages to the static page /50x.html
#
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /var/www/nginx-default;
}
}
Instead of specifying the location of static resources, you can use a regular expression for the files. Here’s the same Nginx.conf you have above, but simplified. This assumes that you will not be doing a request to your servlets that end in any of the file extensions listed below.
[code lang='text']
server {
listen 80;
server_name sacharya.com;
access_log /var/log/nginx/localhost.access.log;
root /user/java/jetty-6.1.22/webapps/myapp;
location / {
proxy_pass http://127.0.0.1:8080;
}
# Static files location
location ~* ^.+.(jpg|jpeg|gif|png|ico|css|zip|tgz|gz|rar|bz2|doc|xls|exe|pdf|ppt|txt|tar|mid|midi|wav|bmp|rtf|js|mov|avi|wmv|mp3)$ {
break;
}
# redirect server error pages to the static page /50x.html
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /var/www/nginx-default;
}
}
[/code]
It is even better to reload nginx than restart it (wont disturb any visitors as much). This can be done by issuing:
$ sudo /etc/init.d/nginx reload