Configure WEBrick to use automatically generated self-signed SSL/HTTPS certificate
Asked Answered
H

1

14

I want to develop my Ruby on Rails application locally with SSL/HTTPS, but I'm having trouble trying to setup a server to use SSL. The following are the things I've already tried so far:

rails server [options]

The rails server command doesn't come with an ssl option (rails server --help):

Usage: rails server [mongrel, thin, etc] [options]
  -p, --port=port         Runs Rails on the specified port.
                          Default: 3000
  -b, --binding=ip        Binds Rails to the specified ip.
                          Default: 0.0.0.0
  -c, --config=file       Use custom rackup configuration file
  -d, --daemon            Make server run as a Daemon.
  -u, --debugger          Enable the debugger
  -e, --environment=name  Specifies the environment to run this server under
                          (test/development/production).
                          Default: development
                          
  -P, --pid=pid           Specifies the PID file.
                          Default: tmp/pids/server.pid

  -h, --help              Show this help message.

Custom WEBrick instance with automatically generated self-signed SSL certificate

My Code

Following along with the WEBrick documentation for HTTPS, I made the following Ruby script that I run as ruby server.rb:

require 'webrick'
include WEBrick

root = File.expand_path './public'

cert_name = [
  %w[CN localhost],
]

server = HTTPServer.new(
  :BindAddress => '127.0.0.1',
  :Port => '4430',
  :DocumentRoot => root,
  :SSLEnable => true,
  :SSLCertName => cert_name # LOOK! SSLCertName IS SET!
)

# Shutdown gracefully on signal interrupt CTRL-C
# http://www.ruby-doc.org/core-2.1.1/Kernel.html#method-i-trap
trap('INT') { server.shutdown }

server.start

According to the documentation I linked to above:

This will start the server with a self-generated self-signed certificate.

and according to the documentation for WEBrick::Config,

WEBrick can automatically create a self-signed certificate if :SSLCertName is set.

The Errors

When I start the server, I get the following output:

INFO  WEBrick 1.3.1
INFO  ruby 2.1.1 (2014-02-24) [x86_64-darwin13.0]
INFO  WEBrick::HTTPServer#start: pid=26059 port=4430

However, when I try to access https://localhost:4430/robots.txt, I get the following error in Chrome 33.0.1750.117:

enter image description here

and the following error when I try the same url in Firefox 27.0.1:

enter image description here

I looked up the ssl_error_rx_record_too_long error, and it looks like it can be caused by a few different things. Maybe WEBrick is still listening for HTTP requests on port 80, but that seems odd considering I explicitly set it to enable SSL on port 4430.

Access Logs

Additionally, here are the access log contents from WEBrick when I make the request for https://localhost:4430/robots.txt from Chrome, but I have no idea what any of it means (it looks like it's encoded in hex or something):

ERROR bad Request-Line `\x16\x03\x01\x02\x00\x01\x00\x01ü\x03\x03S\x15ußð'¦\x14·áÚOá,j\x7FÅ=üüNn#\x02ëý\x0Fø‚\x00\x00(À+À/\x00žÌ\x14Ì\x13\x00œÀ'.
localhost - - [04/Mar/2014:01:42:39 EST] "\x16\x03\x01\x02\x00\x01\x00\x01ü\x03\x03S\x15ußð'¦\x14·áÚOá,j\x7FÅ=üüNn#\x02ëý\x0Fø‚\x00\x00(À+À/\x00žÌ\x14Ì\x13\x00œÀ" 400 417
- -> 
ERROR bad Request-Line `\x16\x03\x01\x02\x00\x01\x00\x01ü\x03\x02S\x15ußj\x05ç©!€¿'ÄÃåë!t…ß\x06pDÒÒ4?”»7\x19\x00\x00\x1EV\x00À'.
localhost - - [04/Mar/2014:01:42:39 EST] "\x16\x03\x01\x02\x00\x01\x00\x01ü\x03\x02S\x15ußj\x05ç©!€¿'ÄÃåë!t…ß\x06pDÒÒ4?”»7\x19\x00\x00\x1EV\x00À" 400 398
- -> 
ERROR bad Request-Line `\x16\x03\x01\x02\x00\x01\x00\x01ü\x03\x01S\x15ußñom¾u<n¨ý9yö“¤Øcƒ{½wh)M@š1;\x00\x00\x1EV\x00À'.
localhost - - [04/Mar/2014:01:42:39 EST] "\x16\x03\x01\x02\x00\x01\x00\x01ü\x03\x01S\x15ußñom¾u<n¨ý9yö“¤Øcƒ{½wh)M@š1;\x00\x00\x1EV\x00À" 400 392
- -> 
ERROR bad URI `\x04ËB¿É\\ ˆ2ðiwñ·*\x02\x06^´\x00@v\x00\x00\x14\x00ÿV\x00\x009\x005\x003\x002\x00\x05\x00\x04\x00/\x00'.
localhost - - [04/Mar/2014:01:42:39 EST] "\x16\x03\x00\x00?\x01\x00\x00;\x03\x00S\x15uß…N®ˆ\r\x04ËB¿É\\ ˆ2ðiwñ·*\x02\x06^´\x00@v\x00\x00\x14\x00ÿV\x00\x009\x005\x003\x002\x00\x05\x00\x04\x00/\x00" 400 389
- -> \x04ËB¿É\\ ˆ2ðiwñ·*\x02\x06^´\x00@v\x00\x00\x14\x00ÿV\x00\x009\x005\x003\x002\x00\x05\x00\x04\x00/\x00

Ruby Source for SSL Module

Also, I checked the Ruby source code for the SSL module, but I don't see anything obvious in there for why this might not be working:

def setup_ssl_context(config) # :nodoc:
  unless config[:SSLCertificate]
    cn = config[:SSLCertName]
    comment = config[:SSLCertComment]
    cert, key = Utils::create_self_signed_cert(1024, cn, comment) # LOOK HERE!
    config[:SSLCertificate] = cert
    config[:SSLPrivateKey] = key
  end
  # etc...
end

# Higher up in the file...
def create_self_signed_cert(bits, cn, comment)
  # etc ...
  cert = OpenSSL::X509::Certificate.new
  cert.version = 2
  cert.serial = 1
  name = OpenSSL::X509::Name.new(cn)
  cert.subject = name
  cert.issuer = name
  # etc ...
end

My Environment

Here are the following things I'm using for development:

  1. OS X Mavericks.
  2. Ruby 2.1.1.
  3. Rails 4.0.3.

Summary

So this is where I'm at currently, and I'm not sure how to proceed. I'm aware that I can just pass my own self-signed certificate file (generated with something like OpenSSL) to WEBrick, but the documentation says that WEBrick can automatically generate its own, and I'm really interested in getting that to work.

I'm also aware that I can use a different webserver like Thin with its --ssl option, but again, I wanted to use WEBrick, because it's the "out-of-the-box" web server for Rails, I want to be able to easily and quickly setup a development SSL web server without having to download additional gems and stuff like that.

I'm also aware that this solution exists, but again, I'm interested in having WEBrick automatically generate its own certificate (and besides, that solution seems to be a little overly complicated for what I'm trying to do).

So does anyone have any ideas of what might be wrong?

Hemolysis answered 4/3, 2014 at 7:44 Comment(0)
H
15

Okay, I figured out what was wrong, I should've paid closer attention to the instructions for HTTPS in WEBrick, this is the exact code from the example:

require 'webrick'
require 'webrick/https' # SEE THIS?

cert_name = [
  %w[CN localhost],
]

server = WEBrick::HTTPServer.new(:Port => 8000,
                                 :SSLEnable => true,
                                 :SSLCertName => cert_name)

See that line that says require 'webrick/https'? I didn't have that in my original config. I didn't think that I'd need it.

Once I added it, my script started serving over HTTPS, and I could finally connect to https://localhost:4430/robots.txt. <face-palm>

Hemolysis answered 4/3, 2014 at 23:52 Comment(5)
If I'm following a Sinatra example, does this just get copied into the app.rb? Or do I create a server.rb that loads the app.rb?Commentative
In recent versions of OpenSSL, the SSLCertName needs to be specified like this: [['CN', 'localhost', OpenSSL::ASN1::PRINTABLESTRING]]Metropolis
@cupcake can you write a tutorial on how to make your localhost rails to https ?Subalternate
@Subalternate unfortunately I don't have time for such a thing. Not only that, but this is probably not a proper way to implement https in a Rails application either (either locally or in production).Hemolysis
@Subalternate you may want to check out this other answer if you're still looking.Melanesian

© 2022 - 2024 — McMap. All rights reserved.