Cant create new launcer entry using jupyter-server-proxy

Hi! i am kinda new to jupyter(hub), I am running into trouble creating a very basic test entry…

When trying to create a basic test setup following the installation:

c.ServerProxy.servers = {
    "test-server": {
        "command": ["echo", "Hello_World"]
    }
}

I get a launcher with the entry missing…

also trying to connect via https://myFQDN/hub/test-server i get no command or any kind of log about the entry.

i haven’t been able to get past this. (or find any other related issues)

Setup:
OS: Contaired setup: jupyterhub/jupyterhub:
Version(s): jupyterhub: 5.2.0, Python: 3.10.12

Just to check if you are placing this config in right file, this must go into jupyter_server_config.py that is placed in one of the config directories reported by jupyter --paths in your JupyterLab server.

Once the config is placed in right file, assuming your JupyterHub user is foo and you are using a unnamed default server, you must verify the new registered endpoint at https://myFQDN/hub/foo/test-server/.

Thanks for the quick reply!

I also had that doubt initially, i am pointing to this config explicitly in my startup command, some other parts of the config (auth) is being read so that’s not the issue

your right, in my example i forgot the user in my URL. my actual URL is: https://myFQDN/user/USERNAME/lab/test-server which creates the following log:

13:12:15.551 [ConfigProxy] error: 503 GET /user/USERNAME/static/lab/9265.bc2b66a4502cdfcfc14f.js socket hang up

jupyter-server-proxy is designed to run and proxy web services. If you want a very simple example try this:

