Tinkering with the OU TM351 VM, looking at putting together an Amazon AWS AMI version, I started to wonder about how I could add a simple authentication layer to mediate public web access so students don’t fire up an image on their dollar and then find other folk using it.
So… h/t to Adam McGreggor for pointing me to nginx. Using this and a smattering of other cribs, I soon got to this (simple_auth.sh
):
#!/usr/bin/env bash #Install nginx #apache2-utils contains htpassword command to configure password used to restrict access to target ports sudo apt-get update && sudo apt-get install -y nginx apache2-utils #Create a password (test) for user tm351 #Optionally set password via environment variable - TMP_PASS - from Vagrantfile #If TMP_PASS not set, use default password: test sudo htpasswd -b -c /etc/nginx/.htpasswd tm351 "${TMP_PASS-test}"
Now we need to create a config file for nginx. Define each service separately, on the top level path (/) for each service (which is referenced relative to its own port).
config=""" #Jupyter notebook running on port 8888 inside the VM upstream notebooks { server 127.0.0.1:8888; } #OpenRefine running on port 3333 inside the VM upstream refine { server 127.0.0.1:3333; } #Create a simple (unauthenticated) server on port 80 #The served files should be placed in /var/www/html/* server { listen 80; location / { root /var/www/html ; index index.html; } } server { #Configure the server to listen on internal port 35180 as an authenticated proxy for internal 8888 listen 35180; auth_basic "Protected..."; auth_basic_user_file /etc/nginx/.htpasswd; location / { proxy_pass http://notebooks; proxy_redirect off; } } server { #Configure the server to listen on internal port 35181 as an authenticated proxy for internal 8888 listen 35181; auth_basic "Protected..."; auth_basic_user_file /etc/nginx/.htpasswd; location / { proxy_pass http://refine; proxy_redirect off; } } """ sudo echo "$config" > /etc/nginx/sites-available/default #if that doesn't work, eg wrt permissions, try a workaround: #sudo echo "$config" > default #sudo mv default /etc/nginx/sites-available/default #sudo chmod 0644 /etc/nginx/sites-available/default #sudo chown root /etc/nginx/sites-available/default #sudo chown :root /etc/nginx/sites-available/default #Restart nginx with the new configuration sudo service nginx reload
The password (set on the command line vagrant is called from using export TMP_PASS="NEW PASSWORD"
) can be passed in from the Vagrantfile for use by simple_auth.sh
as follows:
config.vm.provision :shell, :env => {"TMP_PASS" => ENV["TMP_PASS"]}, :inline => <<-SH source /vagrant/build/simple_auth.sh SH
Setting up port forwarding in my Vagrantfile then looks like this:
config.vm.provider :virtualbox do |virtualbox| #---- BEGIN PORT FORWARDING ---- #jupyter authenticated - expose internal port 35180 on localhost:35180 config.vm.network :forwarded_port, guest: 35180, host: 35180, auto_correct: true #refine authenticated - expose internal port 35181 on localhost:35181 config.vm.network :forwarded_port, guest: 35181, host: 35181, auto_correct: true #---- END PORT FORWARDING ---- end
Running the vagrant provisioner, I now have simple authenticated access to the notebook and OpenRefine servers:
Could be a handy quick recipe, that…
PS Only of course it doesn’t quite work like that – because the I’d originally defined the services to be listening over all network ranges on 0.0.0.0… instead they need to listen on 127.0.0.1…