Repository: jupyterhub/jupyterhub

Issue:
Guidance on how to start JupyterHub with SSL
Greetings!

I have jupyterhub working fine on localhost with PAM authentication and am quite excited about moving forward with deployment in my organization. The documentation strongly suggests running jupyterhub with SSL. When I try running the ip/ssl example from the documentation:

```
dude1@dude1-VirtualBox:~/Documents$ ls
ca.cert     certtest.perm         jupyterhub_config.py      jupyterhub.sqlite
ca.key4096  First Notebook.ipynb  jupyterhub_cookie_secret  keytest.key
dude1@dude1-VirtualBox:~/Documents$ sudo jupyterhub --ip 10.0.1.2 --port 443 --ssl-key ca.key4096 --ssl-cert ca.cert
[sudo] password for dude1: 
[I 2016-03-03 16:25:03.624 JupyterHub app:523] Loading cookie_secret from /home/dude1/Documents/jupyterhub_cookie_secret
[W 2016-03-03 16:25:03.645 JupyterHub app:258] 
    Generating CONFIGPROXY_AUTH_TOKEN. Restarting the Hub will require restarting the proxy.
    Set CONFIGPROXY_AUTH_TOKEN env or JupyterHub.proxy_auth_token config to avoid this message.

[W 2016-03-03 16:25:03.659 JupyterHub app:642] No admin users, admin interface will be unavailable.
[W 2016-03-03 16:25:03.659 JupyterHub app:643] Add any administrative users to `c.Authenticator.admin_users` in config.
[I 2016-03-03 16:25:03.659 JupyterHub app:669] Not using whitelist. Any authenticated user will be allowed.
[I 2016-03-03 16:25:03.673 JupyterHub app:1052] Hub API listening on http://localhost:8081/hub/
[C 2016-03-03 16:27:10.921 JupyterHub app:1058] Failed to start proxy
    Traceback (most recent call last):
      File "/usr/local/lib/python3.4/dist-packages/jupyterhub/app.py", line 1056, in start
        yield self.start_proxy()
      File "/usr/local/lib/python3.4/dist-packages/jupyterhub/app.py", line 770, in start_proxy
        if self.proxy.public_server.is_up() or self.proxy.api_server.is_up():
      File "/usr/local/lib/python3.4/dist-packages/jupyterhub/orm.py", line 117, in is_up
        socket.create_connection((self.ip or localhost(), self.port))
      File "/usr/lib/python3.4/socket.py", line 512, in create_connection
        raise err
      File "/usr/lib/python3.4/socket.py", line 503, in create_connection
        sock.connect(sa)
    TimeoutError: [Errno 110] Connection timed out
```

I get the following error. I notice the HUB API is not listening on SSL. Does the HUB API need to be? I'm obviously missing something here so any tips?



Discussion:
What version of JupyterHub (git commit, if running from a repo)?

I think this is a regression in the connection-checking in 0.4. I believe I have a fix.

Wrong button...


Resolving patch:
diff --git a/jupyterhub/orm.py b/jupyterhub/orm.py
--- a/jupyterhub/orm.py
+++ b/jupyterhub/orm.py
@@ -4,9 +4,7 @@
 # Distributed under the terms of the Modified BSD License.
 
 from datetime import datetime
-import errno
 import json
-import socket
 
 from tornado import gen
 from tornado.log import app_log
@@ -26,7 +24,7 @@
 
 from .utils import (
     random_port, url_path_join, wait_for_server, wait_for_http_server,
-    new_token, hash_token, compare_token,
+    new_token, hash_token, compare_token, can_connect,
 )
 
 
@@ -113,25 +111,7 @@ def wait_up(self, timeout=10, http=False):
     
     def is_up(self):
         """Is the server accepting connections?"""
-        try:
-            socket.create_connection((self.ip or '127.0.0.1', self.port))
-        except socket.error as e:
-            if e.errno == errno.ENETUNREACH:
-                try:
-                    socket.create_connection((self.ip or '127.0.0.1', self.port))
-                except socket.error as e:
-                    if e.errno == errno.ECONNREFUSED:
-                        return False
-                    else:
-                        raise
-                else:
-                    return True
-            elif e.errno == errno.ECONNREFUSED:
-                return False
-            else:
-                raise
-        else:
-            return True
+        return can_connect(self.ip or '127.0.0.1', self.port)
 
 
 class Proxy(Base):
diff --git a/jupyterhub/utils.py b/jupyterhub/utils.py
--- a/jupyterhub/utils.py
+++ b/jupyterhub/utils.py
@@ -30,22 +30,32 @@ def random_port():
 ISO8601_ms = '%Y-%m-%dT%H:%M:%S.%fZ'
 ISO8601_s = '%Y-%m-%dT%H:%M:%SZ'
 
+def can_connect(ip, port):
+    """Check if we can connect to an ip:port
+    
+    return True if we can connect, False otherwise.
+    """
+    try:
+        socket.create_connection((ip, port))
+    except socket.error as e:
+        if e.errno not in {errno.ECONNREFUSED, errno.ETIMEDOUT}:
+            app_log.error("Unexpected error connecting to %s:%i %s",
+                ip, port, e
+            )
+        return False
+    else:
+        return True
+
 @gen.coroutine
 def wait_for_server(ip, port, timeout=10):
     """wait for any server to show up at ip:port"""
     loop = ioloop.IOLoop.current()
     tic = loop.time()
     while loop.time() - tic < timeout:
-        try:
-            socket.create_connection((ip, port))
-        except socket.error as e:
-            if e.errno != errno.ECONNREFUSED:
-                app_log.error("Unexpected error waiting for %s:%i %s",
-                    ip, port, e
-                )
-            yield gen.sleep(0.1)
-        else:
+        if can_connect(ip, port):
             return
+        else:
+            yield gen.sleep(0.1)
     raise TimeoutError("Server at {ip}:{port} didn't respond in {timeout} seconds".format(
         **locals()
     ))


Test patch: