这是indexloc提供的服务,不要输入任何密码
Skip to content

Conversation

@lmars
Copy link
Contributor

@lmars lmars commented Feb 26, 2015

I deploy a Rails app using Dokku which uses subdomain based routing, so requests for admin.example.com and api.example.com get handled differently.

I was previously handling this by deploying multiple apps, each with a single domain and TLS cert, but I now have to push to 3 remotes to deploy the same app.

The change here fixes what looks like intended behaviour to support multiple domains using a wildcard certificate (see comments in a4d79e2 for further explanation of the change).

Signed-off-by: Lewis Marshall <lewis@lmars.net>
Previous to this change, each TLS domain would be written to nginx.conf
using the nginx.ssl.conf template (lines 69-73) but with an empty
"server_name" directive (because NOSSL_SERVER_NAME was not set).

This would then become irrelevant because nginx.conf would get truncated
on line 88, and a single parsing of the template would then be written to
nginx.conf on line 89, meaning only the last TLS domain would be set up to
actually use TLS.

This patch changes this behaviour so that all TLS domains get added to
nginx.conf using the nginx.ssl.conf template (which includes redirecting
HTTP -> HTTPS), and all non-TLS domains get added using the nginx.conf
template, so do not get redirected to a TLS domain.

Signed-off-by: Lewis Marshall <lewis@lmars.net>
@michaelshobbs
Copy link
Member

First off, thanks for taking the time to contribute. I've banged around on this a little bit and need some clarification.

Here are my scenarios:

  1. Wildcard
  • App name - node-js-app
  • Two domains - node-js-app.dokku.me and www.test.dokku.me
  • Wildcard cert for *.dokku.me
  1. Host-based cert with SANS
    • App name - node-js-app
    • Two domains - test.dokku.me and www.test.dokku.me
    • SSL Cert with Alt names with aforementioned domains

Scenario 1 works as expected. http://node-js-app.dokku.me redirects to https://node-js-app.dokku.me and http://www.test.dokku.me redirects to https://www.test.dokku.me.

Scenario 2 redirects as expected but dokku urls returns https for everything. This is due to an earlier assumption that we would redirect everything to https

So we need to decide if non-wildcard redirects should behave differently or modify dokku urls to be smarter.

@josegonzalez
Copy link
Member

Should dokku urls return non-https urls?

@michaelshobbs
Copy link
Member

In scenario 2, yes. As the cert doesn't contain node-js-app.dokku.me as a valid CN to secure.

@josegonzalez
Copy link
Member

Yeah, so I guess dokku urls should be smarter about that. You wrote the https check bits, so I'll leave that in your capable hands :)

@michaelshobbs
Copy link
Member

@lmars feel like taking a stab at dokku urls?

@lmars
Copy link
Contributor Author

lmars commented Feb 26, 2015

@michaelshobbs

Scenario 1 works as expected. http://node-js-app.dokku.me redirects to https://node-js-app.dokku.me and http://www.test.dokku.me redirects to https://www.test.dokku.me.

Yes this is the redirect behaviour I want, but your example is actually incorrect. A CN of *.dokku.me only matches direct subdomains of dokku.me, so www.test.dokku.me should be a non-SSL domain (see RFC 2818):

$ curl --cacert server.crt https://test.dokku.me
nodejs/express

$ curl --cacert server.crt https://www.test.dokku.me
curl: (51) SSL: certificate subject name '*.dokku.me' does not match target host name 'www.test.dokku.me'

This is broken on master and I think should be handled in a separate issue / PR.

Scenario 2 redirects as expected but dokku urls returns https for everything. This is due to an earlier assumption that we would redirect everything to https

Again this is broken on master and I think should be fixed separately:

# on master

$ dokku urls $TEST_APP
http://test.dokku.me

$ dokku nginx:import-ssl $TEST_APP < server_wildcard.tar 
-----> Configuring SSL for test.dokku.me...
-----> Configuring test.dokku.me...
-----> Creating https nginx.conf

$ dokku urls $TEST_APP
https://test.dokku.me

$ dokku domains:add $TEST_APP dokku.example.com
-----> Configuring SSL for test.dokku.me...
-----> Configuring test.dokku.me...
-----> Configuring dokku.example.com...
-----> Creating https nginx.conf

$ dokku urls $TEST_APP
https://test.dokku.me
https://dokku.example.com    # <--- this should be http://dokku.example.com

$ curl --cacert server.crt https://test.dokku.me
nodejs/express

$ curl --cacert server.crt https://dokku.example.com
curl: (51) SSL: certificate subject name '*.dokku.me' does not match target host name 'dokku.example.com'

# http links both redirect to the SSL domain:
$ curl -so /dev/null -w "%{redirect_url}\n" http://test.dokku.me
https://test.dokku.me/
$ curl -so /dev/null -w "%{redirect_url}\n" http://dokku.example.com
https://test.dokku.me/

# I actually think here that http://dokku.example.com should *not* redirect

The problem I am trying to solve in this PR is that valid wildcard domains should redirect to their https equivalent, not to the last configured SSL domain, which is what happens on master:

$ dokku nginx:import-ssl $TEST_APP < server_wildcard.tar
$ dokku domains:add $TEST_APP admin.dokku.me
$ dokku domains:add $TEST_APP dashboard.dokku.me
$ dokku domains:add $TEST_APP api.dokku.me
$ dokku urls $TEST_APP
https://test.dokku.me
https://admin.dokku.me
https://dashboard.dokku.me
https://api.dokku.me

$ curl -so /dev/null -w "%{http_code} %{redirect_url}\n" http://test.dokku.me
301 https://api.dokku.me/

$ curl -so /dev/null -w "%{http_code} %{redirect_url}\n" http://admin.dokku.me                                                      
301 https://api.dokku.me/

$ curl -so /dev/null -w "%{http_code} %{redirect_url}\n" http://dashboard.dokku.me                                                  
301 https://api.dokku.me/

$ curl -so /dev/null -w "%{http_code} %{redirect_url}\n" http://api.dokku.me                                                        
301 https://api.dokku.me/

@michaelshobbs
Copy link
Member

Oh yeah good catch there. I've been ignoring the SSL warnings since I'm using a self signed cert. The SSL stuff could be a lot better.

@josegonzalez: it would be great get the nginx-vhosts functionality fully documented with how it is supposed to work and then ensure our test suite backs that up. 😄

@lmars
Copy link
Contributor Author

lmars commented Feb 27, 2015

@michaelshobbs ok, so is there anything you want me to do before potentially merging this?

@michaelshobbs
Copy link
Member

I'd personally like to see url/urls work correctly with this. I know you mentioned you thought that should be a separate PR but this commit would 'break' that functionality.

@lmars
Copy link
Contributor Author

lmars commented Feb 28, 2015

@michaelshobbs

I'd personally like to see url/urls work correctly with this. I know you mentioned you thought that should be a separate PR but this commit would 'break' that functionality.

As mentioned earlier, the changes in this PR do not affect dokku urls, it is currently broken on master, see #1013.

@michaelshobbs
Copy link
Member

I see where you are coming from and obviously this PR does not actively change how dokku urls works. However this change does break an assumption that was made about how dokku urls works and this makes the information reported by it incorrect. That's all I'm saying. I'd like to see that bit fixed prior to this going into master so we don't have incorrect urls being returned. Does that make sense?

@michaelshobbs
Copy link
Member

Ha! Never mind that last bit. Just saw the other PR. 😄 Thanks!

@michaelshobbs
Copy link
Member

Tested this combined with #1013 and I think we're pretty close. One thing I noticed was that domains that partially match the cert CN, get SSLd and redirected in the nginx config. (Same errant case you pointed out originally.) Thoughts on fixing that here? Other than that, I think this one is good to go.

root@dokku:/home/dokku# openssl x509 -in /home/dokku/tls/server.crt -noout -subject
subject= /C=US/ST=California/L=San Francisco/OU=Dokku Me, LLC/CN=*.dokku.me
root@dokku:/home/dokku# dokku domains node-js-app
=====> node-js-app Domain Names
node-js-app.dokku.me
test.dokku2.me
www.node-js-app.dokku.me
node-js-app2.dokku.me
root@dokku:/home/dokku# dokku urls node-js-app
https://node-js-app.dokku.me
https://www.node-js-app.dokku.me
https://node-js-app2.dokku.me
http://test.dokku2.me
server {
  listen      [::]:80;
  listen      80;
  server_name www.node-js-app.dokku.me;
  return 301 https://www.node-js-app.dokku.me$request_uri;
}

server {
  listen      [::]:443 ssl spdy;
  listen      443 ssl spdy;
  server_name www.node-js-app.dokku.me;


  keepalive_timeout   70;
  add_header          Alternate-Protocol  443:npn-spdy/2;
  location    / {
    proxy_pass  http://node-js-app;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection upgrade;
    proxy_set_header Host $http_host;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_set_header X-Forwarded-For $remote_addr;
    proxy_set_header X-Forwarded-Port $server_port;
    proxy_set_header X-Request-Start $msec;
  }
  include /home/dokku/node-js-app/nginx.conf.d/*.conf;
}

As per RFC 2818 [0], a CN of *.dokku.me will only match direct
subdomains of dokku.me, not sub-subdomains like www.test.dokku.me, but
Dokku currently enables TLS for subdomains of all levels.

I have changed the regex from .*\.dokku\.me to [^.]*\.dokku\.me so TLS
is only enabled for direct subdomains.

[0] - http://tools.ietf.org/html/rfc2818#section-3.1

Signed-off-by: Lewis Marshall <lewis@lmars.net>
@lmars
Copy link
Contributor Author

lmars commented Mar 8, 2015

@michaelshobbs I have fixed the sub-subdomain match issue: 9202f11

@michaelshobbs
Copy link
Member

thanks!

michaelshobbs added a commit that referenced this pull request Mar 9, 2015
Support multiple domains using a wildcard TLS certificate
@michaelshobbs michaelshobbs merged commit b468c2e into dokku:master Mar 9, 2015
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants