Chapter 4. Networking in Vagrant

Part of the ideal Vagrant workflow is the firm belief that you should be able to continue using existing browsers and development tools on your local machine.

One example of this is shared folders, which you saw briefly when setting up your first Vagrant environment. Shared folders allow you to work on your own machine and have files synced into the guest machine, letting you continue to use your own editor.

Likewise, to use your own browser for web applications, we need a way to expose network applications such as web servers to the outside world from the virtual machine. To do this, Vagrant exposes a set of options for networking the virtual machine.

Vagrant offers three networking options to maximize flexibility: forwarded ports, host-only networking, and bridged networking.

Each networking option has its own specific use case and set of upsides and downsides. Understanding each of these is important to getting the most value possible from Vagrant.

For this chapter, we’ll continue building on the previous virtual machine configured to install Apache. If you haven’t done this yet, spend some time quickly setting up your Vagrantfile with the shell configuration to install Apache. If you’re using Chef or Puppet, that is fine, as long as it is provisioned following the examples in Chapter 3.

Using this virtual machine running Apache, we’ll review each option of networking in order to see how it works, and the benefits and costs associated with each.

Forwarded Ports

With forwarded ports, Vagrant will set up a port on the host to forward to a port on the guest, allowing you to access services on the guest without an IP.

We’ve been using forwarded ports already throughout this book, so the basics of this feature should not be new.

As an example, if you forwarded port 80 (the standard port for serving HTTP content) in the guest to port 8080 on your host, then you could access the web server in the guest by loading localhost:8080 on your main machine. The traffic sent to port 8080 is actually forwarded to port 80 on the guest machine.

Pros and Cons

The benefits of forwarded ports is that they’re very simple to set up. You just tell Vagrant in the Vagrantfile what ports to forward where.

The simplicity of forwarded ports comes at a cost. First, you need to be explicit about every port you want to forward. For basic web services, this is easy. But there are also databases, services that listen on multiple ports, and more that can be useful to access, and configuring all of this becomes tedious very quickly.

Forwarded ports are also accessible from outside your own computer. Assuming you don’t have a firewall in place, any computer on the local network can access your virtual machine if they know your IP and the port that it is listening on. For local development this is often not a big issue, but it is worth noting for those who are more sensitive to security and privacy.

And finally, with VirtualBox, Vagrant can’t forward to ports less than 1024 on the host system. This is due to operating systems not allowing this for processes without administrative privileges, such as Vagrant. The main use case this negatively affects is SSL, which is assumed to be on port 443 for web traffic. If you want to test SSL, port forwarding is not a good way to do it.

Basic Usage

We’ve been configuring forward ports throughout this book, so this shouldn’t be new. It is very simple:

config.vm.forwarded_port 80, 8080

The first argument is the port on the guest to make available via the host port, which is the second argument.

Multiple forwarded port definitions can be included in a Vagrantfile in order to forward multiple ports.

Just like any other configuration change in Vagrant, these changes won’t take effect on running machines until a vagrant reload is called.

Collision Detection and Correction

Vagrant has built-in support for detecting port collisions, the case where a forwarded port definition would collide with another used port on your system.

By default, Vagrant will report an error so you can fix the issue by either freeing up that used port, or by changing the port in the Vagrantfile.

Alternatively, Vagrant can auto-correct the collision by choosing another port to use for you. This must be explicitly enabled because it is otherwise confusing when bringing up a new guest machine that the forwarded port defined may have changed, even though Vagrant tells you about the detected collisions and auto-corrections.

To enable auto-correction, add an extra option to your existing forwarded port definitions, like so:

config.vm.forwarded_port 80, 8080, auto_correct: true

If a port collision detection is detected for that forwarded port, Vagrant will then auto-correct it to some other unused port. By default, Vagrant will choose an auto-correction port between port 2200 and port 2250.

This range can also be customized with a setting in the Vagrantfile:

config.vm.usable_port_range = (2200..2250)

TCP versus UDP

Forwarded ports by default only work with TCP connections. If you need to forward UDP packets as well, you have to configure an additional forwarded port with UDP port forwarding:

config.vm.forwarded_port 80, 8080, protocol: "udp"

This forwarded port will only forward UDP packets. If you want to allow both protocols, two forwarded port declarations must be used.

Host-Only Networking

Host-only networking creates a network that is private to your host and the guest machines on that host. Because this is a new, custom network, it has its own IP address space, so guest machines with host-only networking get their own IP.

Vagrant supports host-only networks by specifying a static IP for the machine. Vagrant will handle creating the host-only network and configuring the guest machine to get the specified IP.

The machine can then be accessed directly using this IP. This is a benefit over forwarded ports, since you can then access all the ports directly on the guest machine, rather than enumerating each one on an as-needed basis.

Pros and Cons

“Host-only” literally means that only the host machine and the guest machines can access this network. Machines outside of the host, such as other machines on the local network, cannot access the assigned static IP. This is both a pro and a con.

The pro of the isolation of host-only networks is that they’re secure. Outside computers have no way of accessing network services you may be running.

The con is that because it is isolated, coworkers and team members who may be working on the same project can’t look at your work. The most common use cases for this are testing web pages on mobile, showing a coworker a bug or feature, and so on. This can’t be done with host-only networks.

Another benefit of host-only networks is that multiple virtual machines can communicate with each other by being a part of the same network. With forwarded ports, a virtual machine can’t talk to another virtual machine. With host-only networking, as long as the machines are on the same network and know each other’s IP addresses, they can communicate! The primary use case for this is separating services onto multiple virtual machines to more accurately mimic production, such as web servers and database servers.

In addition to multiple virtual machines being able to communicate, the virtual machines can also communicate with the host itself. This can be useful for accessing services running on the host machine. Forwarded ports, on the other hand, can only be accessed from the host machine. The guest can’t talk to the host.

Networking multiple virtual machines together will be covered in detail in Chapter 5.

Basic Usage

Configuring a host-only network is done in the Vagrantfile as usual with a single line:

config.vm.network "hostonly", "192.168.33.10"

This is the first time seeing this configuration directive. The config.vm.network directive configures networking on the machine. By passing hostonly in as the first argument, a host-only network will be created. The second argument is the static IP to assign to the machine.

This static IP can be anything, although according to RFC specifications, a private, reserved network range should be used.

After configuring the Vagrantfile, create the guest machine or run vagrant reload with a running guest for Vagrant to configure the new network.

When the machine comes back up, it will be accessible with the configured static IP. You can verify this with a ping:

$ ping 192.168.33.10
PING 192.168.33.10 (192.168.33.10): 56 data bytes
64 bytes from 192.168.33.10: icmp_seq=0 ttl=64 time=0.412 ms
64 bytes from 192.168.33.10: icmp_seq=1 ttl=64 time=0.259 ms
64 bytes from 192.168.33.10: icmp_seq=2 ttl=64 time=0.364 ms
64 bytes from 192.168.33.10: icmp_seq=3 ttl=64 time=0.275 ms
...

In addition to being able to access the guest, the guest itself is able to access the host machine. This is very useful if the host itself is running services that may be useful for the guest machine. The IP address of the host is always the same IP address but with the final octet as a 1. In the preceding example, the host machine would have the IP address 192.168.33.1. This can be verified by connecting with SSH into the guest machine and pinging:

$ vagrant ssh
vagrant@precise64:~$ ping 192.168.33.1
PING 192.168.33.1 (192.168.33.1) 56(84) bytes of data.
64 bytes from 192.168.33.1: icmp_req=1 ttl=64 time=0.197 ms
64 bytes from 192.168.33.1: icmp_req=2 ttl=64 time=0.216 ms
64 bytes from 192.168.33.1: icmp_req=3 ttl=64 time=0.378 ms
64 bytes from 192.168.33.1: icmp_req=4 ttl=64 time=0.346 ms
...

Guest Operating System Dependency

For each operating system, there are different methods of configuring network devices. Unfortunately, across multiple operating systems, these methods are inconsistent.

Vagrant has built-in knowledge of how to configure networks for a variety of operating systems such as Ubuntu, FreeBSD, Solaris, and more. When booting a machine, Vagrant probes the guest to determine the operating system, and uses this knowledge to do the right thing.

The downside of this is if you’re running an operating system within Vagrant that Vagrant has no knowledge of, then host-only networking cannot be used. In these cases, a bug should be reported to the project.

Bridged Networking

Bridged networking bridges the virtual machine onto a device on your physical machine, making the virtual machine look like another separate physical machine on the network.

Vagrant supports bridged networking by enabling it and allowing the network to which the machine is bridged to use DHCP to assign an IP to the guest machine.

Because the machine appears to be a physical machine on your network, it is accessible by any machine on your network. Likewise, it adheres to any network routing rules and protections that may exist from routers, firewalls, and so on. As an example of this, home and work routers generally don’t allow inbound connections through, so the bridged virtual machine cannot be accessed by the global Internet. However, these routers generally do allow access to machines on the local network, so your mobile device or a coworker’s machine can access the virtual machine as long as they are all connected to the same network.

Pros and Cons

Bridged networking gives you all the benefits of having an IP to access your virtual machine, just like a host-only network. But unlike host-only networks, there is no isolation, so you can use your mobile device to view websites served from the guest machine, you can share your work with coworkers, and so on.

This lack of isolation can also be seen as a downside, if that is a necessary requirement for your project.

One downside of bridged networking with Vagrant is that Vagrant doesn’t currently allow you to specify a static IP for the bridged network. IP addresses from bridged networks are served via DHCP, so you must SSH into the guest machine and inspect the network configurations in order to determine the IP to access the machine. Host-only networks, on the other hand, have predictable static IP addresses.

Another downside of bridged networking is that because the guest must adhere to the network rules in place by the router, bridged networking simply has no benefits for some environments. Most commonly, hotel and airport networks restrict communication between machines on the local network, so even with the IP of the guest machine, you are unable to communicate. In these situations, there is simply no benefit to using a bridged network, and a host-only network must be used.

Basic Usage

Bridged networking is enabled within the Vagrantfile with a single line:

config.vm.network "bridged"

This tells Vagrant to enable a bridged network device for the virtual machine. The IP is served from DHCP so there are no other configuration options here.

When running vagrant up or vagrant reload for the bridged network to take effect, Vagrant will ask you what network you want the device bridged to. If you don’t know what to answer here, you probably want to choose the same device that is connected to the Internet.

In the following vagrant up output, my laptop was connected to the Internet via WiFi at the time, so I choose to bridge onto my wireless networking device, making my virtual machine appear on the WiFi network:

$ vagrant up
Bringing machine 'default' up with 'virtualbox' provider...
[default] Importing base box 'precise64'...
[default] Matching MAC address for NAT networking...
[default] Setting the name of the VM...
[default] Clearing any previously set forwarded ports...
[default] Creating shared folders metadata...
[default] Clearing any previously set network interfaces...
[default] Available bridged network interfaces:
1) en0: Wi-Fi (AirPort)
2) p2p0
3) vnic0
4) vnic1
What interface should the network bridge to? 1
[default] Preparing network interfaces based on configuration...
[default] Forwarding ports...
[default] -- 22 => 2222 (adapter 1)
[default] Booting VM...
[default] Waiting for VM to boot. This can take a few minutes.
[default] VM booted and ready for use!
[default] Configuring and enabling network interfaces...
[default] Mounting shared folders...
[default] -- /vagrant

Because the IP address is served from DHCP, we need to inspect the network configuration from within the virtual machine in order to determine the IP address it was given. For Ubuntu, the box we’re currently using, we do this as follows:

$ vagrant ssh
vagrant@precise64:~$ ifconfig
eth0      Link encap:Ethernet  HWaddr 08:00:27:88:0c:a6
          inet addr:10.0.2.15  Bcast:10.0.2.255  Mask:255.255.255.0
          inet6 addr: fe80::a00:27ff:fe88:ca6/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:332 errors:0 dropped:0 overruns:0 frame:0
          TX packets:225 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:40678 (40.6 KB)  TX bytes:31408 (31.4 KB)

eth1      Link encap:Ethernet  HWaddr 08:00:27:60:3e:01
          inet addr:10.0.1.31  Bcast:10.0.1.255  Mask:255.255.255.0
          inet6 addr: fe80::a00:27ff:fe60:3e01/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:10 errors:0 dropped:0 overruns:0 frame:0
          TX packets:9 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:1216 (1.2 KB)  TX bytes:1494 (1.4 KB)

lo        Link encap:Local Loopback
          inet addr:127.0.0.1  Mask:255.0.0.0
          inet6 addr: ::1/128 Scope:Host
          UP LOOPBACK RUNNING  MTU:16436  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0
          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)

A bit of experience helps here, but Vagrant generally sets up the second adapter as the bridged adapter. This is not always the case, however, so use your knowledge of the network to which you’re bridging to recognize the proper IP address that may be assigned.

In the example output, eth1 is the bridged device, and 10.0.1.31 is the IP address. We can verify that this device is actually bridged onto our network by pinging it:

$ ping 10.0.1.31
PING 10.0.1.31 (10.0.1.31): 56 data bytes
64 bytes from 10.0.1.31: icmp_seq=0 ttl=64 time=0.696 ms
64 bytes from 10.0.1.31: icmp_seq=1 ttl=64 time=0.330 ms
64 bytes from 10.0.1.31: icmp_seq=2 ttl=64 time=0.521 ms
64 bytes from 10.0.1.31: icmp_seq=3 ttl=64 time=0.286 ms
64 bytes from 10.0.1.31: icmp_seq=4 ttl=64 time=0.329 ms
^C
--- 10.0.1.31 ping statistics ---
5 packets transmitted, 5 packets received, 0.0% packet loss
round-trip min/avg/max/stddev = 0.286/0.432/0.696/0.155 ms

As you can see, the ping was successful, indicating the host is reachable. And while it isn’t shown with a simple ping, the host being pinged is in fact the virtual machine that is running.

Warning

As mentioned in Pros and Cons, bridged networking often fails on public networks or under certain router configurations. If vagrant up gets stuck on configuring the networking interfaces, this is likely what is happening.

Composing Networking Options

Each of the networking options comes with its own set of pros and cons. Individually, they’re all equally useful in various use cases. Together, they’re useful for every use case.

Vagrant allows you to enable multiple network options. As long as the guest machine has room for additional network interfaces (the limit in VirtualBox is eight), then Vagrant will configure it.

To enable multiple networks, just define multiple networks in the Vagrantfile:

config.vm.forwarded_port 80, 8080
config.vm.network "hostonly", "192.168.33.10"
config.vm.network "bridged"

Upon reading a Vagrantfile with this configuration, Vagrant would create a forwarded port mapping, create a host-only network with a static IP, and create a bridged network.

In addition to specifying multiple types of networks, it is possible to define multiple networks of the same type, such as specifying multiple host-only networks with different IPs.

NAT Requirement As the First Network Interface

With VirtualBox, Vagrant requires the first network device attached to the virtual machine to be a NAT device. The NAT device is used for port forwarding, which is how Vagrant gets SSH access to the virtual machine.

Therefore, any host-only or bridged networks will be added as additional network devices and exposed to the virtual machine as “eth1,” “eth2,” and so on. “eth0” or “en0” is generally always the NAT device.

It isn’t currently possible to override this requirement, but it is important to understand that it is in place.

What’s Next?

Networking is a key feature for using Vagrant in the most effective way. In this chapter, we showed the multiple options Vagrant gives you to network the guest machine in order to work the way you want to work.

The three networking options exposed by Vagrant cover almost all the use cases needed for networking with the guest machine.

With networking automated with Vagrant, team members who run a vagrant up now not only get shared folders, automated provisioning, and an isolated environment, but also get a way to access the machine using their own tools, such as web browsers. For many employees, such as designers or managers, this means that they never have to SSH into the virtual machine.

This is a powerful concept that makes the entire development process run more smoothly.

In the next chapter, we’re starting to head toward more advanced features of Vagrant with multimachine clusters. These clusters allow you to model multiple machines with a single Vagrantfile, and are very popular with splitting different services out to different machines to better represent production environments.

Get Vagrant: Up and Running now with the O’Reilly learning platform.

O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.