I use Rails url_helpers to build resources urls in my app.
An example of a url in development is http://localhost:3000/resource/1, generated by the resource_url(resource) url_helper.
I use nginx in production to proxy_pass the requests to my rails app. My nginx listens on port 433 https and redirects to my rails app on port 5000 http:
server {
listen 443 ssl;
server_name api.staging.zup.me;
ssl_certificate /etc/ssl/certs/cert.crt;
ssl_certificate_key /etc/ssl/certs/cert.key;
location / {
proxy_redirect off;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $host:$server_port;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass http://localhost:5000;
}
}
Because the request that my Rails app receives from the nginx proxy is http, it is generating the urls like, http://example.com/resource/1, but only in production I want all my urls to use https, for example, https://example.com/resource/1.
What is the best way to make Rails generate urls with the https protocol only in production?
You can use redirect in nginx and never touch rails app to enable https:
server {
listen 80 default_server deferred;
server_name myserver.domain;
return 301 https://$server_name$request_uri; # enforce https
}
# HTTPS server
server {
listen 443;
server_name myserver.domain;
ssl on;
ssl_certificate /etc/nginx/ssl/myserver.domain.crt;
ssl_certificate_key /etc/nginx/ssl/myserver.domain.key;
root /srv/www/myserver;
...
}
Not sure if it's a best way, but I like it becuase you don't have to do anything with rails app, only nginx.
Related
I'm running a dockerized rails app with puma and nginx, however, I'm getting ERR_TOO_MANY_REDIRECTS when trying to access the application from a browser.
I have config.force_ssl = true on my application.rb and this is my nginx conf file:
upstream kisoul {
server rails:3000;
}
server {
listen 80;
listen 443 ssl;
root /usr/share/nginx/kisoul;
try_files $uri #kisoul;
location #kisoul {
proxy_pass_request_headers on;
proxy_ignore_headers Expires Cache-Control;
proxy_set_header Host $http_host;
proxy_pass_header Set-Cookie;
proxy_set_header X-Forwarded-Proto https;
proxy_pass http://kisoul;
}
ssl_certificate /etc/nginx/fullchain.pem;
ssl_certificate_key /etc/nginx/privkey.pem;
}
I have already tried disabling force_ssl from rails and forcing the redirect through nginx, but then I get a problem with Origin header, saying that the origin header (https://localhost) didn't match request.base_url (HTTP://localhost)
I tried many different solutions already described here, but I couldn't find any solution
I deployed Nginx reverse proxy in docker, and it belong to the bridge network which using 172.16.10.0/24. And I have the other web app in docker which in different bridge network 172.16.20.0/24. In order to let Niginx reverse proxy to connect web app, I have set Nginx reverse proxy to join the 172.16.20.0/24 as well.
My web app is hosting in http://localhost:8899, and I have bind host:8899 --> container:80. What I want to try is: when someone visit https://mydomain, and reverse proxy should pass to http://localhost:8899.
My nginx config is as follow:
server {
listen 80;
listen [::]:80;
server_name mydomain;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl;
listen [::]:443 ssl;
server_name mydomain;
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;
ssl_certificate /ssl/my_domain_cert.pem;
ssl_certificate_key /ssl/my_domain.key;
location / {
proxy_set_header Host $host;
proxy_set_header Cookie $http_cookie;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-Host $host;
proxy_pass http://localhost:8899;
proxy_read_timeout 90;
}
}
However, when i connect to https://mydomain, the error is SSL handshake failed (Error code 525). How should I fix the problem?
The 525 HTTP error means, there is no valid SSL certificate installed.
The nginx conf is searching for the SSL certificate files in these locations:
ssl_certificate /ssl/my_domain_cert.pem;
ssl_certificate_key /ssl/my_domain.key;
Unless you created a SSL certificate in your Dockerfile or created one before and put them in these locations, you have to MANUALLY create a SSL certificate.
How to create a key and pem file:
https://www.digitalocean.com/community/tutorials/how-to-create-a-self-signed-ssl-certificate-for-nginx-on-centos-7
How to get .pem file from .key and .crt files?
Working with a fresh install of Zentyal 6.1, how do I remove /SOGo from the default webmail login. Currently users need to access https://mail.mydomain.com/SOGo (Case sensitive) when I would like them to be able to access at https://mail.mydomain.com/.
I have tried adding the below to /etc/apache2/sites-enabled/default-ssl.conf. Result of that is the text on the page loading but all includes such as css and just return net::ERR_ABORTED 403 (Forbidden).
ServerName mail.domain.com
ProxyPass / http://127.0.0.1/SOGo/ retry=0
ProxyPassReverse / http://127.0.0.1/SOGo/
Ideally I would like all users to access mail.domain.com to access webmail. Also, I would like Outlook clients to use mail.domain.com for the server. This will be setup with multiple virtual mail domains for end users, such as joe#domain1.com or jane#domain2.com.
You should try using the Apache rewrite mod in order to redirect the url you like to the SOGo url. See this:
https://httpd.apache.org/docs/2.4/rewrite/remapping.html
BR.
I ended up scrapping Zentyal and switched to MailCow in Docker. Access SoGo via mail.domain.com. Below is the Reverse-Proxy for NGINX outside of Docker.
#######
### NGINX Reverse-Proxy to mailcow and SOGo
### Redirects root to SOGo and /setup to mailcow control panel
### Handles all SSL security
#######
## HTTP catch-all for invalid domain names (e.g. root domain "example.com")
server {
listen 80 default_server;
listen [::]:80 default_server;
# Have NGINX drop the connection (return no-data)
return 444;
}
## Redirect HTTP to HTTPS for valid domain names on this server
## (e.g. mail.example.com, webmail.example.com)
server {
listen 80;
listen [::]:80;
server_name mail.domain-name.com
autodiscover.domain-name.com
autoconfig.domain-name.com;
location ^~ /.well-known/acme-challenge/ {
allow all;
default_type "text/plain";
# Path can be used for cert-validation on all domains
root /var/www/html/;
break;
}
# Redirect to properly formed HTTPS request
return 301 https://$host$request_uri;
}
## HTTPS catch-all site for invalid domains that generate a certificate
## mismatch but the user proceeds anyways
server {
listen 443 default_server ssl http2;
listen [::]:443 default_server ssl http2;
# SSL settings in another file (see my 'mozModern_ssl' file as an example)
# include /etc/nginx/mozModern_ssl.conf
# SSL certificates for this connection
ssl_certificate /etc/letsencrypt/live/mail.domain-name.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/mail.domain-name.com/privkey.pem;
# Have NGINX drop the connection (return no-data)
return 444;
}
## Proxy primary server and webmail subdomain to mailcow
## Go to SOGo after typing root address only (default browsing action)
## Go to mailcow admin panel after typing /admin subdirectory
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name mail.domain-name.com
autodiscover.domain-name.com;
location ^~ /.well-known/acme-challenge/ {
allow all;
default_type "text/plain";
# Path can be used for cert-validation on all domains
root /var/www/html/;
break;
}
# SSL settings in another file (see my 'mozModern_ssl' file as an example)
#include /etc/nginx/mozModern_ssl.conf
# SSL certificates for this connection
ssl_certificate /etc/letsencrypt/live/mail.domain-name.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/mail.domain-name.com/privkey.pem;
location /Microsoft-Server-ActiveSync {
proxy_pass http://127.0.0.1:8080/Microsoft-Server-ActiveSync;
proxy_set_header Host $http_host;
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 $scheme;
proxy_connect_timeout 75;
proxy_send_timeout 3650;
proxy_read_timeout 3650;
proxy_buffers 64 256k;
client_body_buffer_size 512k;
client_max_body_size 0;
}
# Redirect root to SOGo. Rewrite rule changes / to /SOGo
location / {
rewrite ^/$ /SOGo;
proxy_pass https://127.0.0.1:8443;
proxy_set_header Host $http_host;
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 $scheme;
client_max_body_size 100m;
}
# Redirect /setup to mailcow admin panel
# Note the trailing / after setup and the trailing / after proxy URL
# This makes sure that NGINX doesn't try to go to proxyURL/setup which
# would result in a 404.
# Recent updates result in loops if you try to use 'admin' here
location ^~ /setup/ {
proxy_pass https://127.0.0.1:8443/;
proxy_set_header Host $http_host;
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 $scheme;
client_max_body_size 100m;
}
}
I have a VPS with a Rails 4 application running on Ubuntu, NginX and Unicorn.
As I want all pages to be SSL encrypted, all requests to http:// are forwarded to https:// which is working fine.
This is an excerpt of my NginX configuration:
http {
....
server {
listen 80;
server_name example.com;
rewrite ^ https://$server_name$request_uri? permanent;
}
server {
listen 443;
server_name example.com;
root /home/rails/public;
index index.htm index.html;
ssl on;
ssl_certificate /etc/ssl/example.com.crt;
ssl_certificate_key /etc/ssl/example.com.key;
location / {
try_files $uri/index.html $uri.html $uri #app;
}
location #app {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Host $host;
proxy_pass http://app_server;
}
}
}
How can I make it that all requests to http://example.com and https://example.com are forwarded to https://www.example.com?
Thanks for any help.
We use this in apache2:
<VirtualHost *80>
ServerName frontlineutilities.co.uk
ServerAlias www.frontlineutilities.co.uk
</VirtualHost>
Docs
Having researched how you'd achieve this in Nginx, I found this:
server {
listen 80;
server_name example.org www.example.org;
...
}
--
Capturing Requests
The reason I wrote this as an answer is because your choice is whether to use Middleware or the web server itself
Although I don't know the specifics, I do know that adding to the Rails middleware will eventually lead to bloat. I am a firm proponent of modular programming - and will gladly separate functionality into different parts of the stack
The problem you have is not really a rails one - it's a server issue (how to route all requests to www.). I would therefore highly recommend you focus on the server to get it sorted. As in the end, the sever is there to capture requests to your server IP & route them accordingly
I would start with the resources above & work to redirect in the server. It doesn't matter to rails whether you send a request to www. or the standard domain
If you are looking to setup which redirects http://example.com or https://example.com to http://www.example.com and https://www.example.com
The following should do the redirect
server {
listen 80;
server_name example.com;
rewrite ^/(.*) https://www.example.com$request_uri permanent;
}
server {
listen 443;
server_name example.com;
rewrite ^/(.*) https://www.example.com$request_uri permanent;
}
Also you have change your original server_name to www.example.com
Hope this helps.
I get my SSL request through a load balancer which is performing SSL termination and sending the decrypted traffic to my server on port 81.
I'm running Nginx and have setup a listener to the port 81 and I would like to tell my Rails app that this is a SSL request.
Here is how my Nginx config looks like:
server {
listen 81;
server_name SERVER;
root /var/www/app/current/public;
error_log /var/log/nginx/app-error.log;
access_log /var/log/nginx/app-access.log;
passenger_enabled on;
client_max_body_size 100M;
location / {
passenger_enabled on;
proxy_set_header X-FORWARDED-PROTO https;
}
}
It goes through but Ruby on Rails doesn't detect the header request.headers['X-Forwarded-Proto'], so it takes the request as non-https.
What should I add in order to get Rails thinking this is a SSL request?
So proxy_set_header is not used by passenger, you need to use passenger_set_cgi_param instead:
passenger_set_cgi_param HTTP_X_FORWARDED_PROTO https;
The nginx directive passenger_set_cgi_param has been replaced by passenger_set_env.
https://www.phusionpassenger.com/documentation/Users%20guide%20Nginx.html#PassengerEnvVar
for newer nginx the directive should be
passenger_set_cgi_param HTTP_X_FORWARDED_PROTO https;