NGINX SSL Load Balancing with Liferay

Today I was trying to enable SSL with NGINX as Load Balancer for a demo Liferay cluster, I thought to share my experiences on how I did that with this small post. I am skipping the certificate generation where I followed standard openssl ways for a self signed certificates.

This simple setup I had NGINX server handles all SSL traffic from the outside world , post SSL termination it hands over the requests to Liferay which is DMZ listening over HTTP.

To start with I did create a nginx.conf called liferaysp.example.com with the following configurations, though there are many configuration options we can today in real world I tried to set up a very basic configuration.

upstream liferay {
    ip_hash;
    server 192.168.100.1:8080;
    server 192.168.100.2:8080;
}

log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                     '$status $body_bytes_sent "$http_referer" '
                     '"$http_user_agent" "$http_x_forwarded_for"';

server {
  listen 443;
  server_name liferaysp.example.com;
  access_log  /var/log/nginx/liferaysp.example.com.log  main;

  ssl on;
  ssl_certificate /etc/nginx/ssl/liferaysp.example.com/server.crt;
  ssl_certificate_key /etc/nginx/ssl/liferaysp.example.com/server.key;
  ssl_session_cache shared:SSL:10m;

  ssl_session_timeout 5m;

  ssl_protocols SSLv3 TLSv1 TLSv1.1 TLSv1.2;
  ssl_ciphers "HIGH:!aNULL:!MD5 or HIGH:!aNULL:!MD5:!3DES";
  ssl_prefer_server_ciphers on;

  location / {

     proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
     proxy_set_header Host $http_host;
     proxy_set_header X-Forwarded-Proto https;
     proxy_redirect off;
     proxy_connect_timeout 240;
     proxy_send_timeout 240;
     proxy_read_timeout 240;     

     proxy_pass http://liferay;
  }

}

Once the NGINX server is up and running, my next step was to configure Liferay to handle the proxy offloading, 

To have Liferay + NGINX SSL quickly up and running I did the following changes to Liferay’s portal-setup-wizard.properties

web.server.https.port=443
web.server.protocol=https
web.server.host=liferaysp.example.com

Then when I booted up the Liferay server, I could see the server available over https://liferaysp.example.com ( I did a /etc/hosts entry for liferaysp.example.com to my NGINX server IP)

But this will cause inconsistencies when you want to integrate Liferay with external systems, and typically those systems expect Liferay to send and receive over HTTPS e.g SAML SSO integration as the portal-setup-wizard settings are visible only for Liferay Application which can return the property HTTP scheme via web.server.protocol and request server name via web.server.host and make the request.isSecure() method return true, but when I tried to hook my server to an IdP going by my SAML SSO integration example my integration broke as the other integrated applications likeorg.opensamlwill always get therequest.getScheme()ashttpandrequest.isSecure()asfalse`, the simple reason being those rely on the application server’s, in my case tomcat’s settings.

To overcome this inconsistency we can can skip doing changes to portal-ext and do the following changes at the application server level, in case of Tomcat we need to configure the Tomcat connector(s) $LIFERAY_TOMCAT_HOME/conf/server.xml 

<Connector port=”8080” protocol=”HTTP/1.1connectionTimeout=”20000” redirectPort=”8443” URIEncoding=”UTF-8” proxyPort=”443” proxyName=”liferaysp.example.com“ scheme=”https” secure=”true”/>

Voila! Now my Liferay will be able to use HTTPS scheme though its content are served over HTTP with NGINX handling the SSL load.

 
Blogs
Very good article!
But you should get rid of SSLv3. Please see RFC7568 for reference.

A better configuration is therefore:
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;

This site is quite good if you need strong ssl/cipher configuration:
https://cipherli.st/

To test the ssl config, http://ssllabs.com/ is very useful. While the grade is always capped to F if you use a selfsigned cert, you can still look at the details and recommendations.

For productive environments a lot further things are recommended to do like specifying better DH parameters (ssl_dhparam) or enabling SSL stapling (performance) and possibly adding HSTS. For performance, adding a proxy_cache for themes (css/images) works nicely.

Also, I'd recommend that nginx does the compression and the zip filter in Liferay is disabled.
a very important point which will be appreciated if you create a blog for this! especially mapping (css/images) with theme level and portlet level and the rest of configuration you can add here as a comment
Great posts, this works for my custom portlets, but not for my custom theme. Any help welcomed.