These notes describe how to install and configure a secured Jupyter server directly onto Ubuntu 16.04.
Warning: this might be stupid. In 2017, it might be wiser just to grab a docker image, since some of these look extremely well-packaged. In my view, the advantage of docker is that someone else does the packaging, while docker itself provides cross-platform portability, rudimentary process supervision, and perhaps a simpler model than your OS's package manager. It is easy to know what is installed, how to uninstall it, and where its boundaries are. The disadvantage of docker is that you need to understand docker possibly in addition to understanding some Unix fundamentals.
$ sudo apt update
$ sudo apt install software-properties-common
$ sudo add-apt-repository ppa:certbot/certbot
$ sudo aptn update
$ sudo apt install certbot
First, make sure you have either port 80 or port 443 open.
Check your firewall and your EC2 security-group, and make sure no other service is already bound to the port and listening on it.
$ # if you have port 80 open
$ sudo certbot certonly --standalone --preferred-challenges http -d example.com -d www.example.com
$ # alternatively, if you have port 443 open
$ sudo certbot certonly --standalone --preferred-challenges tls-sni -d example.com -d www.example.com
This will deposit a symlinks to a certificate file fullchain.pem
and a private key privkey.pem
in the directory /etc/letsencrypt/live/example.com/fullchain.pem
.
(This simplifies these Lets Encrypt instructions.)
Install it:
$ pip install jupyter
Interactively enter your password.
$ jupyter notebook password # to set the notebook password interactively
If you do not set a password as above, the server will auto-generate a password token, which will show on the console. This is also fine.
$ jupyter notebook --generate-config # generates a config file with default configs
Now we modify the config file to serve openly. The file is at ~/.jupyter/jupyter_notebook_config.py
.
You need to take care to point the jupyter config file at the physical file on disk, not the symlink, for fullchain.pem
and privkey.pem
. (I'm not sure how to square this with Let's Encrypt's auto-renewal mechanism, so I'm just pointing out the numbered file here, which will presumably expire and be replaced with the next number eventually.)
c.NotebookApp.certfile = u'/etc/letsencrypt/archive/alexisml.topology-engineering.com/fullchain1.pem' # configure certs
c.NotebookApp.keyfile = u'/etc/letsencrypt/archive/alexisml.topology-engineering.com/privkey1.pem'
c.NotebookApp.ip = '*' # let clients find us by any name not just localhost
c.NotebookApp.open_browser = False # do not open the browser
c.NotebookApp.port = 8888 # listen on this port
(This simplifies these Jupyter instructions.)
Install runit (which has a slight learning curve but is the best:
$ sudo apt install runit
$ sudo mkdir /etc/sv/jupyter-daemon
$ sudo touch /etc/sv/jupyter-daemon/run
$ sudo chmod 0755 /etc/sv/jupyter-daemon/run
Create a run script /etc/sv/jupyter-daemon/run
, which just calls the wrapper script:
#!/bin/sh
exec 2>&1
cd /home/ubuntu
exec chpst -uubuntu jupyter notebook
Alternatively, instead of modifying the python config file, you can just create shell script run-jupyter.sh
which passes in all the parameters, and always invoke via that. The advantage of this is you already know how to read and manage a shell script.
#!/bin/sh
exec jupyter notebook \
--certfile=/etc/letsencrypt/archive/alexisml.topology-engineering.com/fullchain1.pem \
--keyfile=/etc/letsencrypt/archive/alexisml.topology-engineering.com/privkey1.pem \
--ip='*' \
--port=8888 \
--no-browser
Create a file /etc/systemd/system/jupyter.service
:
[Unit]
Description=Jupyter service
[Service]
ExecStart=/usr/local/bin/jupyter notebook
WorkingDirectory=/home/ubuntu
User=ubuntu
Group=ubuntu
[Install]
WantedBy=multi-user.target