Hosting 'The Littlest JupyterHub'
Back in 2024 I ran a pyrolite workshop as part of the SGTSG conference (The Geological Society of Australia's Specialist Group in Tectonics and Structural Geology Biennual Meeting), where I used a hosted Jupyterlab
instance to provide easy access to an environment with pyrolite installed for the attendees, in an attempt to maximise the use of time and minimise
technical issues.
Major Players make this Hard™
I had a bunch of headaches trying to set up a server in multiple of the major players (AWS, Azure, OVH). Azure even blocked my account for trying to do this, with no explanation as to why - not helpful a few days out from the workshop. The other major issue was that to access nodes with enough resources to handle 40-odd simultaneous users was nigh on impossible without having a previous record (and series of bills) with each of these providers.
I think in the end I went back to AWS and settled for something subpar which would at least have a few folks running on the night. But the experience wasn't particularly fun. Since I've wondered whether I can host such thing from a server/virtualized desktop I own, and save both the hassle and the bill. I think I've figured out one way which will work.
Setting up The Littlest JupyterHub (TLJH)
As you'll find in other posts here, I use Proxmox as a host for many of my self-hosted services (small and not-to-small). Within this, I principally use Linux Containers (LXC) as my container solution. Typically, installing into an LXC will be pretty similar to installing on a Virtual Private Server (if you're e.g. renting a cloud server, as I did for the workshop originally) and especially similar to installing on any Linux host.
Here I'm going to start with a Debian 13 image, which we can quickly update after starting:
apt update && apt upgrade -y
Note: I don't use
sudohere as I'm running asrootfor the majority of important tasks within the container, but on your device or in your container you might need it.
We'll loosely follow the official guide for getting set up on your own server,
which starts with installing some basic pre-requisites.
I've had issues running the bootstrap.py install script on Debian 13 and Python 3.13, so have simplified this down to a few commands below. Here this is updated to include python3-venv, which for Python 3.13 as of writing this requires it:
apt install python3 python3-dev python3-venv git curl -y
The bootstrap.py script as per the installation instructions, with defaults, essentially reduces to creating a venv, cloning a repo and running the installer:
python3 -m venv /opt/tljh/hub
/opt/tljh/hub/bin/pip install --upgrade git+https://github.com/jupyterhub/the-littlest-jupyterhub.git
/opt/tljh/hub/bin/python -m tljh.installer --admin admin
When this is finished, you can visit your local IP address (found with, for example, ip a)
and you should see the Jupyter login page. It'll probably warn you that this is being served over HTTP
rather than HTTPS - and that's something we can deal with later.
Note that by default, the Jupyterhub Service is running on ports 80 and 8443 (HTTP/HTTPS),
but if you visit the IP address locally you should be mapped to the right place.
You can login with the admin username we set above (here, admin), and choose a password to associate
with this account on first login.
Setting up Default Authentication
Here we're going to modify the default authentication method (which allows anyone to sign up, using a username and password of their choice at first login). We'll instead stop this method from being able to create new users, so essentially whitelisting usernames.
This allows whitelisted users to create a password at first login, but it won't automatically create
a user for any random person trying to access your server; this means you'll need to add
a username for anyone wanting to access it (or a set of usernames which people can take one of,
which is what I did for the workshop). This strikes a bit of a balance in terms of
security - while the presence of e.g. an admin user is fairly guessable, the absence
of others makes it harder to gain access. As more users are added, there's a bit of
a security hole before they set a password, and if they set a bad password but
it's manageable for e.g. workshops (the intended use case of exposing this, where you do).
We can modify the YAML configuration file at /opt/tljh/config/config.yaml
to have an authenticator set as follows, then reload:
authenticator:
type: firstuseauthenticator.FirstUseAuthenticator
create_users: falsetljh-config reloadAdding a Tailscale Funnel for JupyterHub
To make this locally hosted app available to external users, we'll use Tailscale (and more specifically, Tailscale funnel). This only requires a Tailscale account, which is free. You'll end up with a publicly-accessible URL for your JupyterHub, which if you want you could map to a subdomain in DNS configuration for a domain you own.
If you're using an LXC, you'll need to mount
/dev/net/tunto use Tailscale.
On Linux, you can install Tailscale with a basic install script:
curl -fsSL https://tailscale.com/install.sh | sh
To start a funnel providing access to JupyterHub on port 80, you can run:
tailscale funnel -bg http://localhost:80