Post

Remote Jupyterlab with Tailscale

This is another one for all you data scientists and ai lovers out there! Imagine! You have a wonderful GPU desktop and you have a long battery live laptop. Let’s put it together and utilize the power of the desktop remotely!

Yes, not only you can do that, but also in a secure way! We will fisrt go through how to setup jupyterlab fisrt and then tailscale which is a curcial module that enables use to use this over network safely!

Installation

If you already have JupyterLab installed, feel free to skip this section. Otherwise, I recommend using Nix to install micromamba, and then using micromamba to install JupyterLab.

However, starting from Ubuntu 22.04, micromamba can no longer be installed directly from nix-env due to gcc version. To work around this, we’ll use a Nix flake to install it instead.

1. Install Nix

You can install Nix easily using my ansible playbook.

1
2
# Installing nix
ansible-pull -U https://github.com/brucechanjianle/ansible --ask-become-pass --tags nix

2. Install micromamba with Nix Flake

Next, let’s install micromamba using a flake-based project:

1
2
3
4
5
6
git clone https://github.com/BruceChanJianLe/micromamba.git
cd micromamba
nix develop -c $SHELL
which micromamba
# This is important!!! An example output would be the below:
# /nix/store/qgmx5z2bd6i3q0vpz4qgipajf5wdwnf8-micromamba-1.5.8/bin/micromamba

3. Install JupyterLab

1
/nix/store/qgmx5z2bd6i3q0vpz4qgipajf5wdwnf8-micromamba-1.5.8/bin/micromamba create -n jupyterlab jupyterlab -c conda-forge

Setup Jupyterlab As Service

This setup is similar to my previous post on automagically start jupyterlab. If you’re already familiar with systemd user services, feel free to skip ahead.

1. Create Service Directory

User-level services live under your home directory and start when you log in (instead of at system boot). Let’s create the directory:

1
mkdir ~/.config/systemd/user/ -p

2. Add the Service File

Create a new service file for JupyterLab:

1
2
# You can use nano if vim is not something you are familiar with :)
vim ~/.config/systemd/user/jupyter_notebook.service 

Paste the following content, updating the micromamba path where necessary:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
[Unit]
Description=Jupyter Lab Server
After=network.target

[Service]
ExecStart=/nix/store/qgmx5z2bd6i3q0vpz4qgipajf5wdwnf8-micromamba-1.5.8/bin/micromamba run -n jupyterlab jupyter lab --port 7777 --no-browser
WorkingDirectory=%h
# Restart=on-failure
Environment=RORT=7777
StandardOutput=journal
StandardError=journal

[Install]
WantedBy=default.target

This runs JupyterLab from your home directory on port 7777. You can change the working directory or port if needed, for example, 8888 is the default for manual launches.

Enable HTTPS and Remote Access

By default, JupyterLab only accepts local connections. Let’s fix that securely.

1. Generate a Configuration File

1
/nix/store/qgmx5z2bd6i3q0vpz4qgipajf5wdwnf8-micromamba-1.5.8/bin/micromamba run -n jupyterlab jupyter lab --generate-config

Then open the generated configuration file:

1
2
# You may use nano if you're not familiar with vim :D
vi $HOME/.jupyter/jupyter_lab_config.py

Enable remote access:

1
c.ServerApp.allow_remote_access = True

2. Generate SSL Certificates

Let’s create a self-signed certificate (valid for 10 years):

1
openssl req -x509 -nodes -days 3650 -newkey rsa:2048 -keyout jupyterlab.key -out jupyterlab.pem

Then update the configuration file with your certificate paths:

1
2
c.ServerApp.certfile = '/path/to/jupyterlab.pem'
c.ServerApp.keyfile = '/path/to/jupyterlab.key'

Finally, set a fixed base URL (important for reverse proxying):

1
c.ServerApp.base_url = 'jupyter'

Setting Up Tailscale

Now comes the fun part, securing and exposing JupyterLab through Tailscale, so you can access it from anywhere on your tailnet.

1. Install Tailscale

Sign up at tailscale.com and install the client:

1
curl -fsSL https://tailscale.com/install.sh | sh

Then authenticate your machine:

1
2
3
sudo tailscale up
# This will allow user to use tailscale without sudo
sudo tailscale set --operator=$USER

2. Test the Setup

You can now serve your local JupyterLab securely over your tailnet:

1
tailscale serve --https=7777 --set-path /jupyter https+insecure://localhost:7777/jupyter

This will print something like:

1
2
3
4
5
6
# Available within your tailnet:
# 
# https://dev.coat-grey.ts.net:7777/jupyter
# |-- proxy https+insecure://localhost:7777/jupyter
# 
# Press Ctrl+C to exit.

Here, https+insecure is used because we’re serving a self-signed HTTPS certificate. Now we should be able to access it jupyterlab through https://dev.coat-grey.ts.net:7777/jupyter.

Alternatively, we can always run this command with –bg for it to run in the background, but I personally feel like using a linux service to handle this is more deterministic.

Great! So now, let us add another linux service to ensure we have jupyterlab always accessible when it turns on.

3. Automating Tailscale Service

You can stop the previous command now, because instead of running the above command manually, let’s automate it with another user-level service.

1
2
# As always can you nano if you want :)))
vim ~/.config/systemd/user/tailscale_jupyter_notebook.service 

Paste the following:

1
2
3
4
5
6
7
8
9
10
[Unit]
Description=Tailscale for Jupyter Lab
After=network.target tailscaled.service jupyter_notebook.service
Requires=jupyter_notebook.service

[Service]
ExecStart=/usr/bin/tailscale serve --https=7777 --set-path /jupyter https+insecure://localhost:7777/jupyter

[Install]
WantedBy=default.target

Enabling the Services

Now that we are done defining both the services, we can finally activate them!

Reload and enable both services:

1
2
3
systemctl --user daemon-reload
systemctl --user enable jupyter_notebook.service
systemctl --user enable tailscale_jupyter_notebook.service

Start them for the first time:

1
2
systemctl --user start jupyter_notebook.service
systemctl --user start tailscale_jupyter_notebook.service

Well, you will only need to do this once, since it has been enabled to start this service after reboot.

Jupyterlab Password Protection

Well, if you’re sharing the desktop among your friends or colleague, perhaps you want one more layer of protection.

Generate a hashed password:

1
/nix/store/qgmx5z2bd6i3q0vpz4qgipajf5wdwnf8-micromamba-1.5.8/bin/micromamba run -n jupyterlab jupyter lab password

This writes a hash to $HOME/.jupyter/jupyter_server_config.json, for example:

1
2
3
4
5
{
  "IdentityProvider": {
    "hashed_password": "argon2:$argon2id$v=19$m=10240,t=10,p=8$Tfwj5iovyI97/2Tl3GIPAQ$hPfLb+WN6614k2NpRC2HoFYQ8dxp6kXSxdnQzORrsEs"
  }
}

Copy the hashed password and update your $HOME/.jupyter/jupyter_lab_config.json.

1
c.ServerApp.password = 'argon2:$argon2id$v=19$m=10240,t=10,p=8$Tfwj5iovyI97/2Tl3GIPAQ$hPfLb+WN6614k2NpRC2HoFYQ8dxp6kXSxdnQzORrsEs'

Restart JupyterLab:

1
systemctl --user restart jupyter_notebook.service

You should see the following prompt when you enter jupyterlab! But once you have key in you do not need to re-authenticate yourself, unless, you come in from a new browser.

image

Well Done

To validate whether the service has been run succesfully, you can run:

1
2
systemctl --user status jupyter_notebook.service
systemctl --user status tailscale_jupyter_notebook.service

If both show as active (running) then congratulations!

Well, give yourself a hand! You’ve made it so far, hopefully this is as helpful to you as it was for me. And with this you now have a secure, remote-access JupyterLab instance running on your powerful desktop, accessible from anywhere in the globe through Tailscale.

Until next time, keep learning and keep building!

This post is licensed under CC BY 4.0 by the author.

Trending Tags