‘Why you should never ever use NixOS’: a rebuttal
I first heard of NixOS around two years ago, when a friend decided to run it on her personal VPS instances. As with most new things, I immediately hated it. ...
I got a KVM VPS from SSDNodes last week. I wanted to host a transmission seedbox, tapchat IRC bouncer and Jupyter notebook on it. I've done all of these before, but it takes too long to look up guides for each of these every time I need to do this. I'm documenting the process of setting up jupyter and NGINX here for future reference. The VPS is running Ubuntu 16.04, but the procedure shouldn't bee too different for other distros
First, install docker by following the official documentation here:
Installing Docker using the repository
# 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
Next, install NGINX
apt install nginx
Verify that NGINX works by opening your server domain name in your browser
Use the LetsEncrypt certbot tool to generate an SSL certificate and configure NGINX to use it
Securing NGINX with LE on Ubuntu 16.04 - DigitalOcean tutorial
First, make sure the domains you want to use are configured to point to the IP address of your server. With the default NGINX configuration, all of these domains should show the default NGINX page when opened on your prowser.
Next, install certbot
# 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
Next, edit the default NGINX config and add your domains
sudo nano /etc/nginx/sites-available/default
Find the existing server_name line and replace the underscore, _, with your domain name:
server_name domain.tld subdomain1.domain.tld subdomain2.domain.tld;
now reload the NGINX configuration.
sudo systemctl reload nginx
Certbot makes it easy to set up SSL for existing NGINX configurations
sudo certbot --nginx -d domain.tld -d subdomain1.domain.tld -d subdomain2.domain.tld
I chose to redirect HTTP requests to HTTPS when certbot prompted, but this isn't necessary. Once the certificates are obtained, open each domain in your browser to verify that the certificate was successfully installed.
There is no need to add a crontab entry to renew certificates. The certbot package automatically adds a systemd timer to renew the certificates. Verify that the renewal process works by doing a dry run.
sudo certbot renew --dry-run
Check if the auto renew script is running by listing systemd timers.
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.
Edit the NGINX config to forward ipython.domain.tld (or any other subdomain) to 127.0.0.1:8888. To do this, first I removed ipython.domain.tld from the default server config, and created a separate server block for it. This is what the original server block after setting up SSL looked like:
# 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
}
This is the block I added below after removing ipython.domain.tld from the original server config:
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.
Once these changes are made, restart NGINX
sudo systemctl reload nginx
Now start a CPU only tensorflow docker instance. I'm using this tensorflow container because it comes preinstalled with many of the packages I need.
docker run --name jupyter -it -p 8888:8888 gcr.io/tensorflow/tensorflow
Note down the token and enter it at https://ipython.domain.tld to access the Jupyter workspace
open a terminal from jupyter and set a password.
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.
TapChat is the only free IRC bouncer with an android app and working push notifications I could find. I currently have a paid IRCcloud subscription, but I would like to have a free self-hosted alternative for when my subscription expires. The trouble with tapchat is that it generates its own self-signed SSL certs. It took me a while to figure out how I can get it to work with NGINX.
Create a named volume to persist data.
docker volume create --name tapchat-data
Pull the latest tapchat docker image.
docker pull csmith/tapchat:latest
Start tapchat.
docker run -d --name tapchat --restart always -p 8067:8067 -v tapchat-data:/.tapchat csmith/tapchat:latest
The CA used by tapchat is needed by NGINX. To do this, simply by attach to the container, cat the .pem file and paste that to a file outside the container.
docker exec -i -t tapchat /bin/bash
cd .tapchat
cat tapchat.pem
exit
Copy the contents of this file to /etc/ssl/certs/tapchat.pem
Finally, get the hash of the pem and add a symlink to it in /etc/ssl/certs/
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
Add the following server block to the existing config:
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
}
Now restart NGINX and open https://irc.domain.tld to access your tapchat server.
I first heard of NixOS around two years ago, when a friend decided to run it on her personal VPS instances. As with most new things, I immediately hated it. ...
I have a habit of writing excessively long bash one-liners well beyond the threshold of it making more sense to write a script. Chaining commands and transfo...
SHAKTI-MS: a RISC-V processor for memory safety in C
I have a strange list of requirements, and a limited amount of hardware to satisfy them with. I needed: a Windows desktop for windows only software and ga...
A couple of weeks after moving into my apartment, I got a 100Mbps connection from Dsouza cable network, some local ISP that I had never heard of before. At f...
For the lat couple of months, I’ve been spending my weekends setting up my home PC, network and other infrastructure. Over this series of blog posts, I will ...
Using NGINX as a reverse proxy for webapps I got a KVM VPS from SSDNodes last week. I wanted to host a transmission seedbox, tapchat IRC bouncer and Jupyter ...
Quickly setting up headless access on linux SBCs like the pine64 This is a quick guide to enabling headless VNC access on the pine64 using USB serial.
My Github Blag I’ll mostly be posting how-tos on things that took me a long time to figure out, in case I need to do them again