about

nginx 1.2.4 SSL virtual hosting with upstream Tomcat 7 - 13 Oct 2012

search

Fact: fronting Tomcat or Jetty with any actual webserver will make page load times faster by caching most if not all non-servlet requests; mileage with vary, depends on caching/upstream config.

I chose to work with nginx, because of great experiences in the past. Unfortunately no mainline support for AJP. There is an addon module, nginx_ajp_module, but I just could not get it to compile with nginx 1.2.4, even after some hackish patching. Will have to fork and dig around with it further at some point.

the download/build/install

I use the --no-check-certificate option with wget because the AWS image bundling procedure eats .pem files on some of my boxes. The apt-get command should get you all the dependencies you need to compile nginx with everything except pcre-jit enabled.

wget http://nginx.org/download/nginx-1.2.4.tar.gz
tar xzvf nginx-1.2.4.tar.gz

wget --no-check-certificate https://github.com/gnosek/nginx-upstream-fair/tarball/master
mv master gnosek-nginx-upstream-fair.tar.gz
tar xzvf gnosek-nginx-upstream-fair.tar.gz

apt-get install build-essential libpcre++0 libpcre++-dev zlib1g-dev zlib1g openssl libssl-dev

cd nginx-1.2.4
./configure --add-module=../gnosek-nginx-upstream-fair-* --with-http_ssl_module
make
make install

the start-up config

For all your dependency-based Debian booting needs: /etc/init.d/nginx

#! /bin/sh
### BEGIN INIT INFO
# Provides: nginx
# Required-Start: $all
# Required-Stop: $all
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: starts the nginx web server
# Description: starts nginx using start-stop-daemon
### END INIT INFO

PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
DAEMON=/usr/local/nginx/sbin/nginx
NAME=nginx
DESC=nginx
test -x $DAEMON || exit 0
set -e

case "$1" in
start)
    echo -n "Starting $DESC: "
    start-stop-daemon --start --quiet --pidfile /usr/local/nginx/logs/nginx.pid --exec $DAEMON -- $DAEMON_OPTS
    
    echo "$NAME."
    ;;
stop)
    echo -n "Stopping $DESC: "
    start-stop-daemon --stop --quiet --pidfile /usr/local/nginx/logs/nginx.pid --exec $DAEMON
    
    echo "$NAME."
    ;;
restart|force-reload)
    echo -n "Restarting $DESC: "
    start-stop-daemon --stop --quiet --pidfile /usr/local/nginx/logs/nginx.pid --exec $DAEMON
    
    sleep 1
    
    start-stop-daemon --start --quiet --pidfile /usr/local/nginx/logs/nginx.pid --exec $DAEMON -- $DAEMON_OPTS
    
    echo "$NAME."
    ;;
reload)
    echo -n "Reloading $DESC configuration: "
    start-stop-daemon --stop --signal HUP --quiet --pidfile /usr/local/nginx/logs/nginx.pid --exec $DAEMON
    
    echo "$NAME."
    ;;
*)
    N=/etc/init.d/$NAME
    echo "Usage: $N {start|stop|restart|force-reload}" >&2
    
    exit 1
    ;;

esac
exit 0

the main nginx.conf

located at /usr/local/nginx/conf/nginx.conf

Please see the HttpCoreModule wiki page for more information about core directives. For additonal information about the directives to use with the HttpUpstreamFairModule.

#user nobody;
worker_processes 3; #make use of multiple cores efficiently

events {
    worker_connections 1024;
}

http {
    include mime.types;
    default_type application/octet-stream;
    
    sendfile on;
    tcp_nopush on;
    
    keepalive_timeout 2; #in seconds
    
    gzip on;
    
    client_max_body_size 2m; #handle <2MB media uploads
    
    proxy_connect_timeout 10s;
    proxy_read_timeout 40s; #max loading response for long AJAX processing time
    
    upstream dev {
        server 192.168.11.11:8081;
        server 192.168.21.21:8081;
        server 127.0.0.1:8081;
        fair;
    }
    
    upstream production {
        server 192.168.10.10:8080;
        server 192.168.20.20:8080;
        server 127.0.0.1:8080;
        fair;
    }
    
    include /usr/local/nginx/conf/nginx_host.conf;
}

the nginx_host.conf

For more on creating unified CRTs: https://www.startssl.com/?app=42

located at /usr/local/nginx/conf/nginx_host.conf

#redirect all HTTP requests not handled to HTTPS
server {
    listen 80 default;
    rewrite ^(.*) https://$host$1 permanent;
    access_log /dev/null;
    error_log /dev/null;
}

#production
server {
    ssl on;
    listen 443;
    server_name production.myservice.com;
    
    ssl_certificate /srv/tls/production-unified.crt;
    ssl_certificate_key /srv/tls/production.key;
    ssl_ciphers RC4:HIGH:!aNULL:!MD5;
    ssl_prefer_server_ciphers on;
    ssl_session_cache shared:SSL:10m;
    
    location = /favicon.ico {
        expires max;
        add_header Cache-Control public;
    }
    
    # serve static files
    location ~ ^/(css|images|javascript|js|script|style)/ {
        expires 2d;
    }
    
    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://production;
    }
    
    access_log /dev/null;
    error_log /dev/null;
}

#dev
server {
    ssl on;
    listen 443;
    
    server_name dev.myservice.com;
    ssl_certificate /srv/tls/dev-unified.crt;
    ssl_certificate_key /srv/tls/dev.key;
    ssl_ciphers RC4:HIGH:!aNULL:!MD5;
    ssl_prefer_server_ciphers on;
    ssl_session_cache shared:SSL:10m;
    
    location = /favicon.ico {
        expires max;
        add_header Cache-Control public;
    }
    
    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://dev;
    }
    
    access_log /dev/null;
    error_log /dev/null;
}

Please see Configuring HTTPS servers for more information on configuring nginx with HTTPS.

notes on HTTPS virtual hosting

Server Name Indication, which allows for TLS name-based virtual hosting (using different CRTs per virtual host) is not supported by all HTTPS clients or HTTPS servers. If you really want to host a bunch of HTTPS subdomains - *.yourdomain.com - purchase a wildcard SSL certificate. I ran into trouble getting Jenkins CI jobs kicked off from bitbucket commits because old versions of GNU Wget do not support TLS SNI. I know I am still waiting for the latest stable Debian release to include the GNU Wget update.


795 words. Post tags: Nginx, Tomcat, and SSL.

Post content is written by Jason Zerbe and licensed CC BY-NC 3.0.