If you’re using
Vagrant you’ve probably noticed that you can’t bind ports 80/443 on your Mac due to security limitations.
Forwarding host ports < 1024 impossible:https://www.virtualbox.org/manual/ch06.html#nat-limitations
On Unix-based hosts (e.g. Linux, Solaris, Mac OS X) it is not possible to bind to ports below 1024 from applications that are not run by root. As a result, if you try to configure such a port forwarding, the VM will refuse to start. ipfw deprecated as of mavericks
So what’s the solution?
Well, there’s a few.
The VirtualBox manual is correct that
ipfw has been deprecated as of Mac OS X Mavericks, however, the method using
ipfw still happens to work.
Another alternative is to use the preferred solution which happens to be using Apple’s
pfctl software, and that’s what we’ll be covering in this article.
Why You Shouldn’t Automatically Bind The Port Forwarding Rules On Startup
I don’t cover it in this article, but if you want to automatically bind your ports to forward when your system boots, you can. If you modify
/etc/pf.conf with your port forwarding rules (samples are listed below in this article), they ‘ll automatically bind when your system boots.
Before you go this route, I ask that you at least hear me out.
If you’re anything like me, you have more than a single virtual box sitting on your machine (I happen to have over a dozen). Each of those boxes has its own public HTTP port which is unique to the box in question. For the sake of understanding let’s say I have 3 vagrant boxes, the HTTP ports for them would be 8080, 8081, and 8082. All of those boxes want to forward port 80 on my host machine to their respective HTTP ports, as each box is replicating its own unique environment which happens to use port 80.
At any given time in a day, I’m spinning boxes up and down for the environments that I need to gain access to. Manually typing and/or copy-pasting the port forwarding commands is cumbersome and far from convenient. I’m assuming if you’re reading this article that you’re somewhat of an engineer and it makes me want to scream “WE’RE ENGINEERS!” We build, we conquer, we automate things. I swear there’s an engineers bible somewhere that says something along the lines of:
Thou shall not manually type and/or copy-paste something over and over again to accomplish one’s goal.
I can’t cite where it’s written; but it has to be 1 of the 10 commandments of engineering (if you’re reading this, you’re probably laughing and nodding your head in agreement because you know it’s the truth).
Along with the point I just mentioned, I happen to be on Cisco’s VPN around the clock. Whenever I hop on and off the VPN, it apparently wipes all of my port forwarding rules on Mavericks every time without fail. Thus solidifying my stance that the ability to simply bind the port forwarding rules on boot isn’t an ideal solution.
Installing Vagrant Triggers
Before we update our
Vagrantfile we’re going to install the vagrant-triggers plugin. This will allow us to execute commands on the host dependent upon the command that’s being directed to Vagrant. For instance, we may want to run a certain command on our host for
vagrant up and a different command on our host for
vagrant halt. This plugin provides us with this type of functionality.
To install vagrant-triggers, navigate from your terminal to the folder containing your
Vagrantfile and enter the following command:
vagrant plugin install vagrant-triggers
Configuring Your Vagrantfile
When the vagrant-triggers plugin has finished installing, open up your
Vagrantfile (in your editor of choice) and add the following lines within your configuration block:
config.trigger.after [:provision, :up, :reload] do system('echo " rdr pass on lo0 inet proto tcp from any to 127.0.0.1 port 80 -> 127.0.0.1 port 8080 rdr pass on lo0 inet proto tcp from any to 127.0.0.1 port 443 -> 127.0.0.1 port 8443 " | sudo pfctl -f - > /dev/null 2>&1; echo "==> Fowarding Ports: 80 -> 8080, 443 -> 8443"') end
Now whenever we run
vagrant provision, or
vagrant reload on our box, ports 80/443 will automatically forward to 8080/8443 after the box has finished booting/provisioning/reloading.
What about when we halt/destroy the box? How can we remove/reset our session based port forwarding rules?
To reset all of our session based rules when we halt/destroy a box add the following to your
Vagrantfile configuration block:
config.trigger.after [:halt, :destroy] do system("sudo pfctl -f /etc/pf.conf > /dev/null 2>&1; echo '==> Removing Port Forwarding'") end
The block above resets all of your session based
pfctl rules and reloads your
/etc/pf.conf file which is what your system loads when it starts up. Your systems rules will basically be reset to the state that it’s in when you first boot your machine.
What Did We Accomplish?
We’ve installed and applied the vagrant-triggers plugin to execute commands on our host machine specific to the commands being directed at Vagrant.
We’ve updated our
Vagrantfile to automatically forward ports 80/443 on our host machine to ports 8080/8443 on our virtual box whenever we run
vagrant provision or
vagrant reload. We’ve also updated our
Vagrantfile to reset all of our session based port forwarding rules whenever we run
vagrant halt or
If you interested in learning more about the
pfctl program and how it works you can read more about it here.