Jupyter Notebook behind nginx with LetsEncrypt for HTTPS?

I get no errors in neither /var/log/nginx/{access,error}.log nor the journalctl for jupyter and nginx. Putting it all in an HTTP block works, HTTPS the website never loads (I tried curl -Lvvv 'http://DOMAIN_NAME' and the redirect worked but then timeout)


Starting with latest nginx from apt official mirror http://nginx.org/packages/ubuntu, I manually configured LetsEncrypt and the dhparams and nginx-options like so:

$ python3 -m venv venv
$ venv/bin/python -m pip install certbot
$ sudo systemctl stop nginx
$ venv/bin/certbot certonly --standalone --agree-tos \
                            -d '[DOMAIN_NAME]' -m '[EMAIL]'
$ base_url='https://raw.githubusercontent.com/certbot/certbot/master/certbot'
$ curl --proto '=https' --tlsv1.2 -sSf \
  "$base_url"'/certbot/ssl-dhparams.pem' \
   -o '/etc/ssl/certs/ssl-dhparam.pem'
$ curl --proto '=https' --tlsv1.2 -sSf \
  "$base_url"'-nginx/certbot_nginx/_internal/tls_configs/options-ssl-nginx.conf' \
  -o '/etc/letsencrypt/options-ssl-nginx.conf'
$ # Add `nginx service conf` and `jupyter_notebook.service` from below
$ systemctl start nginx

/lib/systemd/system/jupyter_notebook.service

[Unit]
Description=Job that runs the jupyter_notebook daemon

[Service]
User=VIRTUALENV_USER
Group=VIRTUALENV_GROUP
Environment=VIRTUALENV=VIRTUALENV_BIN
 Environment=PYTHONPATH=VIRTUALENV_BIN
WorkingDirectory=/MY/NOTEBOOKS/DIR
ExecStart=VIRTUALENV_BIN/jupyter notebook --no-browser \
          --NotebookApp.port=8000 \
          --NotebookApp.notebook_dir=/MY/NOTEBOOKS/DIR \
          --NotebookApp.local_hostnames DOMAIN_NAME \
          --NotebookApp.allow_origin DOMAIN_NAME \
          --NotebookApp.password_required=True \
          --NotebookApp.password argon2:$argon2id$v=19$m=1024<omitted>

[Install]
WantedBy=multi-user.target

/etc/nginx/sites-enabled/DOMAIN_NAME.conf

Add include /etc/nginx/sites-enabled/*.conf; within the http block of nginx.conf then add this:

map $http_upgrade $connection_upgrade {
    default upgrade;
    ''      close;
}

server {
    listen 80;
    server_name DOMAIN_NAME;

    return 302 https://$host$request_uri;
}
server {
    listen 443 ssl;

    server_name DOMAIN_NAME;

    ssl_certificate /etc/letsencrypt/live/DOMAIN_NAME/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/DOMAIN_NAME/privkey.pem;

    ssl_dhparam /etc/ssl/certs/ssl-dhparam.pem;
    include /etc/letsencrypt/options-ssl-nginx.conf;

    location / {
        proxy_pass http://127.0.0.1:8000;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection $connection_upgrade;
        proxy_set_header X-Scheme $scheme;

        proxy_buffering off;
    }

    location ~ /.well-known {
        allow all;
    }
}

I’ve also tried adding these blocks within the server block:

    location ~ /api/kernels/ {
        proxy_pass http://localhost:8000;
        proxy_set_header Host $host;
        proxy_http_version 1.1;
        proxy_set_header Upgrade "websocket";
        proxy_set_header Connection "Upgrade";
        proxy_read_timeout 86400;
    }

    location ~ /terminals/ {
        proxy_pass http://localhost:8000;
        proxy_set_header Host $host;
        proxy_http_version 1.1;
        proxy_set_header Upgrade "websocket";
        proxy_set_header Connection "Upgrade";
        proxy_read_timeout 86400;
    }

PS: I’ve scripted this entire process but posting here so you can follow along without my automation process.

What am I doing wrong?

Have you tried serving a static page behind HTTPS? Do you see anything in your browser’s console? What do you see in your nginx logs when the request is made- you’ve said there are no errors, but do you see the requests?

Here is a Demo Jupiter Notebook I created with Dooqod.com Dooqod: Power up your remote team
Its really convenient to keep projects under Dooqod where you can also share them with other people by just sharing like you share your google docs.