Repository: jupyterhub/jupyterhub

Issue:
Allow setting `hub_connect_port` too
Currently it looks like we can only set `hub_connect_ip` - not the port. If the hub is receiving traffic on a different port than it is listening on (because there's an nginx in front, for example) this doesn't work.


Discussion:
Yeah, without this everything becomes a little wonky, as single user servers are told the wrong port to connect to as well.

Resolving patch:
diff --git a/jupyterhub/app.py b/jupyterhub/app.py
--- a/jupyterhub/app.py
+++ b/jupyterhub/app.py
@@ -400,6 +400,7 @@ def _deprecated_proxy_api(self, change):
         See `hub_connect_ip` for cases where the bind and connect address should differ.
         """
     ).tag(config=True)
+
     hub_connect_ip = Unicode('',
         help="""The ip or hostname for proxies and spawners to use
         for connecting to the Hub.
@@ -412,6 +413,18 @@ def _deprecated_proxy_api(self, change):
         .. versionadded:: 0.8
         """
     ).tag(config=True)
+
+    hub_connect_port = Integer(
+        0,
+        help="""
+        The port for proxies & spawners to connect to the hub on.
+
+        Used alongside `hub_connect_ip`
+
+        .. versionadded:: 0.8
+        """
+    ).tag(config=True)
+
     hub_prefix = URLPrefix('/hub/',
         help="The prefix for the hub server.  Always /base_url/hub/"
     )
@@ -856,6 +869,8 @@ def init_hub(self):
         )
         if self.hub_connect_ip:
             self.hub.connect_ip = self.hub_connect_ip
+        if self.hub_connect_port:
+            self.hub.connect_port = self.hub_connect_port
 
     @gen.coroutine
     def init_users(self):
diff --git a/jupyterhub/handlers/base.py b/jupyterhub/handlers/base.py
--- a/jupyterhub/handlers/base.py
+++ b/jupyterhub/handlers/base.py
@@ -592,7 +592,7 @@ def get(self, name, user_path):
             port = host_info.port
             if not port:
                 port = 443 if host_info.scheme == 'https' else 80
-            if port != Server.from_url(self.proxy.public_url).port and port == self.hub.port:
+            if port != Server.from_url(self.proxy.public_url).connect_port and port == self.hub.connect_port:
                 self.log.warning("""
                     Detected possible direct connection to Hub's private ip: %s, bypassing proxy.
                     This will result in a redirect loop.
diff --git a/jupyterhub/objects.py b/jupyterhub/objects.py
--- a/jupyterhub/objects.py
+++ b/jupyterhub/objects.py
@@ -28,6 +28,7 @@ class Server(HasTraits):
 
     ip = Unicode()
     connect_ip = Unicode()
+    connect_port = Integer()
     proto = Unicode('http')
     port = Integer()
     base_url = URLPrefix('/')
@@ -50,6 +51,17 @@ def _connect_ip(self):
         else:
             return self.ip
 
+    @property
+    def _connect_port(self):
+        """
+        The port to use when connecting to this server.
+
+        Defaults to self.port, but can be overridden by setting self.connect_port
+        """
+        if self.connect_port:
+            return self.connect_port
+        return self.port
+
     @classmethod
     def from_url(cls, url):
         """Create a Server from a given URL"""
@@ -93,7 +105,7 @@ def host(self):
         return "{proto}://{ip}:{port}".format(
             proto=self.proto,
             ip=self._connect_ip,
-            port=self.port,
+            port=self._connect_port,
         )
 
     @property
@@ -119,11 +131,11 @@ def wait_up(self, timeout=10, http=False):
         if http:
             return wait_for_http_server(self.url, timeout=timeout)
         else:
-            return wait_for_server(self._connect_ip, self.port, timeout=timeout)
+            return wait_for_server(self._connect_ip, self._connect_port, timeout=timeout)
 
     def is_up(self):
         """Is the server accepting connections?"""
-        return can_connect(self.ip or '127.0.0.1', self.port)
+        return can_connect(self._connect_ip, self._connect_port)
 
 
 class Hub(Server):


Test patch: