Hi All,
I am pretty new to SSHSpawner and have encountered multiple issues when trying to spawn a user from a remote machine. Here’s my scenario: I want to launch my JupyterHub on a machine (IP: 10.0.2.8) and store all user accounts on another machine (IP: 10.0.2.9). However when JupyterHub attempts to load up the spawner, it is hitting a timeout error indicating that the server didn’t respond in time.
Below is my jupyterhub_config.py
import os, pwd
import inspect, concurrent,asyncio
from subprocess import check_call, Popen, STDOUT
from sshspawner.sshspawner import SSHSpawner
c = get_config()
c.OAuthenticator.authorize_url = "https://auth.globus.org/v2/oauth2/authorize"
c.OAuthenticator.token_url = "https://auth.globus.org/v2/oauth2/token"
c.OAuthenticator.userdata_url = "https://auth.globus.org/v2/oauth2/userinfo"
c.OAuthenticator.allow_all = True
c.JupyterHub.authenticator_class = "globus"
c.OAuthenticator.oauth_callback_url = "http://127.0.0.1:8888/hub/oauth_callback"
c.OAuthenticator.client_id = <Client_id>
c.OAuthenticator.client_secret = <Secret>
c.OAuthenticator.enable_auth_state = True
c.OAuthenticator.scope = ['openid', 'profile', 'email']
c.OAuthenticator.exclude_tokens = ['auth.globus.org']
c.OAuthenticator.logout_redirect_url = 'https://globus.org/logout'
c.OAuthenticator.revoke_tokens_on_logout = False
c.JupyterHub.admin_access = True
c.JupyterHub.base_url = '/'
c.JupyterHub.bind_url = 'http://127.0.0.1:8888'
c.JupyterHub.data_files_path = '/opt/jupyterhub/share/jupyterhub/'
c.JupyterHub.debug_proxy = True
c.JupyterHub.hub_bind_url = 'http://127.0.0.1:8087'
c.JupyterHub.hub_port = 8087
c.JupyterHub.hub_ip = '127.0.0.1'
c.JupyterHub.internal_ssl = True
c.JupyterHub.recreate_internal_certs = True
c.JupyterHub.spawner_class = 'sshspawner.sshspawner.SSHSpawner'
c.SSHSpawner.remote_hosts = ['10.0.2.9']
c.SSHSpawner.remote_port = '22'
c.SSHSpawner.ssh_command = 'ssh'
c.SSHSpawner.debug = True
c.SSHSpawner.ssh_keyfile = '/home/<username>/.ssh/id_rsa'
c.SSHSpawner.remote_port_command = '/usr/bin/python3 /home/<username of remote computer>/get_port.py -i'
c.Spawner.args = ['--debug']
c.Spawner.cmd = ['jupyterhub-singleuser']
c.Spawner.debug = True
c.Spawner.default_url = '/lab'
c.Spawner.disable_user_config = True
c.Spawner.notebook_dir = '/opt/{username}'
c.Authenticator.auto_login = True
if 'JUPYTERHUB_CRYPT_KEY' not in os.environ:
c.CryptKeeper.keys = [ os.urandom(32) ]
On the remote machine, I have created a user account in /opt/ that matches the username used to log in to JupyterHub, and I have ensured that I am able to log in using the certificate.
Below is the captured log
[E 2024-06-16 14:59:48.569 JupyterHub log:184] {
"X-Forwarded-Host": "127.0.0.1:8888",
"X-Forwarded-Proto": "http",
"X-Forwarded-Port": "8888",
"X-Forwarded-For": "127.0.0.1",
"Priority": "u=1",
"If-None-Match": "\"<some ID>\"",
"Sec-Fetch-Site": "same-origin",
"Sec-Fetch-Mode": "navigate",
"Sec-Fetch-Dest": "document",
"Upgrade-Insecure-Requests": "1",
"Cookie": "jupyterhub-hub-login=[secret]; _xsrf=[secret]; jupyterhub-session-id=[secret]",
"Connection": "keep-alive",
"Sec-Gpc": "1",
"Dnt": "1",
"Referer": "http://127.0.0.1:8888/hub/spawn-pending/jamesleong123098",
"Accept-Encoding": "gzip, deflate, br, zstd",
"Accept-Language": "en-US,en;q=0.5",
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8",
"User-Agent": "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:126.0) Gecko/20100101 Firefox/126.0",
"Host": "127.0.0.1:8888"
}
[E 2024-06-16 14:59:48.569 JupyterHub log:192] 500 GET /hub/spawn-pending/jamesleong123098 (jamesleong123098@127.0.0.1) 40.31ms
[D 2024-06-16 14:59:49.782 JupyterHub scopes:1010] Checking access to /hub/spawn/jamesleong123098 via scope servers!server=jamesleong123098/
[D 2024-06-16 14:59:49.782 JupyterHub user:262] Discarding failed spawner jamesleong123098
[D 2024-06-16 14:59:49.782 JupyterHub user:496] Creating <class 'sshspawner.sshspawner.SSHSpawner'> for jamesleong123098:
[D 2024-06-16 14:59:49.785 JupyterHub pages:216] Triggering spawn with default options for jamesleong123098
[D 2024-06-16 14:59:49.785 JupyterHub base:411] Refreshing auth for jamesleong123098
[D 2024-06-16 14:59:49.786 JupyterHub base:1095] Initiating spawn for jamesleong123098
[D 2024-06-16 14:59:49.786 JupyterHub base:1099] 0/100 concurrent spawns
[D 2024-06-16 14:59:49.786 JupyterHub base:1104] 0 active servers
[I 2024-06-16 14:59:49.827 JupyterHub provider:661] Creating oauth client jupyterhub-user-jamesleong123098
[D 2024-06-16 14:59:49.874 JupyterHub user:909] Creating internal SSL certs for jamesleong123098
[I 2024-06-16 14:59:49.875 JupyterHub spawner:1226] Creating certs for jamesleong123098: DNS:localhost;IP:127.0.0.1
[D 2024-06-16 14:59:50.100 JupyterHub user:912] Calling Spawner.start for jamesleong123098
[D 2024-06-16 14:59:50.104 JupyterHub sshspawner:229] Remote host was set to 10.0.2.9.
[I 2024-06-16 14:59:50.787 JupyterHub log:192] 302 GET /hub/spawn/jamesleong123098 -> /hub/spawn-pending/jamesleong123098 (jamesleong123098@127.0.0.1) 1014.25ms
[D 2024-06-16 14:59:50.799 JupyterHub scopes:1010] Checking access to /hub/spawn-pending/jamesleong123098 via scope servers!server=jamesleong123098/
[I 2024-06-16 14:59:50.800 JupyterHub pages:397] jamesleong123098 is pending spawn
[I 2024-06-16 14:59:50.802 JupyterHub log:192] 200 GET /hub/spawn-pending/jamesleong123098 (jamesleong123098@127.0.0.1) 10.72ms
[D 2024-06-16 14:59:50.813 JupyterHub sshspawner:257] ip=10.0.2.9 port=39613
[D 2024-06-16 14:59:50.813 JupyterHub sshspawner:233] Remote IP was set to 10.0.2.9.
[D 2024-06-16 14:59:50.874 JupyterHub scopes:1010] Checking access to /hub/api/users/jamesleong123098/server/progress via scope read:servers!server=jamesleong123098/
[D 2024-06-16 14:59:51.823 JupyterHub sshspawner:298] /tmp/jamesleong123098_run.sh was written as:
#!/bin/bash
export PATH=/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin
export LANG=en_US.UTF-8
export JUPYTERHUB_API_TOKEN=<Token>
export JPY_API_TOKEN=<API Token>
export JUPYTERHUB_ADMIN_ACCESS=1
export JUPYTERHUB_CLIENT_ID=jupyterhub-user-jamesleong123098
export JUPYTERHUB_COOKIE_HOST_PREFIX_ENABLED=0
export JUPYTERHUB_HOST=
export JUPYTERHUB_OAUTH_CALLBACK_URL=/user/jamesleong123098/oauth_callback
export JUPYTERHUB_OAUTH_SCOPES=["access:servers!server=jamesleong123098/", "access:servers!user=jamesleong123098"]
export JUPYTERHUB_OAUTH_ACCESS_SCOPES=["access:servers!server=jamesleong123098/", "access:servers!user=jamesleong123098"]
export JUPYTERHUB_OAUTH_CLIENT_ALLOWED_SCOPES=[]
export JUPYTERHUB_USER=jamesleong123098
export JUPYTERHUB_SERVER_NAME=
export JUPYTERHUB_API_URL=
export JUPYTERHUB_ACTIVITY_URL=https://127.0.0.1:8087/hub/api/users/jamesleong123098/activity
export JUPYTERHUB_BASE_URL=/
export JUPYTERHUB_SERVICE_PREFIX=/user/jamesleong123098/
export JUPYTERHUB_SERVICE_URL=https://127.0.0.1:0/user/jamesleong123098/
export JUPYTERHUB_PUBLIC_URL=
export JUPYTERHUB_PUBLIC_HUB_URL=
export JUPYTERHUB_SSL_KEYFILE=.jupyterhub-resources/user-jamesleong123098.key
export JUPYTERHUB_SSL_CERTFILE=.jupyterhub-resources/user-jamesleong123098.crt
export JUPYTERHUB_SSL_CLIENT_CA=.jupyterhub-resources/notebooks-ca_trust.crt
export JUPYTERHUB_ROOT_DIR=/opt/jamesleong123098
export JUPYTERHUB_DEFAULT_URL=/lab
export JUPYTERHUB_DEBUG=1
export JUPYTERHUB_DISABLE_USER_CONFIG=1
export GLOBUS_LOCAL_ENDPOINT=
export GLOBUS_DATA=<Some super long data>
unset XDG_RUNTIME_DIR
touch .jupyter.log
chmod 600 .jupyter.log
jupyterhub-singleuser --debug < /dev/null >> .jupyter.log 2>&1 & pid=$!
echo $pid
[D 2024-06-16 14:59:52.276 JupyterHub sshspawner:306] exec_notebook status=0
[D 2024-06-16 14:59:52.277 JupyterHub sshspawner:183] Starting User: jamesleong123098, PID: 1829
[D 2024-06-16 14:59:52.293 JupyterHub spawner:1432] Polling subprocess every 30s
[D 2024-06-16 14:59:52.303 JupyterHub utils:292] Waiting 30s for server at https://10.0.2.9:39613/user/jamesleong123098/api
[D 2024-06-16 15:00:00.203 JupyterHub sshspawner:330] command: kill -s 0 1829 < /dev/null returned --- bash: line 0: kill: (1829) - No such process
--- 1
[D 2024-06-16 15:00:00.203 JupyterHub sshspawner:203] Polling returned False
[D 2024-06-16 15:00:00.203 JupyterHub sshspawner:233] Remote IP was set to remote_ip.
[W 2024-06-16 15:00:23.085 JupyterHub user:1050] jamesleong123098's server never showed up at https://10.0.2.9:39613/user/jamesleong123098/ after 30 seconds. Giving up.
[D 2024-06-16 15:00:23.086 JupyterHub user:1095] Stopping jamesleong123098
[D 2024-06-16 15:00:23.095 JupyterHub user:1117] Deleting oauth client jupyterhub-user-jamesleong123098
[D 2024-06-16 15:00:23.118 JupyterHub user:1120] Finished stopping jamesleong123098
[E 2024-06-16 15:00:23.140 JupyterHub gen:630] Exception in Future <Task finished name='Task-27692' coro=<BaseHandler.spawn_single_user.<locals>.finish_user_spawn() done, defined at /opt/jupyterhub/lib/python3.8/site-packages/jupyterhub/handlers/base.py:1115> exception=TimeoutError("Server at https://10.0.2.9:39613/user/jamesleong123098/api didn't respond in 30 seconds")> after timeout
Traceback (most recent call last):
File "/opt/jupyterhub/lib/python3.8/site-packages/tornado/gen.py", line 625, in error_callback
future.result()
File "/opt/jupyterhub/lib/python3.8/site-packages/jupyterhub/handlers/base.py", line 1122, in finish_user_spawn
await spawn_future
File "/opt/jupyterhub/lib/python3.8/site-packages/jupyterhub/user.py", line 1028, in spawn
await self._wait_up(spawner)
File "/opt/jupyterhub/lib/python3.8/site-packages/jupyterhub/user.py", line 1071, in _wait_up
raise e
File "/opt/jupyterhub/lib/python3.8/site-packages/jupyterhub/user.py", line 1042, in _wait_up
resp = await server.wait_up(
File "/opt/jupyterhub/lib/python3.8/site-packages/jupyterhub/utils.py", line 322, in wait_for_http_server
re = await exponential_backoff(
File "/opt/jupyterhub/lib/python3.8/site-packages/jupyterhub/utils.py", line 265, in exponential_backoff
raise asyncio.TimeoutError(fail_message)
asyncio.exceptions.TimeoutError: Server at https://10.0.2.9:39613/user/jamesleong123098/api didn't respond in 30 seconds
Below is a sample of where it got stuck
From this point onward, I am not entirely sure what is happening with the spawner. Any help or direction is greatly appreciated.
Best,
James