SSL on Nginx causes redirect loop - ruby-on-rails

I'm trying to setup SSL on a Digital Ocean VPS using Nginx. My server conf is like so:
upstream unicorn {
server unix:/home/ubuntu/apps/example/shared/sock/unicorn.example.sock fail_timeout=0;
}
server {
listen 80;
server_name www.example.com example.com;
rewrite ^/(.*) https://example.com/$1 permanent;
}
server {
listen 443;
include example_ssl;
server_name www.example.com;
rewrite ^/(.*) https://example.com/$1 permanent;
}
server {
listen 443;
include example_ssl;
server_name example.com;
root /home/ubuntu/apps/example/current/public;
try_files $uri/index.html $uri #unicorn;
location #unicorn {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_redirect off;
proxy_pass http://unicorn;
}
location ~ ^/(assets)/ {
gzip_static on;
expires max;
add_header Cache-Control public;
#add_header Last-Modified "";
#add_header ETag "";
}
error_page 500 502 503 504 /500.html;
client_max_body_size 4G;
keepalive_timeout 60;
}
The ssl info is in example_ssl:
ssl on;
ssl_certificate /etc/nginx/ssl/example.com.crt;
ssl_certificate_key /etc/nginx/ssl/example.com.key;
ssl_session_timeout 10m;
ssl_ciphers "AES256+EECDH:AES256+EDH";
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_prefer_server_ciphers on;
ssl_session_cache shared:SSL:10m;
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains";
add_header X-Frame-Options DENY;
add_header X-Content-Type-Options nosniff;
This is causing an endless redirect loop. Http requests are redirected to HTTPS as expected but all tries to https://example.com are being redirected back to HTTP.
I can't seem to figure out why the HTTPS requests are being redirected. I checked my SSL cert by going to www.digicert.com and everything came back saying it was successfully installed.
When I try from my terminal:
openssl s_client -connect example.com:443
I get the following error:
verify error:num=20:unable to get local issuer certificate
The cert I got from my client did not contain the intermediate certs, but from what I understand this should still work when trying to access the site from the browser.
If I change the server block to only listen for 80 and not use SSL the site is able to load successfully, but I need to use SSL only.
Also, this is hosting a Rails app with Unicorn web server. My unicorn.log is empty other than starting the webserver so am I correct that this is not touching my Rails configuration at all, just an issue with nginx/ssl cert configuration?
Thanks!

Try this:
upstream unicorn {
server unix:/home/ubuntu/apps/example/shared/sock/unicorn.example.sock fail_timeout=0;
}
server {
listen 80;
server_name example.com www.example.com;
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl;
include example_ssl;
server_name example.com;
root /home/ubuntu/apps/example/current/public;
try_files $uri/index.html $uri #unicorn;
location #unicorn {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_redirect off;
proxy_pass http://unicorn;
}
location ~ ^/(assets)/ {
gzip_static on;
expires max;
add_header Cache-Control public;
#add_header Last-Modified "";
#add_header ETag "";
}
error_page 500 502 503 504 /500.html;
client_max_body_size 4G;
keepalive_timeout 60;
}
You will need to remove "ssl on;" from your ssl include file, that is for older versions of nginx. You might have to modify this if you are using multiple ssl on a single IP.

Related

Rails Application using Nginx working on HTTP but not HTTPS

I have been trying to get my application working in production. I was able to access the site before changing config.force_ssl = true in my config\environments\production.rb.
I have seen many others with this problem need to add proxy_set_header X-Fowarded-Proto https;
I have tried adding this in my /etc/nginx/sites-available/default but haven't seen a difference.
My full default is below:
upstream puma {
server unix:///home/deploy/apps/appname/shared/tmp/sockets/appname-puma.sock;
}
server {
listen 80;
listen [::]:80;
listen 443 ssl;
listen [::]:443 ssl;
root /var/www/html;
index index.html index.htm index.nginx-debian.html
server_name appname.com www.appname.com
try_files $uri/index.html $uri #puma;
location #puma {
proxy_set_header X-Forwarded-Proto https;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_redirect off;
proxy_pass http://puma;
}
}
After making changes I reloaded nginx using sudo service nginx reload followed by sudo service nginx stop and sudo service nginx start
Am I missing something?
EDIT:
I updated my default and removed the config.force_ssl = true:
upstream puma {
server unix:///home/kiui/apps/appnamw/shared/tmp/sockets/appname-puma.sock;
}
server {
listen 80 default_server;
listen [::]:80 default_server;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl;
keepalive_timeout 70;
server_name appname.com www.appname.com;
ssl on;
ssl_certificate /root/appname.com.chain.cer;
ssl_certificate_key /root/appname.com.key;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers AES128-SHA:AES256-SHA:RC4-SHA:DES-CBC3-SHA:RC4-MD5;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
root /home/deploy/apps/appname/current/public;
access_log /home/deploy/apps/appname/current/log/nginx.access.log;
error_log /home/deploy/apps/appname/current/log/nginx.error.log info;
location ^~ /assets/ {
gzip_static on;
expires max;
add_header Cache-Control public;
}
try_files $uri/index.html $uri #puma;
location #puma {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $host;
proxy_redirect off;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_pass http://puma;
}
error_page 500 502 503 504 /500.html;
client_max_body_size 10M;
}
I can now access the site with http but not https.
Could you try the following:
upstream puma {
  server unix:///home/deploy/apps/appname/shared/tmp/sockets/appname-puma.sock;
}
server {
 listen 80;
 server_name appname.com www.appname.com;
 return 301 https://$host$request_uri;
}
server {
  # SSL configuration
  ssl on;
 listen 443 ssl;
 ssl_certificate path-to-your-crt-file;
 ssl_certificate_key path-to-your-key-file;
 server_name appname.com www.appname.com;
...
}
My problem was where I was adding the code above. I was adding it in default rather than nginx.conf. Moving the code above solved the problem.

Nginx SSL working but sending request as http

I followed Deploying a Rails App on Ubuntu 14.04 with Capistrano, Nginx, and Puma to deploy a Rails app to Digital Ocean.
It suggested to keep nginx.conf (/etc/nginx/sites-enabled/medical-app) as
upstream puma {
server unix:///home/myappuser/apps/medical-app/shared/tmp/sockets/medical-app-puma.sock;
}
server {
listen 80 default_server deferred;
# server_name example.com;
root /home/myappuser/apps/medical-app/current/public;
access_log /home/myappuser/apps/medical-app/current/log/nginx.access.log;
error_log /home/myappuser/apps/medical-app/current/log/nginx.error.log info;
location ^~ /assets/ {
gzip_static on;
expires max;
add_header Cache-Control public;
}
try_files $uri/index.html $uri #puma;
location #puma {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_redirect off;
proxy_pass http://puma;
}
error_page 500 502 503 504 /500.html;
client_max_body_size 10M;
keepalive_timeout 10;
}
and than I added domain and than installed SSL using let's encrypt
which changed the nginx.conf (/etc/nginx/sites-enabled/medical-app) as following
upstream puma {
server unix:///home/myappuser/apps/medical-app/shared/tmp/sockets/medical-app-puma.sock;
}
server {
listen 80 default_server deferred;
# server_name example.com;
root /home/myappuser/apps/medical-app/current/public;
access_log /home/myappuser/apps/medical-app/current/log/nginx.access.log;
error_log /home/myappuser/apps/medical-app/current/log/nginx.error.log info;
location ^~ /assets/ {
gzip_static on;
expires max;
add_header Cache-Control public;
}
try_files $uri/index.html $uri #puma;
location #puma {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_redirect off;
proxy_pass http://puma;
}
error_page 500 502 503 504 /500.html;
client_max_body_size 10M;
keepalive_timeout 10;
}
server {
# server_name example.com;
root /home/myappuser/apps/medical-app/current/public;
access_log /home/myappuser/apps/medical-app/current/log/nginx.access.log;
error_log /home/myappuser/apps/medical-app/current/log/nginx.error.log info;
location ^~ /assets/ {
gzip_static on;
expires max;
add_header Cache-Control public;
}
try_files $uri/index.html $uri #puma;
location #puma {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_redirect off;
proxy_pass http://puma;
}
error_page 500 502 503 504 /500.html;
client_max_body_size 10M;
keepalive_timeout 10;
server_name www.medtib.com medtib.com; # managed by Certbot
listen 443 ssl; # managed by Certbot
ssl_certificate /etc/letsencrypt/live/www.medtib.com/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/www.medtib.com/privkey.pem; # managed by Certbot
include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
}
server {
if ($host = medtib.com) {
return 301 https://$host$request_uri;
} # managed by Certbot
if ($host = www.medtib.com) {
return 301 https://$host$request_uri;
} # managed by Certbot
listen 80 ;
server_name www.medtib.com medtib.com;
return 404; # managed by Certbot
}
Now https is working fine but if I enable force SSL through Rails config
config.force_ssl = true
Than it gives error page not working with message redirected too many times
and if I try to login with Facebook which requires https than it gives following error
I don't have idea about nginx etc.
You should forward X-Forwarded-Proto header to your application to inform your application which protocol used. (https, http)
Put the following:
proxy_set_header X-Forwarded-Proto $scheme;
Before:
proxy_pass http://puma;
It should do the trick.

Serving Assets VIA SSL in Rails 3 App Using NGINX and Unicorn

I have set up my rails app, works great. Unfortunately on the https:// version of the site, none of my assets are being served... any idea as to why this might happen? All assets get served via http:// but none via https://
Help?
============= CODE ==============
upstream unicorn {
server unix:/tmp/unicorn.XXX.sock fail_timeout=0;
}
server {
listen 80 default;
server_name example.com;
root /home/deployer/apps/XXX/current/public;
location ^~ /assets/ {
gzip_static on;
expires max;
add_header Cache-Control public;
}
try_files $uri/index.html $uri #unicorn;
location #unicorn {
proxy_set_header X-Forwarded-Proto http;
proxy_pass http://unicorn;
}
error_page 500 502 503 504 /500.html;
client_max_body_size 5G;
keepalive_timeout 10;
send_timeout 240;
sendfile_max_chunk 5m;
}
server {
listen 443;
server_name example.com;
root /home/webuser/apps/XXX/current/public;
location ^~ /assets/ {
gzip_static on;
expires max;
add_header Cache-Control public;
}
try_files $uri #non-ssl-redirect #unicorn;
location #unicorn {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto https;
proxy_set_header Host $http_host;
proxy_redirect off;
proxy_pass http://unicorn;
}
error_page 500 502 503 504 /500.html;
client_max_body_size 5G;
keepalive_timeout 10;
ssl on;
ssl_certificate /etc/nginx/ssl/server.crt;
ssl_certificate_key /etc/nginx/ssl/server.key;
ssl_protocols SSLv3 TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers ALL:-ADH:+HIGH:+MEDIUM:-LOW:-SSLv2:-EXP;
ssl_session_cache shared:SSL:10m;
send_timeout 240;
sendfile_max_chunk 5m;
}
It sounds like your asset host configuration is hard-wired to http. When you view a page over https, but load an asset over http, many browsers will block the asset or show a warning.
The easiest way to fix this is to set a Rails asset_host that does not include a protocol, which should inherit the protocol of the page it's loaded from.
For example:
# Use just the asset host domain name for Rails pages
config.action_controller.asset_host = "assets.mycompany.com"
# Specify HTTP for ActionMailer messages, since they don't have a protocol to inherit
config.action_mailer.asset_host = "http://assets.mycompany.com"
If you are properly including your assets with an https protocol, but they are failing to load - it's likely there is an SSL certificate name mismatch between the hostname for your assets and the SSL certificate. For example, if you're serving assets straight from S3 with a custom domain name, the S3 SSL certificate (*.s3.amazonaws.com) will fail to match assets.yourcompany.com and cause an SSL error, preventing the assets from loading.
The only fix in this case is to use an asset host or CDN that allows a custom SSL cert to match your hostname, or revert back to the public hostname that matches your providers SSL cert.

