I'm planning to move a Rails application from an nginx with
mongrel_cluster to a two-machine setup using nginx and Passenger and
I'm having some issues with the requests sent over HTTPS.
The planned setup looks something like this:
* a front-end web server using nginx that will serve static files and
proxy requests
* a load balancer that will handle requests sent by the front-end
server downstream
* a number nginx instances with Passenger enabled, working as
application servers
* a MySQL database
Right now, I've simplified to setup as much as possible and current
setup is an nginx server that serves static content and sends
everything else to another nginx instance listening on another port.
The problem is that the requests to HTTPS-only pages are actually
infinite redirects because the backend server thinks that every
request is always done via HTTP.
When I used a mongrel_cluster, the solution was to have
"proxy_set_header X_FORWARDED_PROTO https;" in the server block that
would handle traffic over port 443, but it seems to have no effect
with passenger.
Here are my config files:
# frontend.conf
upstream haproxy {
server
127.0.0.1:5000;
}
server {
listen *:80;
include /etc/nginx/sites-available/frontend.common;
}
server {
listen *:443;
ssl on;
ssl_certificate /etc/nginx/ssl.crt/ssl.crt;
ssl_certificate_key /etc/nginx/ssl.key/ssl.key;
proxy_set_header X_FORWARDED_PROTO https;
include /etc/nginx/sites-available/frontend.common;
}
# frontend.common
server_name app.test;
keepalive_timeout 70;
client_max_body_size 50M;
access_log /var/log/nginx/app/access.log combined;
root /var/www/app/current/public;
location / {
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_redirect off;
proxy_read_timeout 500;
proxy_next_upstream error;
proxy_max_temp_file_size 0;
# If the file exists as a static file serve it directly without
# running all the other rewite tests on it
if (-f $request_filename) {
break;
}
# this rewrites all the requests to the maintenance.html
# page if it exists in the doc root. This is for capistrano's
# disable web task
if (-f $document_root/system/maintenance.html) {
rewrite ^(.*)$ /system/maintenance.html last;
break;
}
# check for index.html for directory index
# if its there on the filesystem then rewite
# the url to add /index.html to the end of it
# and then break to send it to the next config rules.
if (-f $request_filename/index.html) {
rewrite (.*) $1/index.html break;
}
# this is the meat of the rails page caching config
# it adds .html to the end of the url and then checks
# the filesystem for that file. If it exists, then we
# rewite the url to have explicit .html on the end
# and then send it on its way to the next config rule.
# if there is no file on the fs then it sets all the
# necessary headers and proxies to our upstream mongrels
if (-f $request_filename.html) {
rewrite (.*) $1.html break;
}
if (!-f $request_filename) {
proxy_pass
http://haproxy;
break;
}
}
error_page 500 502 503 504 /500.html;
error_page 403 /403.html;
location = /500.html {
root /var/www/app/current/public;
}
# backend.conf
server {
listen *:5000;
access_log /var/log/nginx/app/access-backend.log combined;
root /var/www/app/current/public;
passenger_enabled on;
}
frontend.conf and frontend.common are used by the frontend server
while the backend nginx + Passenger server is using backend.conf.