Best Way to Achieve Separate File Paths for Different Named Servers?

I am wanting to allow users to be able to to have multiple named servers, but for these named servers to not share files between them. For instance, I have multiple named servers currently, and when I spin up one or the other I see the same files within them.

To start, I have added the c.JupyterHub.allow_named_servers = True in my config file and dug a bit through the Spawner documentation.

I have the following in my config file:

class CustomSpawner(LocalProcessSpawner):
    def start(self):
        self.notebook_dir = f"/hub/{self.user.name}/jupyter_servers/{self.name}"
        os.makedirs(self.notebook_dir, mode=0o700, exist_ok=True)
        self.default_url = f"/tree/{self.notebook_dir}"
        return super().start()

c.JupyterHub.spawner_class = CustomSpawner

but this just times out when I go to create the named server.

I am checking my logs and something that appears is No module names 'jupyter_server' so my best guess is somehow I am not setting the environment right?

I a bit green when it comes to this forum and configuring JupyterHub, so please guide me in any direction if I have missed something obvious.

Thank you!.

Before we get to the more detailed question of separate paths, let’s resolve being able to start a server at all.

I am checking my logs and something that appears is No module names 'jupyter_server' so my best guess is somehow I am not setting the environment right?

How is jupyterhub and the single-user server installed? Is it possible that jupyterlab or another UI is not yet installed? You may want to pip install jupyterlab or similar in the environment.

In terms of setting the notebook directory, your approach should generally work, but the URL you give to /tree/ is relative to the notebook directory. So:

self.notebook_dir = f"/hub/{self.user.name}/jupyter_servers/{self.name}"
# self.default_url = f"/tree/"

starts the user in /hub/{self.user.name}/jupyter_servers/{self.name}

whereas moving the last component to default_url grants the server access to more, while keeping the default starting directory the same:

self.notebook_dir = f"/hub/{self.user.name}/jupyter_servers/"
self.default_url = f"/tree/{self.name}"

starts the user by default in the named server folder, but still with access to the files of all their servers.

From what I understand, it’s unlikely that you want to set default_url and notebook_dir. Removing the default_url line may result in the behavior you want, after you resolve installation issues.

1 Like

Thank you for the reply!

I got the behavior I wanted through setting a pre spawn hook for the Spawner in my config file:

def custom_notebook_dir(spawner):
    username = spawner.user.name
    servername = spawner.name

    base_dir = f"/home/jupyter-{username}"

    if servername:  
        custom_dir = os.path.join(base_dir, servername)
        os.makedirs(custom_dir, exist_ok=True)  # Ensure it exists
        user_info = pwd.getpwnam(f"jupyter-{username}")
        uid, gid = user_info.pw_uid, user_info.pw_gid
        shutil.chown(custom_dir, user=uid, group = gid)
        os.chmod(custom_dir, 0o700)
        spawner.notebook_dir = custom_dir  # Set the notebook directory
    else:
        spawner.notebook_dir = base_dir  # Default server uses base dir

c.Spawner.pre_spawn_hook = custom_notebook_dir

To answer you question about the installation, I am using TLJH on an AWS EC2 instance.