> ## Documentation Index
> Fetch the complete documentation index at: https://anaconda.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Administrating your JupyterHub

export const Comments = ({children}) => {
  return <div class="my-4 px-5 py-4 overflow-hidden rounded-2xl flex gap-3 border border-zinc-500/20 bg-zinc-50/50 dark:border-zinc-500/30 dark:bg-zinc-500/10" data-callout-type="comments">
      <div class="w-4">
        <svg width="14" height="14" viewBox="0 0 640 640" fill="currentColor" xmlns="http://www.w3.org/2000/svg" class="w-5 h-5" aria-label="Comments">
            <path d="M320 112C434.9 112 528 205.1 528 320C528 434.9 434.9 528 320 528C205.1 528 112 434.9 112 320C112 205.1 205.1 112 320 112zM320 576C461.4 576 576 461.4 576 320C576 178.6 461.4 64 320 64C178.6 64 64 178.6 64 320C64 461.4 178.6 576 320 576zM280 400C266.7 400 256 410.7 256 424C256 437.3 266.7 448 280 448L360 448C373.3 448 384 437.3 384 424C384 410.7 373.3 400 360 400L352 400L352 312C352 298.7 341.3 288 328 288L280 288C266.7 288 256 298.7 256 312C256 325.3 266.7 336 280 336L304 336L304 400L280 400zM320 256C337.7 256 352 241.7 352 224C352 206.3 337.7 192 320 192C302.3 192 288 206.3 288 224C288 241.7 302.3 256 320 256z" />
        </svg>
      </div>
      <div class="text-sm prose min-w-0 w-full">
        {children}
      </div>
    </div>;
};

export const Danger = ({children}) => {
  return <div class="callout my-4 px-5 py-4 overflow-hidden rounded-2xl flex gap-3 border danger-admonition dark:danger-admonition" data-callout-type="danger">
      <div class="mt-0.5 w-4">
        <svg width="14" height="14" viewBox="0 0 14 14" fill="rgb(239, 68, 68)" xmlns="http://www.w3.org/2000/svg" class="w-4 h-4 text-sky-500" aria-label="Danger">
          <path fill-rule="evenodd" clip-rule="evenodd" d="M7 1.3C10.14 1.3 12.7 3.86 12.7 7C12.7 10.14 10.14 12.7 7 12.7C5.48908 12.6974 4.0408 12.096 2.97241 11.0276C1.90403 9.9592 1.30264 8.51092 1.3 7C1.3 3.86 3.86 1.3 7 1.3ZM7 0C3.14 0 0 3.14 0 7C0 10.86 3.14 14 7 14C10.86 14 14 10.86 14 7C14 3.14 10.86 0 7 0ZM8 3H6V8H8V3ZM8 9H6V11H8V9Z"></path>
        </svg>
      </div>
      <div class="text-sm prose min-w-0 w-full">
        {children}
      </div>
    </div>;
};

Administrators are responsible for configuring, securing, and maintaining JupyterHub to ensure reliable and performant operation.

## Resource management

The JupyterHub installer bundles a conda environment that includes SystemdSpawner to manage resource allocation, security, and process isolation for user notebooks by integrating with `systemd` and Linux `cgroups`.

SystemdSpawner provides:

* Memory and CPU limits per user
* Fair scheduling independent of process count
* Accurate resource accounting via cgroups
* Path restrictions for user write access
* Automatic log collection to journald with rotation
* Process isolation through systemd units

### Configuration file location

JupyterHub configuration is managed in:

```
/opt/jupyterhub/etc/jupyterhub/jupyterhub_config.py
```

### Basic resource configuration

Set default resource limits for all users:

```python theme={null}
c.JupyterHub.spawner_class = 'systemdspawner.SystemdSpawner'
c.SystemdSpawner.default_shell = '/bin/bash'
c.SystemdSpawner.mem_limit = '2G'
c.SystemdSpawner.cpu_limit = 1.0
c.SystemdSpawner.isolate_tmp = True
c.SystemdSpawner.isolate_devices = True
c.SystemdSpawner.disable_user_sudo = True
c.SystemdSpawner.unit_extra_properties = {'RuntimeDirectoryPreserve': 'no'}
```

### Advanced resource configuration

#### Working directory and paths

As an admin, you can control how users access different parts of the workspace. For example, you might make shared data `readonly` while allowing notebook outputs to be `writeable`. To configure workspace locations:

