8
votes

I have MySQL running locally on my host machine and for reasons™ I can't run it inside of my Vagrant machine. I know that there's a way to address this issue with iptables by forwarding all traffic to 3306 on the guest to the host's IP address and port, but this complicates things a lot for me as I'll have to play around with iptables rules and probably get into TCP masquerading, which would be nice to avoid.

Is there a way in Vagrant (VirtualBox VM) to forward a host TCP port to the guest so that the guest can access 127.0.0.1:3306 and have all traffic forwarded to host:3306 seamlessly? If not, how exactly would I set this up in iptables?

According to this answer, Docker provides a way to do this natively without having to screw around with IP tables rules. Does VirtualBox and Vagrant provide a way to mimic this functionality?

2

2 Answers

8
votes

I have two solutions, one involving iptables hacking and one more straightforward using SSH.

Tunnel a Host Port to the Guest over SSH

When connecting to the guest using vagrant ssh, pass the port along as an argument:

vagrant ssh -- -R 3306:localhost:3306

This will forward the local port 3306 to the remote machine at port 3306.

iptables Hackery

We can use iptables on the guest to forward all traffic to a local port on the guest to a remote port on the host. We need to ensure that the host and guest have more or less static IP addresses in relation to each other to ensure that everything works fine. We'll also need to open a port on the host's firewall to allow the guest to do this.

Give the Guest a Static IP

In your Vagrantfile, set a static IP address for the guest:

config.vm.network "private_network", ip: "10.10.10.10"

Now, when you hit 10.10.10.10, you'll always* be hitting your guest.

Configure iptables in the Guest

Found in this awesome answer in Server Fault:

$ remote_ip=10.0.2.2
$ mysql_port=3306
$ sudo iptables -t nat -A PREROUTING -i eth0 -p tcp --dport $mysql_port \
      -j DNAT --to $remote_ip:$mysql_port
$ sudo iptables -N INET-PRIV
$ sudo iptables -A FORWARD -i eth0 -o eth1 -j INET-PRIV
$ sudo iptables -A FORWARD -j drop
$ sudo iptables -A INET-PRIV -p tcp -d $remote_ip --dport $mysql_port \
      -j ACCEPT
$ sudo iptables -A INET-PRIV -j DROP

Then, enable port forwarding:

$ echo "1" | sudo tee /proc/sys/net/ipv4/ip_forward

First, test it out, then when you're sure it works, run:

$ sudo iptables-save

I'm not sure that /proc/sys/net/ipv4/ip_forward will remember settings on boot, so you might want to add that to a startup script.


Which Should I Use?

SSH is definitely easier to do, but there's a bit of a performance overhead of having to encrypt that port's traffic and forward it back to the host.

iptables feels like black magic, but once you get it working, it's really nice and fairly seamless.

1
votes

Port forwarding (using NAT back network backend) doesn't seem to fit the use case well.

In your use case, Public Network (Bridged Networking) is a better choice. Create a 2nd network in Vagrantfile and do a vagrant reload.

Vagrant.configure("2") do |config|
  config.vm.network "public_network"
end

Basically this will add an extra virtual NIC in the VM, and it'll get an IP from the same DHCP server in your network. Get its IP by using ifconfig -a or ip addr.

The host <=> VM will be able to communicate. VM should be able to connect to mysql running on the host via port 3306.

HTH