Intro

To host Grails web
application Apache Tomcat is quite a natural choice. However a big part
of what is served are just static files (images, CSS, javascript code)
or rarely changed pages. Using Tomcat to serve all that stuff would be a
waste of resources, especially when running on small VPS like we do.
Nginx
is a small efficient web server that helps with this task. It can be
setup to both serve static files and act as reverse proxy to Tomcat
running the Grails application. Even more, it can cache some of the web
pages so that it sends less requests to Tomcat.
In this post I’ll highlight important parts of Nginx and Tomcat configuration files needed to achieve setup like this.

Nginx configuration

For Nginx configuration you can start from its default config file. Let’s add following to http section:

# Enable GZip compression gzip on; gzip_http_version 1.1; gzip_min_length 1000; gzip_buffers 16 8k; gzip_disable "MSIE [1-6] \."; gzip_types text/html text/css text/xml application/x-javascript application/atom+xml text/plain gzip_vary on; # Set proxy cache path proxy_cache_path /var/nginx/cache keys_zone=one:10m; # Main website Tomcat instance upstream main { server localhost:8080; }

This will enable GZip compression, set the path which we
want to use for cache and set the Tomcat instance to proxy requests
into.

Then it is needed to specify the configuration for the
particular server. For this example virtual domain names will be used to
define server (as it is most common case).

# iPad Sketchbook website server server { listen 80; server_name www.ipadsketchbook.com; # Redirect to appropriate language location = / { set_from_accept_language $lang en ru; rewrite ^/$ /$lang redirect; } location / { # Rewrite the URL for logged-in users if ($http_cookie ~* "JSESSIONID=([A-Z0-9]*)") { rewrite ^(.*)$ /loggedIn$1 last; } # Proxy all the requests to Tomcat proxy_pass http://main; proxy_set_header Host $http_host; proxy_cache one; proxy_cache_min_uses 1; proxy_cache_valid 200 302 1m; proxy_cache_valid 404 1m; proxy_cache_use_stale error timeout invalid_header http_500 http_502 http_503 http_504; } # Content for logged-in users should not be cached location /loggedIn { # Rewrite URL back before forwarding request to backend rewrite ^/loggedIn(.*)$ $1 break; proxy_pass http://main; proxy_set_header Host $http_host; if ($http_cookie !~* "JSESSIONID") { return 404; } } # Admin panel should not be cached location /admin { proxy_pass http://main/admin; proxy_set_header Host $http_host; } # Serve static resources location ~ ^/(images|css|js|google|yandex|y_key) { root /var/www/vhosts/ipadsketchbook.com/httpdocs; } error_page 404 /404.html; # redirect server error pages to the static page /50x.html # error_page 500 502 503 504 /50x.html; location = /50x.html { root html; } }

There are several tricks in the aforementioned config:

  • it redirects to appropriate language version based on request headers. It is only possible if you install nginx_accept_language_module.
  • it rewrites request path for users with existing session (based on JSESSIONID cookie), so that the pages served for them aren’t cached
  • it then rewrites back request path (for logged in users), when issuing request to Tomcat
  • there is a list of path prefixes for which static files are served

Of course most likely there should also be redirect from other domains set up. It is quite easy to do:

# Redirect all the iPhone Sketchbook website domains to main domain server { listen 80; server_name ipadsketchbook.com ipad-sketchbook.com www.ipad-sketchbook.com; rewrite ^(.*) http://www.ipadsketchbook.com$1 permanent; }

Tomcat configuration

Of
course in addition to configuring Nginx, Tomcat itself need to be
configured. This is quite straightforward though. Note that only single
domain name is configured, as other ones are redirected by Nginx.

So in server.xml we have such host configuration:

<Host name="www.ipadsketchbook.com" appBase="vhosts/ipadsketchbook.com" unpackWARs="true" autoDeploy="false" xmlValidation="false" xmlNamespaceAware="false"> </Host>

Note that autoDeploy is disabled, it is not needed on production server. appBase specifies the path to directory which contains applications’ WAR files. Root of the domain would be served by ROOT.WAR.

And more examples for configuration

Example 1.

server { listen 80; server_name YOUR_DOMAIN; root /PATH/TO/YOUR/WEB/APPLICATION; location / { index index.jsp; } location ~ \.do$ { proxy_pass http://localhost:8080; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header Host $http_host; } location ~ \.jsp$ { proxy_pass http://localhost:8080; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header Host $http_host; } location ^~/servlets/* { proxy_pass http://localhost:8080; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header Host $http_host; } }

Example 2.

server {
    listen myhost:80;
    server_name  myhost;
    location / {
        root /path/to/myapp/public;
        proxy_set_header X-Forwarded-Host $host;
        proxy_set_header X-Forwarded-Server $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 
        proxy_pass http://myapp:8080;
    }
}

And proxy pass by port

server { listen mysite.com:80; server_name mysite.com; root /path/to/tomcat/webapps/mysite/; location / { proxy_set_header X-Forwarded-Host $host; proxy_set_header X-Forwarded-Server $host; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_pass http://127.0.0.1:8082/; } }

The port 8082 is the one that Tomcat is listening to. This can be found in /path/to/tomcat/conf/server.xml

<Connector port="8082" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" />

It is also important that our Java web application is in root which
is http://127.0.0.1:8082/ instead of http://127.0.0.1:8082/mysite/ . We
can easily do this with adding a section to server.xml file inside
<Host> tag.

<Context path="" docBase="mysite" debug="0" reloadable="true">

Restaring  Tomcat and then Nginx at the end will make our web application available on the configured domain through port 80 .

Leave a Reply

Your email address will not be published. Required fields are marked *