# Set up multiple jupyterhub on same domain with different ports using nginx

**URL:** <https://discourse.jupyter.org/t/set-up-multiple-jupyterhub-on-same-domain-with-different-ports-using-nginx/8706>\
**Category:** JupyterHub\
**Tags:** how-to\
**Created:** [April 9, 2021, 2:49pm UTC](https://discourse.jupyter.org/t/set-up-multiple-jupyterhub-on-same-domain-with-different-ports-using-nginx/8706 "2021-04-09T14:49:14Z")\
**Posts on this page:** 8\
**Page:** 1

<div class="post-metadata">

**Author:** ![fabian278](https://yyz1.discourse-cdn.com/flex031/user_avatar/discourse.jupyter.org/fabian278/32/4139_2.png) [@fabian278](https://discourse.jupyter.org/u/fabian278)\
**Post date:** [April 9, 2021, 2:49pm UTC](https://discourse.jupyter.org/t/set-up-multiple-jupyterhub-on-same-domain-with-different-ports-using-nginx/8706/1 "2021-04-09T14:49:14Z")

</div>

Hello, I have set up two vms with Jupyterhub and all seems to be working as expected, I have used the same domain [jhub.example.com](http://jhub.example.com) and then [jhub.example.com:1234](http://jhub.example.com:1234) and I can access the IUs without issues.

I thin my problem is with nginx configuration, as when I try to go to the admin page and stop the server I get 403. Only at this time.

I can restart the service and it works just fine, but 403 and CORS error in the logs when I try it from the UI.

I have tried different configuration blocks inside my sites-enabled/jupyterhub.conf but still no luck.

Can anybody provide a working configuration example?

I am using Azure AD for authentication, it’s running on Ubuntu 20.04, and this runs docker containers, spawning a new instance per new user (this works)

Thank you

---

<div class="post-metadata">

**Author:** ![manics](https://yyz1.discourse-cdn.com/flex031/user_avatar/discourse.jupyter.org/manics/32/85_2.png) [@manics](https://discourse.jupyter.org/u/manics)\
**Post date:** [April 11, 2021, 4:07pm UTC](https://discourse.jupyter.org/t/set-up-multiple-jupyterhub-on-same-domain-with-different-ports-using-nginx/8706/2 "2021-04-11T16:07:01Z")

</div>

Hi! Are you seeing problems with both of your JupyterHubs, or only one? Can you show us your Nginx and JupyterHub configs with secrets redacted? Thanks!

---

<div class="post-metadata">

**Author:** ![fabian278](https://yyz1.discourse-cdn.com/flex031/user_avatar/discourse.jupyter.org/fabian278/32/4139_2.png) [@fabian278](https://discourse.jupyter.org/u/fabian278)\
**Post date:** [April 12, 2021, 1:48pm UTC](https://discourse.jupyter.org/t/set-up-multiple-jupyterhub-on-same-domain-with-different-ports-using-nginx/8706/3 "2021-04-12T13:48:36Z")

</div>

Hi, thank you for your reply. No, I have just confirmed only vm 2 returns 403 when trying to ‘Stop my server’ from the hub control panel. I will share the configurations for vm01 - jhub.example .com and vm02 jhub.example. com:1234. (Sorry but some url have whitespaces as the forum wouldn’t allow me to post more then 2 urls, they are correct in my actual code)

nginx configuration for vm01

```
server {
        listen 80;
        return 301 https:/ /$host$request_uri;
}
server {
    listen 443 ssl;
    ssl_reject_handshake on;
}

server {
        listen 443 ssl;
        server_name jhub.example. com;

        ssl_certificate /etc/ssl/jupyterhub/certs/ssl.jupyterhub.cert;
        ssl_certificate_key /etc/ssl/jupyterhub/private/ssl.jupyterhub.key;

        ssl_session_cache builtin:1000 shared:SSL:10m;
        ssl_protocols TLSv1.2;
        ssl_ciphers HIGH:!aNULL:!eNULL:!EXPORT:!CAMELLIA:!DES:!MD5:!PSK:!RC4;
        ssl_prefer_server_ciphers on;

        access_log /var/log/nginx/jupyterhub.access.log;

        location / {
                proxy_set_header Host $host;
                proxy_set_header X-Real-IP $remote_addr;
                proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
                proxy_set_header X-Forwarded-Proto $scheme;

                proxy_pass https ://127.0.0.1:8000;
                proxy_read_timeout 90;

                proxy_redirect https ://127.0.0.1:8000 https ://jhub.example;

                # WebSockets support
                proxy_http_version 1.1;
                proxy_set_header Upgrade $http_upgrade;
                proxy_set_header Connection "upgrade";
        }
}

```

nginx configuration for vm02

```
server {
        listen 80;
        return 301 https:/ /$host$request_uri;
}
server {
    listen 443 ssl;
    ssl_reject_handshake on;
}

server {
	 listen 1234 ssl default_server;
	 server_name jhub.example:1234;
	 ssl_certificate /etc/ssl/jupyterhub/certs/ssl.jupyterhub.cert; 
	 ssl_certificate_key /etc/ssl/jupyterhub/private/ssl.jupyterhub.key;
	 location / {
                proxy_pass "https:/ /127.0.0.1:1234";
		proxy_set_header Host $host;
	}
    }

server {
        listen 443 ssl default_server;
        server_name jhub.example;

        ssl_certificate /etc/ssl/jupyterhub/certs/ssl.jupyterhub.cert;
        ssl_certificate_key /etc/ssl/jupyterhub/private/ssl.jupyterhub.key;

        ssl_session_cache builtin:1000 shared:SSL:10m;
        ssl_protocols TLSv1.2;
        ssl_ciphers HIGH:!aNULL:!eNULL:!EXPORT:!CAMELLIA:!DES:!MD5:!PSK:!RC4;
        ssl_prefer_server_ciphers on;

        access_log /var/log/nginx/jupyterhub.access.log;

        location / {
                proxy_set_header Host $host;
                proxy_set_header X-Real-IP $remote_addr;
                proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
                proxy_set_header X-Forwarded-Proto $scheme;

                proxy_pass https:/ /127.0.0.1:8000;
                proxy_read_timeout 90;

                proxy_redirect https:/ /127.0.0.1:8000 https:/ /jhub.example:1234;

                # WebSockets support
                proxy_http_version 1.1;
                proxy_set_header Upgrade $http_upgrade;
                proxy_set_header Connection "upgrade";
       }
}

```

Jupyterhub\_config.py file, almost the same for both vms, only port changes.

```
from oauthenticator.azuread import LocalAzureAdOAuthenticator
from jupyter_client.localinterfaces import public_ips
from dockerspawner import DockerSpawner
from tornado import gen
from jupyterhub.auth import LocalAuthenticator
import re
import os
import docker
import json
import shlex
import subprocess
import pwd
c.Application.log_level = 'DEBUG'
c.Spawner.args = ['--NotebookApp.allow_origin=*']
c.Spawner.http_timeout = 300
c.Spawner.start_timeout = 300

c.JupyterHub.ssl_key = '/etc/ssl/jupyterhub/private/ssl.jupyterhub.key'
c.JupyterHub.ssl_cert = '/etc/ssl/jupyterhub/certs/ssl.jupyterhub.cert'
c.JupyterHub.port = 443
host_name = 'jhub.example. com' #[this url is jhub.example. com:1234 in the vm02]
tenant_id = ''
client_id = ''
client_secret = ''
default_admin = ''
image_map_file_name = "image_map.json"
azure_storage_name=""
azure_file_share_name=""
start_ssh_port_mapping=5101

c.Spawner.default_url = '/lab'
c.JupyterHub.spawner_class = CustomDockerSpawner
c.JupyterHub.logo_file = "/home/jupyterhub/logo.png"
c.DockerSpawner.extra_host_config = {'runtime': 'nvidia', 'pid_mode': 'host', 'cap_drop': ['SYS_MODULE', 'SYS_RAWIO', 'SYS_PACCT', 'SYS_ADMIN', 'SYS_NICE', 'SYS_RESOURCE', 'SYS_TIME', 'SYS_TTY_CONFIG', 'AUDIT_CONTROL', 'MAC_ADMIN',
                                                                                           'MAC_OVERRIDE', 'NET_ADMIN', 'SYSLOG', 'DAC_READ_SEARCH', 'LINUX_IMMUTABLE', 'NET_BROADCAST', 'IPC_LOCK', 'IPC_OWNER', 'SYS_BOOT', 'LEASE', 'WAKE_ALARM', 'BLOCK_SUSPEND'], 'privileged': True, 'devices': ['/dev/fuse']}
c.DockerSpawner.extra_create_kwargs = {'user': 'root'}
c.DockerSpawner.environment = {
    'GRANT_SUDO': '1', 'NVIDIA_DRIVER_CAPABILITIES': 'compute,utility', 'NVIDIA_VISIBLE_DEVICES': 'all'}
c.DockerSpawner.remove = True

with open(image_map_file_name, "r") as image_map_file:
    image_map = json.load(image_map_file)

c.DockerSpawner.image_whitelist = image_map

c.DockerSpawner.notebook_dir = azfiles_dir

c.DockerSpawner.volumes = {'jupyterhub-user-{user}': azfiles_dir,
                           'jupyterhub-ssdp-{user}': ssdprivate_data_dir, 'jupyterhub-ssd': ssdshared_data_dir}

ip = public_ips()[0]

c.JupyterHub.ip = '0.0.0.0'
c.JupyterHub.port = 8000
c.JupyterHub.hub_ip = ip

c.JupyterHub.authenticator_class = NormalizedUsernameLocalAzureAdOAuthenticator

c.Authenticator.admin_users = {default_admin}

c.LocalAuthenticator.create_system_users = True
c.Authenticator.delete_invalid_users = True
c.LocalAzureAdOAuthenticator.tenant_id = tenant_id
c.LocalAzureAdOAuthenticator.oauth_callback_url = 'https:/ /{}/hub/oauth_callback'.format(
    host_name)
c.LocalAzureAdOAuthenticator.client_id = client_id
c.LocalAzureAdOAuthenticator.client_secret = client_secret

```

There are parts of the code in the config file that have been removed, this is working for me as it’s been up for some time now without issues. Only problem there is now is the 403 when stopping.

Thank you for your help.

---

<div class="post-metadata">

**Author:** ![manics](https://yyz1.discourse-cdn.com/flex031/user_avatar/discourse.jupyter.org/manics/32/85_2.png) [@manics](https://discourse.jupyter.org/u/manics)\
**Post date:** [April 12, 2021, 8:48pm UTC](https://discourse.jupyter.org/t/set-up-multiple-jupyterhub-on-same-domain-with-different-ports-using-nginx/8706/4 "2021-04-12T20:48:23Z")

</div>

Thanks, could you also dig out your JupyterHub logs around the time of the error? If you can enable debug logging that would be even better!

---

<div class="post-metadata">

**Author:** ![fabian278](https://yyz1.discourse-cdn.com/flex031/user_avatar/discourse.jupyter.org/fabian278/32/4139_2.png) [@fabian278](https://discourse.jupyter.org/u/fabian278)\
**Post date:** [April 13, 2021, 1:03pm UTC](https://discourse.jupyter.org/t/set-up-multiple-jupyterhub-on-same-domain-with-different-ports-using-nginx/8706/5 "2021-04-13T13:03:55Z")

</div>

Hello, thanks again for your reply.

This is the only thing that happens when trying to stop my server, there is a 403 and CORS error, the rest is usual debug logging. See the first two lines below:

```
Apr 13 12:52:12 VM02 bash[1784]: [W 2021-04-13 12:52:12.152 JupyterHub log:174] 403 DELETE /hub/api/users/someusername/server (@123.12.123.123) 2.35ms
Apr 13 12:52:12 VM02 bash[1784]: [W 2021-04-13 12:52:12.151 JupyterHub base:57] Blocking Cross Origin API request. Referer: https://jhub.example.com:1234/hub/home, Host: jhub.example.com/hub/
Apr 13 12:52:11 VM02 bash[1784]: 'Status': 'running'}
Apr 13 12:52:11 VM02 bash[1784]: 'StartedAt': '2021-03-30T22:19:11.358150395Z',
Apr 13 12:52:11 VM02 bash[1784]: 'Running': True,
Apr 13 12:52:11 VM02 bash[1784]: 'Restarting': False,
Apr 13 12:52:11 VM02 bash[1784]: 'Pid': 8226,
Apr 13 12:52:11 VM02 bash[1784]: 'Paused': False,
Apr 13 12:52:11 VM02 bash[1784]: 'OOMKilled': False,
Apr 13 12:52:11 VM02 bash[1784]: 'FinishedAt': '0001-01-01T00:00:00Z',
Apr 13 12:52:11 VM02 bash[1784]: 'ExitCode': 0,
Apr 13 12:52:11 VM02 bash[1784]: 'Error': '',
Apr 13 12:52:11 VM02 bash[1784]: [D 2021-04-13 12:52:11.468 JupyterHub dockerspawner:761] Container 8cc9281 status: {'Dead': False,
Apr 13 12:52:11 VM02 bash[1784]: [D 2021-04-13 12:52:11.465 JupyterHub dockerspawner:777] Getting container 'jupyter-someotheruser'
Apr 13 12:52:04 VM02 bash[1784]: 'Status': 'running'}
Apr 13 12:52:04 VM02 bash[1784]: 'StartedAt': '2021-03-30T22:06:34.843226462Z',
Apr 13 12:52:04 VM02 bash[1784]: 'Running': True,
Apr 13 12:52:04 VM02 bash[1784]: 'Restarting': False,
Apr 13 12:52:04 VM02 bash[1784]: 'Pid': 6614,
Apr 13 12:52:04 VM02 bash[1784]: 'Paused': False,
Apr 13 12:52:04 VM02 bash[1784]: 'OOMKilled': False,
Apr 13 12:52:04 VM02 bash[1784]: 'FinishedAt': '0001-01-01T00:00:00Z',
Apr 13 12:52:04 VM02 bash[1784]: 'ExitCode': 0,
Apr 13 12:52:04 VM02 bash[1784]: 'Error': '',
Apr 13 12:52:04 VM02 bash[1784]: [D 2021-04-13 12:52:04.987 JupyterHub dockerspawner:761] Container 2158e20 status: {'Dead': False,
Apr 13 12:52:04 VM02 bash[1784]: [D 2021-04-13 12:52:04.984 JupyterHub dockerspawner:777] Getting container 'jupyter-someusername'
Apr 13 12:52:03 VM02 bash[1784]: [W 2021-04-13 12:52:03.616 JupyterHub log:174] 403 DELETE /hub/api/users/someusername/server (@123.12.123.123) 3.13ms
Apr 13 12:52:03 VM02 bash[1784]: [W 2021-04-13 12:52:03.615 JupyterHub base:57] Blocking Cross Origin API request. Referer: https://jhub.example.com:1234/hub/home, Host: jhub.example.com/hub/
Apr 13 12:51:57 VM02 bash[1784]: [D 2021-04-13 12:51:57.803 JupyterHub log:174] 200 GET /hub/static/js/utils.js?v=20210330215732 (@123.12.123.123) 0.65ms

```

I am still trying to make it work, but haven’t had any luck, so if any ideas you can share so I can explore in the meantime, I’ll much appreciate it.

Thank you!

---

<div class="post-metadata">

**Author:** ![manics](https://yyz1.discourse-cdn.com/flex031/user_avatar/discourse.jupyter.org/manics/32/85_2.png) [@manics](https://discourse.jupyter.org/u/manics)\
**Post date:** [April 13, 2021, 7:15pm UTC](https://discourse.jupyter.org/t/set-up-multiple-jupyterhub-on-same-domain-with-different-ports-using-nginx/8706/6 "2021-04-13T19:15:33Z")

</div>

> [@fabian278](#):
>
> `Blocking Cross Origin API request. Referer: https://jhub.example.com:1234/hub/home, Host: jhub.example.com/hub/`

It looks like there’s a mismatch in the host headers- for some reason the port is being dropped (different ports for the same host are considered different origins). You could try setting a `X-Forward-*` or `Forward` headers.

There was a similar sounding PR to fix a related issue in [Fix #2284 must be sent from authorization page by elgalu · Pull Request #3219 · jupyterhub/jupyterhub · GitHub](https://github.com/jupyterhub/jupyterhub/pull/3219) so there’s a chance it’s a bug, but to verify this we’d need to see the headers that Nginx is sending to JupyterHub.

---

<div class="post-metadata">

**Author:** ![fabian278](https://yyz1.discourse-cdn.com/flex031/user_avatar/discourse.jupyter.org/fabian278/32/4139_2.png) [@fabian278](https://discourse.jupyter.org/u/fabian278)\
**Post date:** [April 13, 2021, 8:00pm UTC](https://discourse.jupyter.org/t/set-up-multiple-jupyterhub-on-same-domain-with-different-ports-using-nginx/8706/7 "2021-04-13T20:00:01Z")

</div>

Hello, thanks for your answer. Seems like this is being set in nginx configuration but still, the error persists:

> [@fabian278](#):
>
> `proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;`

How can I see and share with you the headers that are being passed?

Thank you.

---

<div class="post-metadata">

**Author:** ![minrk](https://yyz1.discourse-cdn.com/flex031/user_avatar/discourse.jupyter.org/minrk/32/13_2.png) [@minrk](https://discourse.jupyter.org/u/minrk)\
**Post date:** [April 26, 2021, 10:18am UTC](https://discourse.jupyter.org/t/set-up-multiple-jupyterhub-on-same-domain-with-different-ports-using-nginx/8706/8 "2021-04-26T10:18:30Z")

</div>

The preserve-host-header config that’s important is:

```auto
proxy_set_header Host $host;

```
