36

I'm looking to learn how to cleanup my app's URLs. My app is powered by Rails 3 on Heroku.

The desired URL is https://www.example.comite.com

I'd like to redirect all URLs unlike the above to that URL. Is this a Rails thing or DNS?

Bad URLs:

https://example.comite.com
http://www.example.comite.com
http://example.comite.com

And if anything is trailing, like http://www.example.comite.com/photo/1 for the url to be redirected with the path: https://www.example.comite.com/photo/1

Stephan Muller
  • 27,018
  • 16
  • 85
  • 126
AnApprentice
  • 108,152
  • 195
  • 629
  • 1,012

6 Answers6

57

As an extension to user2100689's answer, in Rails 3+ you can use config.force_ssl = true in config/environments/production.rb

The line can just be uncommented as follows

# Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies.
config.force_ssl = true
Community
  • 1
  • 1
Jon
  • 1,328
  • 1
  • 11
  • 11
18

DNS records cannot define the protocol for a domain, therefore you can't redirect http:// to https:// through DNS. Doing it through the web server configuration is not portable, hard to do, error prone and just plain outdated. This is a job best handled by the Rails router.

# beginning of routes.rb 
match "*path" => redirect("https://www.mysite.com/%{path}"), :constraints => { :protocol => "http://" }
match "*path" => redirect("https://www.mysite.com/%{path}"), :constraints => { :subdomain => "" }
edgerunner
  • 14,873
  • 2
  • 57
  • 69
  • This works, but do you need to leave the A records in place? I was assuming you'd be able to redirect `mysite.com` to `http://www.mysite.com` via DNS, and then once it hit your rails app it would redirect to https using your route contraints. However, with my DNS redirect `http://mysite.com` redirects as expected, but `https://mysite.com` doesn't (and never hits my rails server for the route contraints to take effect). I've reverted back to having A records for now, but was just wondering if you knew why the DNS redirect didn't work for `https://mysite.com`. – Brian Armstrong Jun 13 '12 at 23:21
  • there's nothing you can do on the DNS side. As I said, DNS has nothing to do with the protocol. You can redirect a name to another, but not the protocol. It isn't even transmitted to the DNS server. Your browser asks the IP address of `mysite.com` not `http://mysite.com`, and it gets a reply like `REDIRECT www.mysite.com` not `REDIRECT http://www.mysite.com` – edgerunner Jun 14 '12 at 12:51
  • I am not able to redirect from "https://example.com" to "https://www.example.com" by adding above rules in routes – Shrinivas Nov 15 '17 at 10:38
  • @Shrinivas they probably won't work unless you put them at the **beginning** of your `routes.rb` – edgerunner Sep 10 '19 at 12:00
7

Rails 3.1.0 and higher has force_ssl, which is a controller method that will redirect to https for non-development environments.

http://api.rubyonrails.org/classes/ActionController/ForceSSL/ClassMethods.html

Place it in each controller that you want to redirect, or better yet, place it in your ApplicationController:

app/controllers/application.rb:

class ApplicationController < ActionController::Base
  # ...
  force_ssl
  # ...
end

This is a good thing to always include in your apps (and of course you'll have to get a certificate). HTTPS Everywhere!

Robin Daugherty
  • 7,115
  • 4
  • 45
  • 59
  • Does this protect against SSL stripping? – stephenmurdoch Jan 18 '14 at 12:46
  • 1
    I believe this does protect against sslstrip-type attacks. Rails will refuse to serve non-SSL requests by always redirecting to the corresponding HTTPS URL. If sslstrip changes the protocol of the redirect, Rails will simply redirect to HTTPS again. – Robin Daugherty Jan 20 '14 at 16:02
  • @RobinDaugherty CAREFUL, if there is a MITM attack then session cookies will be leaked before the redirect back to https happens. Which means a more advanced sslstrip will pwn your site, and make public wifi's (and spoofed wifis) very dangerous while using your app. To prevent cookies leaking, you need to enable config.use_ssl = true – Simon B. Feb 07 '17 at 11:28
  • [`force_ssl` is the setting that enables secure cookies.](http://stackoverflow.com/a/39476254/1589422) I can find no reference to a `use_ssl` setting [in the Rails codebase](https://github.com/rails/rails/search?q=use_ssl), nor in Google. – Robin Daugherty Feb 07 '17 at 15:54
7

You can always throw this in your production.rb... config.use_ssl = true

user2100689
  • 79
  • 1
  • 2
7

Because this is Heroku, you cannot use apache or nginx configs. What you can do is put a before_filter in your ApplicationController, assuming you have 3 or more controllers like these below, although of course they will be in separate files

class ApplicationController < ActionController::Base
    def redirect_https        
        redirect_to :protocol => "https://" unless request.ssl?
        return true
    end
    before_filter :redirect_https
end
class TypicalController < ApplicationController
    def blah
    end
end
class HomePageController < ApplicationController
    skip_before_filter :redirect_https
end

You may also need to fiddle your routes a bit when using devise, but I suspect that was just the way we did it so I won't get into those details here, and I've modified the code above to avoid that complication.

happy hacking.

edgerunner
  • 14,873
  • 2
  • 57
  • 69
user693960
  • 141
  • 1
  • 2
  • This feels like the right way to go, but doesn't answer one key point: how do you transition from `http://mysite.com` to `https://www.mysite.com`? (Answer the essentially identical question in http://stackoverflow.com/questions/9027916/redirecting-from-http-mysite-com-to-https-secure-mysite-com and get double points!) – fearless_fool Jan 27 '12 at 06:38
-5

DO it in your vhosts file.

Setup a SSL vhost.

In your standard port 80 virtual host. Add this to the config:

Redirect permanent / https://www.mysite.com

This will forward all port 80 requests to https.

edgerunner
  • 14,873
  • 2
  • 57
  • 69
Flukey
  • 6,445
  • 3
  • 46
  • 71