21

server declaration in my nginx.conf:

    listen       1.2.3.4:443 ssl;
    root /var/www/myapp/current/public;
    ssl on;
    ssl_certificate /etc/nginx-cert/server.crt;
    ssl_certificate_key /etc/nginx-cert/server.key;
    location / {
          proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
          proxy_set_header Host $http_host;
          proxy_redirect off;

          if (!-f $request_filename) {
            proxy_pass http://upstreamy;
            break;
          }
     }

upstream declaration in nginx.conf:

upstream upstreamy {
    server unix:/var/www//myapp/shared/sockets/unicorn.sock fail_timeout=0;
}

this works fine, myapp is reachable as https://somehost

but the app is generating http url's for redirects, so for instance when authenticating with devise, the / is redirected to http://somehost/user/sign_in instead of https (from the viewpoint of the rails app, it's all http anyway).

I tried

proxy_pass https://upstreamy;

but that just tries to encrypt traffic between nginx and the unicorns that run the rails app.

I also tried, in application_helper.rb:

# http://stackoverflow.com/questions/1662262/rails-redirect-with-https
def url_options
  super
  @_url_options.dup.tap do |options|
  options[:protocol] = Rails.env.production? ? "https://" : "http://"
  options.freeze
end

but it seems to not work.

How would one solve this?

Edit: so, the goal is not to make the rails app to require ssl, or to be forced to use ssl; the goal is to make the rails app generate https:// urls when redirecting... (I think all other urls are relative).

2 Answers2

51

You need to add the following line:

proxy_set_header X-Forwarded-Proto https;

as in

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;

      if (!-f $request_filename) {
        proxy_pass http://upstreamy;
        break;
      }
 }
Yosep Kim
  • 2,931
  • 22
  • 23
  • 3
    Awesome! Setting up nginx can be very painful. Very painful... :) – Yosep Kim May 03 '12 at 13:58
  • I couldn't get to use proxy_set_header but I just forwarded everything to my proxy for "post" method and rewrite url for the get. Working very well so far. – nembleton Aug 18 '12 at 09:38
  • 11
    In a lot of cases (although perhaps not yours), it's more useful to use `proxy_set_header X-Forwarded-Proto $scheme;` so that you're passing X-Forwarded-Proto correctly to your upstream application weather you're on http or https. This is particularly useful when you have a load balancer handling https. – jmervine Aug 28 '13 at 21:19
  • 1
    @jmervine If the load balancer is terminating SSL, communicating with nginx over HTTP which communicates with Rails over HTTP, won't $scheme be (incorrectly) HTTP? When you'd still want Rails to generate HTTPS urls in this case. – Patrick Apr 02 '14 at 21:17
  • where to put this code? under listen 80 or 443? can u share ur full config? – buncis Apr 13 '23 at 23:12
-2

You can pass :protocol => "https", to redirect_to.

You can set this as a default by adding the following to application.rb

Rails.application.routes.default_url_options[:protocol]= 'https'

Reference: https://stackoverflow.com/a/6101147/446203

Community
  • 1
  • 1
CambridgeMike
  • 4,562
  • 1
  • 28
  • 37