Play Framework 2 in production: HTTPS using nginx

by Chris

If you provide some sort of user login on your page, you’ll probably want to use HTTPS/SSL. Play Framework 2 supports secure connections using the recommended setup with a reverse proxy such as nginx.

This means your application server will run your play framework application on a private port (the default is 9000), as well as an nginx web server which listens to the public ports (HTTP/80 and HTTPS/443), and redirects those requests back to your play app.

Nginx Configuration for HTTPS

Installing nginx on most linux distributions is usually a one-liner (please refer to the nginx documentation). Here is the configuration we use for setting up nginx as the reverse proxy. In this example we assume that your domain name is example.com and that your compiled Play application files (using play dist) are located in /var/example/target.

UPDATE: The some paths may have changed for Play Framework 2.3+ and later. See comments.

Nginx config file: /etc/nginx/sites-available/default

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
# Redirect everything to HTTPS and all subdomains to example.com
server {
    listen 80;
    example.com *.example.com;
    rewrite ^ https://example.com$request_uri? permanent;
}
 
# HTTPS server
server {
    listen 443;
    server_name example.com;
 
    # play public assets
    root /var/example/target/scala-2.10/classes/public;
 
    # SSL configuration
    ssl on;
    ssl_certificate /var/example/target/deployment/example_com.pem;
    ssl_certificate_key /var/example/target/deployment/example_com.key;
 
    ssl_session_timeout 5m;
 
    ssl_protocols SSLv3 TLSv1;
    ssl_ciphers ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv3:+EXP;
    ssl_prefer_server_ciphers on;
 
    # static content (with client-side caching enabled)
    location /assets/ {
       access_log  off;
       log_not_found off;
       add_header  Pragma "public";
       add_header  Cache-Control "public";
       expires     30d;
       alias /var/example/target/scala-2.10/classes/public/;
    }
 
    # serve assets or request page from proxy (if asset not found)
    location / {
       try_files $uri @proxy;
    }
 
    # the play web server
    location @proxy {
       proxy_pass  http://localhost:9000;
       proxy_redirect off;
       proxy_buffering off;
 
       #send protocol info to play server
       proxy_set_header        Host               $host;
       proxy_set_header        X-Real-IP          $remote_addr;
       proxy_set_header        X-Forwarded-Proto  https;
       proxy_set_header        X-Forwarded-Ssl    on;
       proxy_set_header        X-Forwarded-For    $proxy_add_x_forwarded_for;
    }
}

Checking for SSL in your play app

Note that in this example configuration, ALL traffic will use HTTPS. If you want to use both HTTP and HTTPS, you’ll have to remove the redirects from http to https. You can check in your play app which protocol the request uses:

1
2
3
4
5
def someAction = Action {
    implicit request = > {
       val isSecure = request.headers.get( "X-Forwarded-Proto" ).exists( _ == "https" )
    }
}
http://blog.papauschek.com/2013/10/play-framework-https-nginx/