当通过SSL使用proxy_pass时,Nginxredirect循环

我们使用Nginx作为Rails应用程序的负载平衡器。 由于我们正在转向多路由器托pipe解决scheme,因此我们希望负载均衡器在将请求转发到前端时为每个连接开始使用SSL,因为其中一些可能会通过互联网。

我面临的问题是非https页面创build了一个redirect循环。 这似乎是由于X-Forwarded-Proto头部设置不正确而造成的。 所以当rails在http上获取请求时,它认为这是一个https请求,即使它不是,所以它redirect到http,它认为它是一个https请求等等。

谷歌search量似乎没有帮助我解决这个问题。 所以我想知道:

  • 这是由NGINX支持(我认为是)
  • 我的configuration有问题吗?
  • 我的方法在概念上有什么问题吗?

谢谢!

user www-data; worker_processes 2; events { worker_connections 1024; use epoll; } http { passenger_root /opt/ruby-enterprise/lib/ruby/gems/1.8/gems/passenger-3.0.2; passenger_ruby /opt/ruby-enterprise/bin/ruby; passenger_pool_idle_time 0; passenger_max_pool_size 20; # Over all apps passenger_min_instances 5; # Over each app passenger_use_global_queue on; rails_env production; include mime.types; default_type application/octet-stream; log_format main '"$remote_addr", "$remote_user", "$time_local", "$request", ' '"$uid_got", "$uid_set", "$status", "$body_bytes_sent", "$http_referer", ' '"$http_user_agent", "$http_x_forwarded_for"'; ## Compression gzip on; gzip_http_version 1.0; gzip_comp_level 2; gzip_proxied any; gzip_min_length 1100; gzip_buffers 16 8k; gzip_types text/plain text/css application/x-javascript text/xml application/xml application/xml+rss text/javascript; # Some version of IE 6 don't handle compression well on some mime-types, so just disable for them gzip_disable "MSIE [1-6].(?!.*SV1)"; # Set a vary header so downstream proxies don't send cached gzipped content to IE6 gzip_vary on; sendfile on; tcp_nopush on; tcp_nodelay on; client_max_body_size 20M; server { listen 80 default; return 404; } server { listen 80; server_name MYDOMAIN.com; rewrite ^(.*) http://www.MYDOMAIN.com$1 permanent; } server { listen 80; server_name www.MYDOMAIN.com; root /u/apps/MYDOMAIN_marketing/current/public; passenger_enabled on; userid on; userid_domain MYDOMAIN.com; userid_expires max; access_log /u/apps/MYDOMAIN_marketing/shared/log/nginx/access.log main; error_log /u/apps/MYDOMAIN_marketing/shared/log/nginx/error.log info; } ##################### upstream app_backend { server www01:8000; server www02:8000; server www03:8000; server www04:8000; server www05:8000; server www06:8000; } server { listen 80; server_name *.MYDOMAIN.com; root /u/apps/MYDOMAIN/current/public; userid on; userid_domain MYDOMAIN.com; userid_expires max; access_log /u/apps/MYDOMAIN/shared/log/nginx/lb_access.log main; error_log /u/apps/MYDOMAIN/shared/log/nginx/lb_error.log info; if (-f $document_root/system/maintenance.html) { # I don't know how to get NGINX to both show a page and give a return code. # So just return 503 with a generic error page. return 503; } location / { ## General Rails error page stuff error_page 404 /404.html; error_page 422 /422.html; error_page 500 502 503 504 /500.html; error_page 403 /403.html; # If the file exists then stop here. Saves 4 more stats and some # rewrites. if (-f $request_filename) { break; } # Rails page caching if (-f $request_filename/index.html) { rewrite (.*) $1/index.html break; } if (-f $request_filename.html) { rewrite (.*) $1.html break; } # If it hasn't been handled above, and isn't a static file # then send to passenger. proxy_pass https://app_backend; proxy_connect_timeout 1; ##proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header Host $http_host; proxy_set_header X-Forwarded-Proto http; } } server { ssl on; listen 8000; server_name *.MYDOMAIN.com; root /u/apps/MYDOMAIN/current/public; passenger_enabled on; access_log /u/apps/MYDOMAIN/shared/log/nginx/access.log main; error_log /u/apps/MYDOMAIN/shared/log/nginx/error.log info; } ######################## # SSL configuration from: # http://tumblelog.jauderho.com/post/121851623/nginx-and-stronger-ssl # http://articles.slicehost.com/2007/12/19/ubuntu-gutsy-nginx-ssl-and-vhosts ssl_certificate MYDOMAIN.com.combined.crt; ssl_certificate_key MYDOMAIN.com.key; ssl_prefer_server_ciphers on; ssl_protocols SSLv3 TLSv1; ssl_session_cache shared:SSL:2m; ssl_ciphers ALL:!ADH:RC4+RSA:+HIGH:+MEDIUM:-LOW:-SSLv2:-EXP; # This is necessary to catch random crap thrown at us during the # SecurityMetrics scans before it hits Passenger. Without this, # Passenger becomes confused and stops serving requests. server { listen 443 default; ssl on; return 404; } server { # If we're willing to log secure and non-secure together, # we can probably just merge this with the config above. listen 443; server_name *.MYDOMAIN.com; ssl on; root /u/apps/MYDOMAIN/current/public; userid on; userid_domain MYDOMAIN.com; userid_expires max; access_log /u/apps/MYDOMAIN/shared/log/nginx/lb_secure_access.log main; error_log /u/apps/MYDOMAIN/shared/log/nginx/lb_secure_error.log info; if (-f $document_root/system/maintenance.html) { # I don't know how to get NGINX to both show a page and give a return code. # So just return 503 with a generic error page. return 503; } location / { ## General Rails error page stuff error_page 404 /404.html; error_page 422 /422.html; error_page 500 502 503 504 /500.html; error_page 403 /403.html; # If the file exists then stop here. Saves 4 more stats and some # rewrites. if (-f $request_filename) { break; } # Rails page caching if (-f $request_filename/index.html) { rewrite (.*) $1/index.html break; } if (-f $request_filename.html) { rewrite (.*) $1.html break; } # If it hasn't been handled above, and isn't a static file # then send to passenger. proxy_pass https://app_backend; proxy_connect_timeout 1; ##proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header Host $http_host; proxy_set_header X-Forwarded-Proto https; } } } 

事实certificate,乘客和Nginx不像其他大多数人一样工作。 您必须在您的nginx.conf文件中手动强制HTTPS标头。

 server { listen 8000; ssl on; server_name *.pagerduty.com *.supportduty.com; root /u/apps/pagerduty/current/public; set $my_https "off"; if ($http_x_forwarded_proto = "https") { set $my_https "on"; } passenger_enabled on; passenger_set_cgi_param HTTPS $my_https; access_log /u/apps/pagerduty/shared/log/nginx/access.log main; error_log /u/apps/pagerduty/shared/log/nginx/error.log info; } 

if语句不能正确设置代理标头。

请参阅: http : //wiki.nginx.org/IfIsEvil – >“指令如果在位置上下文中使用时有问题,在某些情况下,它不会达到您的期望值,而是完全不同的东西。

if语句可以被更有效的try_files语句替代。

你的conf文件应该是这样的:

 server { listen 80; server_name *.MYDOMAIN.com; root /u/apps/MYDOMAIN/current/public; userid on; userid_domain MYDOMAIN.com; userid_expires max; access_log /u/apps/MYDOMAIN/shared/log/nginx/lb_access.log main; error_log /u/apps/MYDOMAIN/shared/log/nginx/lb_error.log info; location $document_root/system/maintenance.html { return 503; } # Nginx will try thoses locations and will stop after the first success try_files $uri $uri.html $uri/index.html @passenger location / { ## General Rails error page stuff error_page 404 /404.html; error_page 422 /422.html; error_page 500 502 503 504 /500.html; error_page 403 /403.html; } location @passenger { # Here you're sure that if the request goes to the backends, the header will be set. If this doesn't work, then you should consider charging the ruby app. proxy_pass https://app_backend; proxy_connect_timeout 1; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header Host $http_host; proxy_set_header X-Forwarded-Proto http; } }