JupyterHub DockerSpawner not preserving API token when attempting to spawn container with NB_USER

Hey folks,

I am running into an issue where I am trying to deploy an instance of JupyterHub using DockerSpawner (more specifically, SwarmSpawner) in which I want to launch notebook containers (the Jupyter Docker Stacks in particular) as the user who logs into the Hub, rather than the default jovyan user.


Instead of launching each notebook container as jovyan, I wish to spawn each container through JupyterHub as the particular user logging into to the system. Running the container without the hub, this is just:

docker run -it --rm --user root \
    -e NB_USER=user \
    -e CHOWN_HOME=yes \
    -w "/home/${NB_USER}"

Trying to port this logic over to JupyterHub/DockerSpawner, I’ve tried the following:

I created a custom authenticator that implements a pre_spawn_start function that will take the user who has logged in and update the spawner’s container spec to launch as said user:

async def pre_spawn_start(self, user, spawner):
            "user": "root",
            "workdir": f"/home/{user.name}",
            "env": {
                "NB_USER": user.name,
                "CHOWN_HOME": "yes",

I pass this authenticator in to the jupyterhub_config.py file:

c.JupyterHub.authenticator_class = CustomAuthenticator

What happens next is after launching JupyterHub and logging in, depending on the approach, one of two things will happen:

  1. The default command for the notebook image is start-notebook.sh, in which it will look for the JUPYTERHUB_API_TOKEN environment variable; if it exists, it will attempt to execute start-singleuser.sh to launch the notebook server. Otherwise it will launch a jupyter (lab) instance. When the container is started as jovyan (the default in the stack), this API token is passed without issue and start-singleuser.sh executes and communicates with the Hub with no issue. Changing the user to NB_USER and launching the notebook container, the API token does not seem to be passed as an environment variable to the container, which causes start-notebook.sh to launch a local instance of JupyterLab - this does not communicate back to the Hub and thus when the container spawns, I cannot continue further, getting a 404 error.

  2. If I change the default cmd to something like jupyterhub-singleuser instead, the notebook container will fail to spawn after 30 seconds. Inspecting the logs, it compains with the following error:

JUPYTERHUB_API_TOKEN env is required to run jupyterhub-singleuser. Did you launch the service manually?

The start.sh script in the docker stacks, upon creating the new user based on NB_USER, launches with the --preserve-env option, so I’m a bit stuck here as to how I could proceed. Has anybody tried this particular endeavor?

I suspect this might be overriding the environment:

Have you tried setting the environment using the spawner configuration instead?

I had initially tried setting it through c.DockerSpawner.environment, but it seems that takes effect too late to make a difference. I can confirm that what you proposed does the trick! I was under the assumption that the container_spec var was only for the docker run (or equivalent) command environment variables, but I guess that is the global set instead. Appreciate the help!

1 Like