Important
You should not run JupyterHub without SSL encryption on a public network.
Security is the most important aspect of configuring Jupyter. Three configuration settings are the main aspects of security configuration:
SSL encryption (to enable HTTPS)
Cookie secret (a key for encrypting browser cookies)
Proxy authentication token (used for the Hub and other services to authenticate to the Proxy)
The Hub hashes all secrets (e.g., auth tokens) before storing them in its database. A loss of control over read-access to the database should have minimal impact on your deployment; if your database has been compromised, it is still a good idea to revoke existing tokens.
Since JupyterHub includes authentication and allows arbitrary code execution, you should not run it without SSL (HTTPS).
This will require you to obtain an official, trusted SSL certificate or create a self-signed certificate. Once you have obtained and installed a key and certificate you need to specify their locations in the jupyterhub_config.py configuration file as follows:
jupyterhub_config.py
c.JupyterHub.ssl_key = '/path/to/my.key' c.JupyterHub.ssl_cert = '/path/to/my.cert'
Some cert files also contain the key, in which case only the cert is needed. It is important that these files be put in a secure location on your server, where they are not readable by regular users.
If you are using a chain certificate, see also chained certificate for SSL in the JupyterHub Troubleshooting FAQ.
It is also possible to use letsencrypt to obtain a free, trusted SSL certificate. If you run letsencrypt using the default options, the needed configuration is (replace mydomain.tld by your fully qualified domain name):
mydomain.tld
c.JupyterHub.ssl_key = '/etc/letsencrypt/live/{mydomain.tld}/privkey.pem' c.JupyterHub.ssl_cert = '/etc/letsencrypt/live/{mydomain.tld}/fullchain.pem'
If the fully qualified domain name (FQDN) is example.com, the following would be the needed configuration:
example.com
c.JupyterHub.ssl_key = '/etc/letsencrypt/live/example.com/privkey.pem' c.JupyterHub.ssl_cert = '/etc/letsencrypt/live/example.com/fullchain.pem'
In certain cases, for example if the hub is running behind a reverse proxy, and SSL termination is being provided by NGINX, it is reasonable to run the hub without SSL.
To achieve this, simply omit the configuration settings c.JupyterHub.ssl_key and c.JupyterHub.ssl_cert (setting them to None does not have the same effect, and is an error).
c.JupyterHub.ssl_key
c.JupyterHub.ssl_cert
None
The cookie secret is an encryption key, used to encrypt the browser cookies which are used for authentication. Three common methods are described for generating and configuring the cookie secret.
The cookie secret should be 32 random bytes, encoded as hex, and is typically stored in a jupyterhub_cookie_secret file. An example command to generate the jupyterhub_cookie_secret file is:
jupyterhub_cookie_secret
openssl rand -hex 32 > /srv/jupyterhub/jupyterhub_cookie_secret
In most deployments of JupyterHub, you should point this to a secure location on the file system, such as /srv/jupyterhub/jupyterhub_cookie_secret.
/srv/jupyterhub/jupyterhub_cookie_secret
The location of the jupyterhub_cookie_secret file can be specified in the jupyterhub_config.py file as follows:
c.JupyterHub.cookie_secret_file = '/srv/jupyterhub/jupyterhub_cookie_secret'
If the cookie secret file doesn’t exist when the Hub starts, a new cookie secret is generated and stored in the file. The file must not be readable by group or other or the server won’t start. The recommended permissions for the cookie secret file are 600 (owner-only rw).
group
other
600
If you would like to avoid the need for files, the value can be loaded in the Hub process from the JPY_COOKIE_SECRET environment variable, which is a hex-encoded string. You can set it this way:
JPY_COOKIE_SECRET
export JPY_COOKIE_SECRET=$(openssl rand -hex 32)
For security reasons, this environment variable should only be visible to the Hub. If you set it dynamically as above, all users will be logged out each time the Hub starts.
You can also set the cookie secret in the configuration file itself, jupyterhub_config.py, as a binary string:
c.JupyterHub.cookie_secret = bytes.fromhex('64 CHAR HEX STRING')
If the cookie secret value changes for the Hub, all single-user notebook servers must also be restarted.
The Hub authenticates its requests to the Proxy using a secret token that the Hub and Proxy agree upon. The value of this string should be a random string (for example, generated by openssl rand -hex 32).
openssl rand -hex 32
Or you can set the value in the configuration file, jupyterhub_config.py:
c.JupyterHub.proxy_auth_token = '0bc02bede919e99a26de1e2a7a5aadfaf6228de836ec39a05a6c6942831d8fe5'
You can pass this value of the proxy authentication token to the Hub and Proxy using the CONFIGPROXY_AUTH_TOKEN environment variable:
CONFIGPROXY_AUTH_TOKEN
export CONFIGPROXY_AUTH_TOKEN=$(openssl rand -hex 32)
This environment variable needs to be visible to the Hub and Proxy.
If you don’t set the Proxy authentication token, the Hub will generate a random key itself, which means that any time you restart the Hub you must also restart the Proxy. If the proxy is a subprocess of the Hub, this should happen automatically (this is the default configuration).