Skip to content

Serving over HTTPS on a domain

By default TLJH listens on plain HTTP at http://<your-ip>. For a real classroom you want a memorable URL like https://jupyter.yourschool.org.uk with a valid TLS certificate, so:

  • Browsers don’t show scary warnings when students log in.
  • OAuth providers can use a stable callback URL.
  • You can run a real heartbeat against /hub/health rather than -k against an IP.

TLJH ships with Traefik baked in as its reverse proxy, and tljh-config exposes the relevant TLS settings without you needing to touch Traefik directly.

There are two paths depending on where your certificate comes from. Pick one.

If your hub will be on the public internet on a domain you control, TLJH can do the whole certificate dance for you with Let’s Encrypt.

  1. Point a public DNS A record at your host’s public IP

    e.g. jupyter.yourschool.org.uk → 203.0.113.42. Wait for it to resolve before continuing.

  2. Open ports 80 and 443

    Both are required: 80 for the ACME HTTP-01 challenge, 443 for the actual hub.

  3. Tell TLJH to enable HTTPS

    Terminal window
    sudo tljh-config set https.enabled true
    sudo tljh-config set https.letsencrypt.email you@yourschool.org.uk
    sudo tljh-config add-item https.letsencrypt.domains jupyter.yourschool.org.uk
    sudo tljh-config reload proxy

    Traefik will request a certificate within ~30 seconds, store it under /opt/tljh/state/, and renew it automatically before expiry.

  4. Verify

    Terminal window
    curl -I https://jupyter.yourschool.org.uk/
    # expect: HTTP/2 302 (redirect to /hub/login)

If you’ve configured an OAuth provider, update its redirect URI to match the new HTTPS host. Microsoft Entra, Google and GitHub all let you swap callback URLs in-place; you don’t need to recreate the app:

Terminal window
sudo tljh-config set auth.<Provider>OAuthenticator.oauth_callback_url \
'https://jupyter.yourschool.org.uk/hub/oauth_callback'
sudo tljh-config reload hub

Replace <Provider> with AzureAd, Google, GitHub or Generic as appropriate.

If your TLJH is on a Windows host with WSL2, two extra things matter:

  1. Use mirrored networking mode

    In ~/.wslconfig on the Windows host (the file may not exist; create it):

    C:\Users\<you>\.wslconfig
    [wsl2]
    networkingMode=mirrored

    Then wsl --shutdown and reopen WSL. The Linux side now binds directly to your machine’s LAN IP, so jupyter.yourschool.org.uk (an A record pointing at that IP) just works — no portproxy, no NAT.

  2. Open the Windows firewall

    PowerShell as administrator:

    Terminal window
    New-NetFirewallRule -DisplayName "TLJH HTTPS" -Direction Inbound -Protocol TCP -LocalPort 443 -Action Allow -Profile Any
    New-NetFirewallRule -DisplayName "TLJH HTTP" -Direction Inbound -Protocol TCP -LocalPort 80 -Action Allow -Profile Any

From a separate device on the same network as the hub:

Terminal window
# Windows
curl.exe -I https://jupyter.yourschool.org.uk
Test-NetConnection jupyter.yourschool.org.uk -Port 443
Terminal window
# macOS / Linux
curl -I https://jupyter.yourschool.org.uk

You should see HTTP/2 302 redirecting to /hub/login. If you get a connection refused, check the host’s firewall first; if the cert is unrecognised, check whether the device has the school root CA installed.