I ran into the need to access the internet from a VirtualBox VM via host-only networking. Of course, you’re saying “There’s a better way to do that!” And of course, I agree: with no other considerations, the best way to do this is to simply add another NIC to the VM configured as NAT instead of host-only. However, I’m trying to test out some new networking ideas for my OpenStack Network node, and it doesn’t have a NIC configured with NAT. Since I’m trying to reproduce a production system in VirtualBox for testing purposes (which is how I typically use it), it stands to reason that I want the VM setup as close to the real thing as possible.

This is actually pretty easy, especially after reading Ubuntu’s Connection Sharing wiki page. First, consider my development setup:

  • Development laptop NICs:
    • wlan0: Wifi internet connection
    • vboxnet0: VirtualBox’s host-only interface (creating these is well-documented). I disabled DHCP to reproduce production setup.
      • IP is 192.168.56.1
  • VirtualBox VM NIC:
    • eth0: Host-only interface connecting to laptop’s vboxnet0.
      • static IP: 192.168.56.100/24
      • gateway: 192.168.56.1 (i.e. development laptop)

Normally, in this setup, the VM would attempt to use the development laptop as a NAT gateway for external access, but since our laptop isn’t setup that way, the VM can’t see the internet nor is it accessible from the internet. I didn’t care about the latter– I just needed internet access from the VM. That’s as simple as setting up IP forwarding on the development laptop and enabling a few firewall (iptables) rules to setup the NAT.

Let’s start with some iptables rules. Note that these will be flushed upon reboot. That’s not important to me, but if you want these settings to persist it’s not difficult, and is well-documented elsewhere (start with Ubuntu’s wiki, linked above).

Let’s first add a rule to forward new connections from the host-only network:

$ sudo iptables -A FORWARD -o wlan0 -i vboxnet0 -s 192.168.56.0/24 -m conntrack --ctstate NEW -j ACCEPT

Now add a rule to forward already-established and related connections:

$ sudo iptables -A FORWARD -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT

Now flush the NAT table and add a new rule to it to masquerade any packets flowing out of wlan0 to look as if they’re coming from the laptop (i.e. “do NATing”):

$ sudo iptables -t nat -F POSTROUTING
$ sudo iptables -t nat -A POSTROUTING -o wlan0 -j MASQUERADE

At this point, the firewall is all setup to take care of NATing traffic from vboxnet0 to wlan0, but we still need to allow packet forwarding to occur at the kernel level. Again, the way we’re doing it here is temporary (will be gone at reboot):

$ sudo sh -c "echo 1 > /proc/sys/net/ipv4/ip_forward"

Finally, you should be able to access resources on the internet from the VM:

$ ping 8.8.8.8
PING 8.8.8.8 (8.8.8.8) 56(84) bytes of data.
64 bytes from 8.8.8.8: icmp_seq=1 ttl=56 time=14.4 ms
64 bytes from 8.8.8.8: icmp_seq=2 ttl=56 time=14.6 ms
64 bytes from 8.8.8.8: icmp_seq=3 ttl=56 time=15.3 ms
^C

Note, however, that domain names won’t work, since we didn’t set that up. You know you can access 8.8.8.8 (Google’s nameserver), so you may as well use that. Then you’re good to go!