Exposing a web-server (e.g. JuptyerHub) on a Multipass virtual machine
This will demonstrate how a web-server running within a Multipass virtual
machine (guest) can be made visible on the IP address of the Linux
host. This uses iptables
configured via ufw
rules. Note, that I
have no idea on how safe this setup is, use at your own peril!
Setup
I set this up on a Ubuntu 20.04 LTS host system, although other Linux distros should work too. Note that as I did this not on a fresh install of Ubuntu, I maybe missing some bits. But I think this is what you'd do for the basic setup:
$ sudo apt update $ sudo apt upgrade # install and setup ufw (if not installed already) $ sudo apt install ufw $ sudo ufw allow http $ sudo ufw allow https $ sudo ufw limit ssh # don't forget this, otherwise you'll lock yourself out $ yes | sudo ufw enable
Note that this setup uses the ufw
firewall which is a frontend for
iptables
. It simply sets the iptable
rules. If you use something
else, e.g. iptables
straight, you should still be able to follow this.
Multipass setup
Multipass is an easy way to spin up virtual machines (guests). It installs via snap
:
$ snap install multipass $ multipass launch -m2G -c2 -n "tljh" lts $ multipass shell tljh
This launches a Ubuntu LTS guest system (the lts
option) with 2GB of
memory and 2 CPUs with the name tljh
. The last command then opens a
shell within the guest.
Guest setup
Within the guest, install The Littlest JupyterHub (or any other web-server for that matter). I use my setup on https://github.com/mauro3/JupyterHubWithJulia for this:
## install TLJH via https://github.com/mauro3/JupyterHubWithJulia git clone https://github.com/mauro3/JupyterHubWithJulia.git ## get a config-file git clone https://gist.github.com/b2a548771163d27dfca005f2bcc7030b.git JupyterHubWithJulia-def-settings cd JupyterHubWithJulia cp ../JupyterHubWithJulia-def-settings/settings_tljh_julia.sh . chmod u+x settings_tljh_julia.sh # nano settings_tljh_julia.sh # update as needed (should be ok as is) sudo ./tljh_install.sh
After some time passed… this now launched a JupyterHub server on the guest (note that I disabled the Julia installation for this demo).
Now the networking setup on the host
The JupyterHub-server on the guest is now merrily serving the JupyterHub on the host-machine internal IP address which was assigned at guest creation. This IP-address can be checked with
$ multipass list
let's assume for the following that the IP is 1.2.3.4
.
Note: re-setting up the mutipass guest will change the assigned ip
address!
If you point a browser launched on your host system to 1.2.3.4
, it will
show the JupyterHub login page (you can login with admin
and a
password of your choosing).
But how can we forward this web-server, such that it can be accessed from external machines?
The setup described below follows this forum-post; other potentially useful links are 1 and 2.
Misc setup
First we need to allow IPv4 traffic forwarding on the host. Uncomment the line
net.ipv4.ip_forward=1
in /etc/sysctl.conf
.
To reload this file run
$ sudo sysctl -p
Check that cat /proc/sys/net/ipv4/ip_forward
returns 1.
Iptables setup
With iptables
the following will setup (on the host) the forwards
the traffic to ports 443 and 80 to the guest.
This assumes that your outgoing network connection is called eth1
,
but do find out by running ip addr
. Execute on the host:
$ sudo iptables -t nat -I PREROUTING 1 -i eth1 -p tcp --dport 443 -j DNAT --to-destination 1.2.3.4:443 $ sudo iptables -I FORWARD 1 -p tcp -d 1.2.3.4 --dport 443 -j ACCEPT $ sudo iptables -t nat -I PREROUTING 1 -i eth1 -p tcp --dport 80 -j DNAT --to-destination 1.2.3.4:80 $ sudo iptables -I FORWARD 1 -p tcp -d 1.2.3.4 --dport 80 -j ACCEPT
Note that this adds rules for both http
and https
.
You can test now whether this works by pointing a browser running on another computer at your host-computer (either at its IP or at its domain-name if it has one). You should see the Jupyterhub login (or whatever web-page the guest is serving).
Note, this change is not permanent. It can be made permanent via a
bunch of different methods; here I use ufw
.
UFW setup
For this you need to edit the file /etc/ufw/before.rules
(on the
host). You need to insert this at the top of the file:
############# # Forward HTTP traffic to multipass virtual-machine instance # https://discourse.ubuntu.com/t/multipass-port-forwarding-with-iptables/18741 # Note that the IP address will change when re-doing the multipass instance. *nat :PREROUTING ACCEPT [0:0] -I PREROUTING 1 -i eth1 -p tcp --dport 443 -j DNAT --to-destination 1.2.3.4:443 -I PREROUTING 1 -i eth1 -p tcp --dport 80 -j DNAT --to-destination 1.2.3.4:80 COMMIT ##############
Then at the top of the existing *filter
section add this:
############## # Also needed to forward HTTP traffic to multipass virtual-machine instance -I FORWARD 1 -p tcp -d 1.2.3.4 --dport 443 -j ACCEPT -I FORWARD 1 -p tcp -d 1.2.3.4 --dport 80 -j ACCEPT ###########
Reload ufw
with
$ sudo ufw reload
Done! Probably best to reboot the machine to check whether all is working as is intended: everything setup here should start running automatically after a reboot.