Why is SSL redirect not working with force_ssl and Nginx?

I have a Rails 3.2.13 app that I am trying to configure SSL for with Nginx and Unicorn. I want to be able to tell some controllers and some controller actions to 'force_ssl' and to properly redirect. I have been able to get this working so that I can manually hit the app with 'https://foo.com' and things work. When I put 'force_ssl' into a controller action, let's say users#index:
class UsersController < ApplicationController
force_ssl
def index
# do some stuff
end
end
I would expect that if I navigate to 'http://foo.com/users' that it would redirect to 'https://foo.com/users'.
It does not.
Instead, it redirects to: 'https://unicorn_foo/users'. What am I missing?
nginx.conf:
upstream unicorn_foo {
server unix:/tmp/unicorn.foo.sock fail_timeout=0;
}
server {
listen 80 default;
server_name foo.com;
root /home/webuser/apps/foo/current/public;
location ^~ /assets/ {
gzip_static on;
expires max;
add_header Cache-Control public;
}
try_files $uri/index.html $uri #unicorn_foo;
location #unicorn_foo {
proxy_set_header X-Forwarded-Proto http;
proxy_pass http://unicorn_foo;
}
error_page 500 502 503 504 /500.html;
client_max_body_size 5G;
keepalive_timeout 10;
send_timeout 240;
sendfile_max_chunk 5m;
}
server {
listen 443;
server_name foo.com;
root /home/webuser/apps/foo/current/public;
location ^~ /assets/ {
gzip_static on;
expires max;
add_header Cache-Control public;
}
try_files $uri/index.html $uri #unicorn_foo;
location #unicorn_foo {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto https;
proxy_set_header Host $http_host;
proxy_redirect off;
proxy_pass http://unicorn_foo;
}
error_page 500 502 503 504 /500.html;
client_max_body_size 5G;
keepalive_timeout 10;
ssl on;
ssl_certificate /etc/nginx/ssl/server.crt;
ssl_certificate_key /etc/nginx/ssl/server.key;
ssl_protocols SSLv3 TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers ALL:-ADH:+HIGH:+MEDIUM:-LOW:-SSLv2:-EXP;
ssl_session_cache shared:SSL:10m;
send_timeout 240;
sendfile_max_chunk 5m;
}
First guess... the port 80 server block does not pass the host through, maybe that's it?
proxy_set_header Host $http_host;
The SSL block does, but if you start at the non-SSL side and Rails picks it up, it might not have the full header there?

NGINX CONF with RAILS on LINODE

This is my nginx.conf file
upstream unicorn {
server unix:/tmp/unicorn.blog.sock fail_timeout=0;
}
server {
listen 80 default deferred;
# server_name example.com;
root /home/deployer/apps/blog/current/public;
location ^~ /assets/ {
gzip_static on;
expires max;
add_header Cache-Control public;
}
try_files $uri/index.html $uri #unicorn;
location #unicorn {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_redirect off;
proxy_pass http://unicorn;
}
error_page 500 502 503 504 /500.html;
client_max_body_size 4G;
keepalive_timeout 10;
}
I tried to add SSL - I redeplyed and restarted NGINX and the server. I undid everything redeployed and it was back up.... Now I tried the same thing. Tried to add SSL it failed. Undid. Now server is down. Here is the github with revisions!
Ran /etc/init.d/unicorn_blog start and restarted unicorn. It worked

Resources