Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to fix Sinatra redirecting https to http under nginx

I have a Sinatra app running in nginx (using thin as a back-proxy) and I'm using redirect '/<path>' statements in Sinatra. However, when I access the site under https, those redirects send me to http://localhost/<path> rather than to https://localhost/<path> as they should.

Currently, nginx passes control to thin with this command proxy_pass http://thin_cluster, where thin_cluster is

upstream thin_cluster { server unix:/tmp/thin.cct.0.sock; }

How can I fix this?

like image 735
Alex Mullans Avatar asked Jun 13 '11 12:06

Alex Mullans


People also ask

How do I redirect HTTP request to HTTPS in nginx?

Redirect HTTP to HTTPS version for Specified domain in Nginx Server_name domain-name.com www.domain-name.com – it specifies the domain names. So, replace it with your website domain name that you want to redirect. Return 301 https://domain-name.com$request_uri – it moves the traffic to the HTTPS version of the site.

How do I redirect all HTTPS requests to HTTP?

In order for something to redirect HTTPS to HTTP, something must be listening on the HTTPS port. Your client must first open a SSL/TLS connection to the port serving HTTPS, HTTP traffic is tunneled through the SSL/TLS connection and the server will respond with a redirect to the HTTP port.

Is it possible to redirect HTTPS to HTTP?

If you don't have a valid SSL certificate, then it's not possible to redirect HTTPS to HTTP without a warning. To properly issue the redirect, the site needs to have a valid SSL certificate. And if the site has a valid SSL certificate, then at that point it usually makes more sense to just serve the site over HTTPS.


2 Answers

In order for Sinatra to correctly assemble the url used for redirects, it needs to be able to determine whether the request is using ssl, so that the redirect can be made using http or https as appropriate.

Obviously the actual call to thin isn't using ssl, as this is being handled by the front end web server, and the proxied request is in the clear. We therefore need a way to tell Sinatra that it should treat the request as secure, even though it isn't actually using ssl.

Ultimately the code that determines whether the request should be treated as secure is in the Rack::Request#ssl? and Rack::Request#scheme methods. The scheme methods examines the env hash to see if one of a number of entries are present. One of these is HTTP_X_FORWARDED_PROTO which corresponds to the X-Forwarded-Proto HTTP header. If this is set, then the value is used as the protocol scheme (http or https).

So if we add this HTTP header to the request when it is proxied from nginx to the back end, Sinatra will be able to correctly determine when to redirect to https. In nginx we can add headers to proxied requests with proxy_set_header, and the scheme is available in the $scheme variable.

So adding the line

proxy_set_header X-Forwarded-Proto $scheme;

to the nginx configuration after the proxy_pass line should make it work.

like image 77
matt Avatar answered Sep 30 '22 15:09

matt


You can force all links to go to https in the nginx layer. in nginx.conf:

server{
   listen 80;
   server_name example.com;
   rewrite    ^(.*) https://$server_name$1 redirect;
}    

This is good to have too to assure that your requests are always https

like image 31
Michael Papile Avatar answered Sep 30 '22 15:09

Michael Papile