I've implemented a project in Play!Framework with NGinx using only https.
Everything works fine, the SSL is well recognized and I can use my app from anywhere but when Play! returns an absolute URL, it's in http, not https.
This is problematic, and I don't know where the problem is. I tried to start Play with -Dhttps.port=XXXX instead of -Dhttp.port=XXXX but it didn't changed the output of "http" instead of "https".
I'm suspecting an Nginx bad configuration (a parameter I forgot?).
Here's my sites-enabled/website
config file :
proxy_buffering off;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Scheme "https"; # I also tried $scheme without any luck
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_http_version 1.1;
server {
listen 80;
server_name my.website.com;
return 301 https://my.website.com;
}
upstream my-backend {
server 127.0.0.1:9100;
}
server {
listen 443;
ssl on;
root /var/www/website/errors/;
# http://www.selfsignedcertificate.com/ is useful for development testing
ssl_certificate /etc/nginx/ssl/my.website.com.crt;
ssl_certificate_key /etc/nginx/ssl/my.website.com.key;
# From https://bettercrypto.org/static/applied-crypto-hardening.pdf
ssl_prefer_server_ciphers on;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2; # not possible to do exclusive
ssl_ciphers 'EDH+CAMELLIA:EDH+aRSA:EECDH+aRSA+AESGCM:EECDH+aRSA+SHA384:EECDH+aRSA+SHA256:EECDH:+CAMELLIA256:+AES256:+CAMELLIA128:+AES128:+SSLv3:!aNULL:!eNULL:!LOW:!3DES:!MD5:!EXP:!PSK:!DSS:!RC4:!SEED:!ECDSA:CAMELLIA256-SHA:AES256-SHA:CAMELLIA128-SHA:AES128-SHA';
add_header Strict-Transport-Security max-age=15768000; # six months
# use this only if all subdomains support HTTPS!
# add_header Strict-Transport-Security "max-age=15768000; includeSubDomains"
keepalive_timeout 70;
server_name my.website.com;
location / {
#proxy_pass http://my-backend;
proxy_pass http://127.0.0.1:9100;
}
location ~ /\.git {
deny all;
}
error_page 502 @maintenance;
location @maintenance {
rewrite ^(.*)$ /error502.html break;
}
}
What am I missing?
Update: Here's the code that generate the absolute url :
controllers.routes.Pages.loginToken(getToken()).absoluteURL(play.mvc.Http.Context.current().request());
There are a couple overloads for absoluteURL
. You're using this one:
public String absoluteURL(Http.Request request) {
return absoluteURL(request.secure(), request.host());
}
The problem with this is that since you're reverse proxying to Play via nginx, Play is actually receiving all the requests through HTTP, and not HTTPS. This means that request.secure()
is false, and absoluteURL
will return a URL containing http://...
.
Instead, manually set secure
to true
in one of the overloads:
controllers.routes.Pages.loginToken(getToken()).absoluteURL(play.mvc.Http.Context.current().request(), true);
Additionally, what I normally do is have a configuration variable for secure
so it can generate non-https URLs when developing locally.
In application.conf:
application.secure = false # for local dev
And in production I add the command line option -Dapplication.secure=true
when starting the application, to override the value in application.conf
.
Then generating the URL would look like this:
controllers.routes.Pages.loginToken(getToken()).absoluteURL(
play.mvc.Http.Context.current().request(),
play.Play.application().configuration().getBoolean("application.secure", true) // default to true
);