# update apt list
sudo apt-get update

# install essential packages
sudo apt-get install apt-transport-https ca-certificates curl software-properties-common

# add gpg keys for the docker repository
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -

# add the AMD64 docker repository
sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"

# update apt list
sudo apt-get update

# install docker
sudo apt-get install docker-ce

# verify that docker works
sudo docker run hello-world

apt install nginx

# Add certbot PPA
sudo add-apt-repository ppa:certbot/certbot

# Update package list
sudo apt-get update

# Install certbot
sudo apt-get install python-certbot-nginx

sudo nano /etc/nginx/sites-available/default

server_name domain.tld subdomain1.domain.tld subdomain2.domain.tld;

sudo systemctl reload nginx

sudo certbot --nginx -d domain.tld -d subdomain1.domain.tld -d subdomain2.domain.tld

sudo certbot renew --dry-run

root@kvm:~# systemctl list-timers
NEXT                         LEFT          LAST                         PASSED       UNIT                         ACTIVATES
Sun 2017-12-03 09:08:15 PST  1h 40min left Sun 2017-12-03 03:01:58 PST  4h 25min ago snapd.refresh.timer          snapd.refresh.service
Sun 2017-12-03 09:12:01 PST  1h 44min left Sun 2017-12-03 03:01:58 PST  4h 25min ago apt-daily.timer              apt-daily.service
Sun 2017-12-03 12:41:34 PST  5h 13min left n/a                          n/a          certbot.timer                certbot.service
Sun 2017-12-03 19:48:58 PST  12h left      Sat 2017-12-02 19:48:58 PST  11h ago      systemd-tmpfiles-clean.timer systemd-tmpfiles-clean.service

4 timers listed.
Pass --all to see loaded but inactive timers, too.
# Default server configuration
#
server {
	listen 80 default_server;
	listen [::]:80 default_server;

	# SSL configuration
	#
	# listen 443 ssl default_server;
	# listen [::]:443 ssl default_server;
	#
	# Note: You should disable gzip for SSL traffic.
	# See: https://bugs.debian.org/773332
	#
	# Read up on ssl_ciphers to ensure a secure configuration.
	# See: https://bugs.debian.org/765782
	#
	# Self signed certs generated by the ssl-cert package
	# Don't use them in a production server!
	#
	# include snippets/snakeoil.conf;

	root /var/www/html;

	# Add index.php to the list if you are using PHP
	index index.html index.htm index.nginx-debian.html;

	server_name ipython.domain.tld subdomain1.domain.tld subdomain2.domain.tld;

	location / {
		# First attempt to serve request as file, then
		# as directory, then fall back to displaying a 404.
		try_files $uri $uri/ =404;
	}

	# pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
	#
	#location ~ \.php$ {
	#	include snippets/fastcgi-php.conf;
	#
	#	# With php7.0-cgi alone:
	#	fastcgi_pass 127.0.0.1:9000;
	#	# With php7.0-fpm:
	#	fastcgi_pass unix:/run/php/php7.0-fpm.sock;
	#}

	# deny access to .htaccess files, if Apache's document root
	# concurs with nginx's one
	#
	#location ~ /\.ht {
	#	deny all;
	#}

	listen 443 ssl; # managed by Certbot
	ssl_certificate /etc/letsencrypt/live/ipython.domain.tld/fullchain.pem; # managed by Certbot
	ssl_certificate_key /etc/letsencrypt/live/ipython.domain.tld/privkey.pem; # managed by Certbot
	include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
	ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot




	if ($scheme != "https") {
		return 301 https://$host$request_uri;
	} # managed by Certbot


	# Redirect non-https traffic to https
	# if ($scheme != "https") {
	# 	return 301 https://$host$request_uri;
	# } # managed by Certbot

}
server {
	listen 80;
	listen [::]:80;
	server_name ipython.domain.tld;

	error_log /var/log/nginx/jupyter_error.log;
	access_log /var/log/nginx/jupyter_access.log;

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

	location ~* /(api/kernels/[^/]+/(channels|iopub|shell|stdin)|terminals/websocket)/? {
		proxy_pass http://127.0.0.1:8888;
		proxy_set_header Host $host;
		proxy_set_header X-Real-IP $remote_addr;
		proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
		# WebSocket support
		proxy_http_version 1.1;
		proxy_set_header Upgrade $http_upgrade;
		proxy_set_header Connection "upgrade";
	}

	listen 443 ssl; # managed by Certbot
	ssl_certificate /etc/letsencrypt/live/ipython.domain.tld/fullchain.pem; # managed by Certbot
	ssl_certificate_key /etc/letsencrypt/live/ipython.domain.tld/privkey.pem; # managed by Certbot
	include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
	ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot

	if ($scheme != "https") {
		return 301 https://$host$request_uri;
	} # managed by Certbot

}

The location / block forwards all incoming connections on the ipython.domain.tld domain to 127.0.0.1:8888 and adjusts the headers so that jupyter sees the packets as originating from the client instead of 127.0.0.1. The location ~* /(api/kernels/[^/]+/(channels|iopub|shell|stdin)|terminals/websocket)/? block ensures that the websockets created by jupyter to communicate with the client browser get forwarded to the container.

sudo systemctl reload nginx

docker run --name jupyter -it -p 8888:8888 gcr.io/tensorflow/tensorflow

jupyter notebook password

Kill the docker container by pressing CTRL-C. Launch it again in the background.

docker start jupyter

Open https://ipython.domain.tld and enter the password to access the workspace.

docker volume create --name tapchat-data

docker pull csmith/tapchat:latest

docker exec -i -t tapchat /bin/bash
cd .tapchat
cat tapchat.pem
exit
openssl x509 -noout -hash -in /etc/ssl/certs/tapchat.pem
# use the hash from the previous command in place of "deadbeef" below
ln -s /etc/ssl/certs/tapchat.pem /etc/ssl/certs/deadbeef.0
server {
	listen 80;
	listen [::]:80;

	server_name irc.domain.tld;

	error_log /var/log/nginx/tapchat_error.log;
	access_log /var/log/nginx/tapchat_access.log;

	location / {
		proxy_pass  https://127.0.0.1:8067;
		proxy_set_header Host $host;
		proxy_set_header X-Real-IP $remote_addr;
		proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
		
		# SSL upstream
		proxy_ssl_trusted_certificate /etc/ssl/certs/tapchat.pem;
		proxy_ssl_verify off;
		
		# WebSocket support
		proxy_http_version 1.1;
		proxy_set_header Upgrade $http_upgrade;
		proxy_set_header Connection "upgrade";
	}

	listen 443 ssl; # managed by Certbot
	ssl_certificate /etc/letsencrypt/live/irc.domain.tld/fullchain.pem; # managed by Certbot
	ssl_certificate_key /etc/letsencrypt/live/irc.domain.tld/privkey.pem; # managed by Certbot
	include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
	ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot

	if ($scheme != "https") {
		return 301 https://$host$request_uri;
	} # managed by Certbot

}