```python theme={null}
c.SystemdSpawner.user_workingdir = '/shared/users/{USERNAME}'
c.SystemdSpawner.readonly_paths = ['/opt/shared-data']
c.SystemdSpawner.readwrite_paths = ['/tmp', '/shared/notebook-outputs']
```

### Applying configuration changes

Before you restart the JupyterHub service, have all users save their work and log out. JupyterHub is configured through the `jupyterhub_config.py` file. Apply any configuration updates to that file, then restart the JupyterHub service:

```bash theme={null}
# Validate configuration
sudo /opt/jupyterhub/bin/jupyterhub --config=/opt/jupyterhub/etc/jupyterhub/jupyterhub_config.py --generate-config

# Restart JupyterHub
sudo systemctl restart jupyterhub

# Check status
sudo systemctl status jupyterhub
```

## Security management

### SSL/TLS certificate management

<Tabs>
  <Tab title="Third-party certificates">
    To replace certificates from external providers, copy the new certs to the correct location:

    ```bash theme={null}
    # Copy new certificates
    sudo cp your-cert.crt /opt/jupyterhub/certs/cert.pem
    sudo cp your-key.key /opt/jupyterhub/certs/cert.key

    # Restart services
    sudo systemctl restart nginx jupyterhub
    ```
  </Tab>

  <Tab title="Self-signed certificates">
    Generate new self-signed certificates using the `DIY-SSL-CA` package:

    <Danger>
      Do not use self-signed certificates in production environments!
    </Danger>

    ```sh theme={null}
    cd DIY-SSL-CA
    bash create_noprompt.sh \<HOSTNAME\>
    ```

    <Comments>
      Replace \<HOSTNAME> with your JupyterHub server hostname.
    </Comments>

    Once you have the new certificates, copy them to the `/opt/jupyterhub/certs` directory:

    ```bash theme={null}
    sudo cp DIY-SSL-CA/out/\<HOSTNAME\>/\<HOSTNAME\>-bundle.crt /opt/jupyterhub/certs/cert.pem
    sudo cp DIY-SSL-CA/out/\<HOSTNAME\>/\<HOSTNAME\>.key /opt/jupyterhub/certs/cert.key

    # Restart services
    sudo systemctl restart nginx
    ```

    <Comments>
      Replace \<HOSTNAME> with your JupyterHub server hostname.
    </Comments>
  </Tab>
</Tabs>

### Security hardening

Additional security configurations:

```python theme={null}
# Disable user sudo access in notebooks
c.SystemdSpawner.disable_user_sudo = True

# Isolate temporary directories
c.SystemdSpawner.isolate_tmp = True

# Isolate devices
c.SystemdSpawner.isolate_devices = True

# Set secure headers
c.JupyterHub.tornado_settings = {}
```

<Tip>
  Refer to the official [JupyterHub documentation](https://jupyterhub.readthedocs.io/en/stable/explanation/websecurity.html) for more information on using secure headers.
</Tip>

## Monitoring & troubleshooting

### Log management

<Tabs>
  <Tab title="JupyterHub logs">
    To view JupyterHub service logs:

    ```bash theme={null}
    # View recent logs
    sudo journalctl -u jupyterhub -f

    # View logs for specific time period
    sudo journalctl -u jupyterhub --since "2024-01-01" --until "2024-01-02"

    # View logs with specific priority
    sudo journalctl -u jupyterhub -p err
    ```
  </Tab>

  <Tab title="User session logs">
    To view individual user <Tooltip tip="A temporary connection that remembers who you are and what you're doing until you sign out, time out, or close it.">session</Tooltip> logs:

    ```bash theme={null}
    # List user sessions
    sudo systemctl list-units --type=service jupyter-*

    # View specific user logs
    sudo journalctl -u jupyter-username
    ```
  </Tab>
</Tabs>

### User Sessions Failing

Check user-specific logs:

```bash theme={null}
sudo journalctl -u jupyter-username --no-pager
```

## Need more help with JupyterHub?

* [JupyterHub Configuration Reference](https://jupyterhub.readthedocs.io/en/stable/reference/config-reference.html)
* [SystemdSpawner Documentation](https://github.com/jupyterhub/systemdspawner)
* [JupyterHub Security Guide](https://jupyterhub.readthedocs.io/en/stable/reference/websecurity.html)