import sys
c.ServerProxy.servers = {
    "python-http": {
        "command": [sys.executable, '-mhttp.server', '{port}'],
    },

and go to /user/<username>/python-http/

See Starting & Proxying processes — Jupyter Server Proxy documentation for more information

1 Like

Hi manics,

Ive read the documentation and also tried your solution but still got no launcher item (nor a URL reachable server) cant seem to find anything relevant in the logs.

Could you please post your config and logs of JupyterHub and JupyterLab? There was a typo in my earlier comment, the server will be availble at /user/<username>/test-server/ as @manics posted. In your response you have /user/<username>/lab/test-server/. There should not be /lab in the URL path and trailing slash is important

1 Like

Sure!

here’s my config

import os
import pwd
import subprocess
from oauthenticator.generic import GenericOAuthenticator

class CustomAuthenticator(GenericOAuthenticator):
    async def pre_spawn_start(self, user, spawner):
        username = user.name
        try:
            pwd.getpwnam(username)  # Check if user exists
        except KeyError:
            # Create user if it doesn't exist
            subprocess.check_call(['useradd', '-m', username])

#
# AD Config
#

c.JupyterHub.authenticator_class = CustomAuthenticator

# OAuth2 application info
# -----------------------
c.GenericOAuthenticator.client_id = os.getenv('AD_CLIENT_ID')
c.GenericOAuthenticator.client_secret = os.getenv('AD_CLIENT_SECRET')

# Identity provider info
# ----------------------
# Docs: https://servicedesk.surf.nl/wiki/display/IAM/Connect+an+application+using+OpenID+Connect
c.GenericOAuthenticator.authorize_url = "https://proxy.sram.surf.nl/saml2sp/OIDC/authorization"
c.GenericOAuthenticator.token_url = "https://proxy.sram.surf.nl/OIDC/token"
c.GenericOAuthenticator.userdata_url = "https://proxy.sram.surf.nl/OIDC/userinfo"

# SRAM docs: https://servicedesk.surf.nl/wiki/display/IAM/Attributes+in+SRAM 
c.GenericOAuthenticator.scope = ["openid", "email", "eduperson_entitlement"]
c.GenericOAuthenticator.username_claim = "email"
c.GenericOAuthenticator.auth_state_groups_key = "oauth_user.eduperson_entitlement"
c.GenericOAuthenticator.manage_groups = True
c.GenericOAuthenticator.oauth_callback_url = os.getenv('OAUTH_CALLBACK_URL')

# Authorization
c.GenericOAuthenticator.admin_groups = {os.getenv('SURF_ADMIN_GROUP')}
c.GenericOAuthenticator.allowed_groups = {os.getenv('SURF_USER_GROUP')}

#
# Test Config
#

c.ServerProxy.servers = {
    "test-server": {
        "command": ["echo", "Hello_World"]
    }
}

c.ServerProxy.log_level = 'DEBUG'

Relevant logs: (when i go to the URL of /user/<username>/test-server/)

jupyterhub_jupyterhub  | [I 2024-10-23 10:51:58.056 ServerApp] 302 GET /user/<username>/test-server/ -> /user/<username>/test-server (@<IP>) 2.86ms
jupyterhub_jupyterhub  | [W 2024-10-23 10:51:58.168 ServerApp] 404 GET /user/<username>/test-server (<username>@<IP>) 26.33ms

Is the extensions installed and enabled? Config is one requirement, but there is a jupyterlab extension and jupyter server extension that also need to be enabled to make it all work. They are often setup automatically after installing jupyter-server-proxy, but maybe something went wrong?

From mobile now, i suggest listing jupyter server extensions, and jupyterlab extensions, and checking you see something there enabled related to jupyter-server-proxy

1 Like

To add to what @consideRatio already gave some pointers on debugging, your are putting c.ServerProxy.servers config in wrong place. The config content you posted is for JupyterHub. Assuming that config is placed in a file called jupyterhub_config.py, you give to JupyterHub as CLI arg as jupyterhub -f jupyterhub_config.py.

Now the single user JupyterLab servers will not read and should not read any config from this file by default. This must go into a file say /etc/jupyter/jupyter_server_config.py on the host where your single user server is running. Then the single user JupyterLab server can pick up this config and register the custom server endpoints.

You can place all JupyterLab related config in any config folders returned by jupyter --paths command on the single user server. For example, JupyterHub deployed on k8s return following:

$ jupyter --paths
config:
    /home/jovyan/.jupyter
    /home/jovyan/.local/etc/jupyter
    /usr/local/etc/jupyter
    /etc/jupyter
data:
    /home/jovyan/.local/share/jupyter
    /usr/local/share/jupyter
    /usr/share/jupyter
runtime:
    /home/jovyan/.local/share/jupyter/runtime
2 Likes

I think so, i had some luck using a different prebuilt proxy (This one) but i cannot create my own…

As for more information, here’s my Dockerfile:

FROM jupyterhub/jupyterhub:latest

# Install sudo
RUN apt-get update && apt-get install -y sudo

# Install Jupyter packages
RUN pip install jupyterlab jupyter_core jupyter-server-proxy oauthenticator

#RUN jupyter server extension enable --sys-prefix jupyter_server_proxy
# ^ This line did not work 

# Start JupyterHub
CMD ["jupyterhub", "--config=/srv/jupyterhub/jupyterhub_config.py"]

I am using jupyterhub and i know that the config is being read by me being able to use my configured authentication login. Or am i interpreting your question wrong?

JupyterHub and Jupyter server/lab/notebook are separate components with their own separate configuration files, as mentioned in

The advantage of decoupling these components is JupyterHub is very flexible in what it can manage.

1 Like

What would the config splitting look like?

i now have created a new file /etc/jupyter/serverproxy_config.py (that i got from the config part of command jupyter --paths)

containing:

c = get_config()

c.ServerProxy.servers = {
    "test-server": {
        "command": ["echo", "Hello_World"]
    }
}

but this seems a bit counterintuitive…
(still not working ofc)

The file should be called jupyter_server_config.py:
https://jupyter-server.readthedocs.io/en/latest/users/configuration.html

This is because jupyter-server-proxy is a jupyter-server extension, not a standalone application.

Another reason your current configuration won’t work is because it’s not a web service - did you see my earlier post?

1 Like

@manics Thanks for the reply, the change of the filename fixed it for me!

i now have a created a new file: /etc/jupyter/jupyter_server_config.py with just the serverconfig:

c = get_config()

c.ServerProxy.servers = {
    "test-server": {
        "command": ['echo', 'Hello, World!']
    }
}

(not using a web service didn’t seem to matter)

which created a launcher item for me, when pressed:

log:

jupyterhub_jupyterhub  | Hello, World!

Related issues seem to have a docker installation in common, maybe it has something to do with the installation/initiation of the jupyter_server_proxy package within a container that goes wrong?

Thanks for the help everyone!

1 Like