I'm trying to set up a secured Jupyter notebook on my Apache 2.4.7 server. If there's a better, easier, or more secure way to do it, that'd be great. I know AuthType Basic doesn't really add much, I was just playing with Apache, and am including it here for completeness. When I set up an unsecure notebook through HTTP it works, but obviously this is a bad idea.
The issue I'm having, specifically, is
But only when accessing it through my domain. Obviously it has to be secured, as I'm exposing python through it. Apache doesn't log an error for this, but the Jupyter notebook throws SSL Error on
some number('127.0.0.1',
some number): [SSL: WRONG_VERSION_NUMBER_NUMBER] wrong version number (_ssl.c:600)
I have Jupyter set up with SSL and can access it through the normal https://localhost:8888/tree
which confirms the same set up as https://www.[mydomain].com/ipython
in connection details and technical details in the security tab for the pages in both Chrome and Firefox
Jupyter seems to default to TLS 1.0, according to openssl s_client -connect localhost:8888
, selecting another protocol gets SSL: WRONG_VERSION_NUMBER
as expected. diff <(openssl s_client -connect www.[mydomain].com:443 </dev/null) <(openssl s_client -connect localhost:8888 </dev/null)
shows no real differences. A byte difference due to size of url, pretty sure, the session-ID, Master-Key, and the TLS session ticket are the differences.
My jupyter_notebook_config.py
(after cutting it down and sanitation of a sort?) looks like:
c = get_config()
c.NotebookApp.certfile = u'[/my/cert/here].pem'
c.NotebookApp.keyfile = u'[/my/cert/here].pem'
c.NotebookApp.open_browser = False
c.NotebookApp.password = u'sha1:[much:password:sha:such:wow]'
c.NotebookApp.port = 8888
c.NotebookApp.tornado_settings = {
'headers': {
'Content-Security-Policy': "frame-ancestors 'https://www.[mydomain].com' 'self' "
}
}
I set it up with the ipython instructions (which are the same as the jupyter one luckily) and a bug report that introduced the keyfile thing. I set up the cert with openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout [mycert.pem] -out [mycert.pem]
as suggested in the bug report, with the key and cert appended together for simplicity. I'll get a real one signed later. Since it works locally (with a browser complaint of localhost
not matching the CN www.[mydomain].com
which doesn't appear when accessing through the website), I'd imagine getting the Apache server setup correctly is the only thing I'm missing.
Pulling from a couple of related but unfortunately not completely duplicating stackoverflow and serverfault (c.NotebookApp.ip = '*'
/'localhost'
doesn't help) questions, I got to the settings:
SSLProxyEngine on
SSLProtocol TLSv1
SSLProxyVerify none
SSLProxyCheckPeerCN off
SSLProxyCheckPeerName off
ServerName www.[mydomain].com
SSLCertificateFile [/my/cert/here].pem
<Location /ipython>
ProxyPass https://localhost:8888/tree
ProxyPassReverse https://localhost:8888/tree
ProxyAddHeaders On
ProxyPreserveHost On
ProxyPassReverseCookieDomain localhost www.[mydomain].com
RequestHeader set Origin "https://localhost:8888"
AuthType Basic
AuthName "Warning: Who are you?"
AuthUserFile [/password/file/just/for/fun/].htpasswd
Require valid-user
Require ssl
</Location>
<Location /kernelspecs/>
ProxyPass ws://localhost:8888/kernelspecs/
ProxyPassReverse ws://localhost:8888/kernelspecs/
ProxyAddHeaders On
ProxyPreserveHost On
AuthType Basic
AuthName "Warning: Who are you?"
AuthUserFile [/password/file/just/for/fun/].htpasswd
Require valid-user
Require ssl
</Location>
<Location /static/>
ProxyPass ws://localhost:8888/static/
ProxyPassReverse ws://localhost:8888/static/
ProxyAddHeaders On
ProxyPreserveHost On
AuthType Basic
AuthName "Warning: Who are you?"
AuthUserFile [/password/file/just/for/fun/].htpasswd
Require valid-user
Require ssl
</Location>
<Location /ipython/api/kernels/>
ProxyPass ws://localhost:8888/ipython/api/kernels/
ProxyPassReverse ws://localhost:8888/ipython/api/kernels/
ProxyAddHeaders On
ProxyPreserveHost On
AuthType Basic
AuthName "Warning: Who are you?"
AuthUserFile [/password/file/just/for/fun/].htpasswd
Require valid-user
Require ssl
</Location>
<Location /login>
ProxyPass ws://localhost:8888/login
ProxyPassReverse ws://localhost:8888/login
ProxyAddHeaders On
ProxyPreserveHost On
AuthType Basic
AuthName "Warning: Who are you?"
AuthUserFile [/password/file/just/for/fun/].htpasswd
Require valid-user
Require ssl
</Location>
For now, the Jupyter notebook is run in a terminal so I can see the output as I access it variously.