130

I'm working on a web services architecture. I've got some software that I need to run on the native host machine, not in Vagrant. But I'd like to run some client services on the guest.

Vagrant's config.vm.forwarded_port parameter will open a port on the host and send the data to the guest. But how can I open a port on the guest and send the data to the host? (It's still port forwarding, but in the reverse direction.)

Dan Fabulich
  • 37,506
  • 41
  • 139
  • 175
  • Since Vagrant is using SSH it is theoretically possible and the [Ruby SSH implementation gem](https://github.com/net-ssh/net-ssh) supports this but never saw anything like this in the Vagrant docu. – cmur2 Apr 26 '13 at 21:05
  • See also: http://stackoverflow.com/q/19933550/1157054 – Ajedi32 Jul 21 '15 at 15:28

5 Answers5

142

When you run vagrant ssh, it's actually using this underlying command:

ssh -p 2222 -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -o LogLevel=ERROR -o IdentitiesOnly=yes -i ~/.vagrant.d/insecure_private_key vagrant@127.0.0.1

SSH supports forwarding ports in the direction you want with the -R guestport:host:hostport option. So, if you wanted to connect to port 12345 on the guest and have it forwarded to localhost:80, you would use this command:

ssh -p 2222 -R 12345:localhost:80 -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -o LogLevel=ERROR -o IdentitiesOnly=yes -i ~/.vagrant.d/insecure_private_key vagrant@127.0.0.1

As Eero correctly comments, you can also use the command vagrant ssh -- -R 12345:localhost:80, which has the same effect in a much more concise command.

William Luc Ritchie
  • 1,666
  • 1
  • 11
  • 15
  • 72
    and you can run this more simply using `vagrant ssh -- -R 12345:localhost:80` This follows the ssh option syntax **-R** _[bind_address:]port:host:hostport_, where the first number is the port number to listen on inside the guest machine, and the last two are the service address as visible from the host machine. – Eero May 13 '13 at 12:33
  • 2
    As far as I understand that reverse forwarding only works in the corresponding ssh shell. I think Dan Fabulich wanted a solution without the need to ssh into the vm. – Alp Nov 22 '13 at 21:08
  • 2
    @Alp I believe it's a port available to the whole system, not just available to the ssh process. Works fine for me! – Henrik Heimbuerger Jan 29 '14 at 16:09
  • 1
    For those who use PuTTy, the SSH/Tunnels section of the configuration gui allows both Remote port forwarding (hence the -R in the command) or Local port forwarding (-L in the command line) – Titou Jan 16 '15 at 11:10
  • 3
    Or something accounting for vagrant's potentially differente config if you have multiple vagrant setup: `vagrant ssh-config | ssh -F /dev/stdin $BOX -R $PORT_VM:localhost:$PORT -N` – ibizaman Nov 11 '15 at 10:36
  • Thanks guy for you saving my day !! – haotang Sep 22 '16 at 08:14
107

In the book Vagrant: Up and Running (Pub. date: June 12, 2013), written by the creator of Vagrant, he mentioned that it is not possible for guest machine to access services running on the host machine.

Instead of using Forwarded Ports, you could set up a private network using Host-Only Networks.

  • Pros of using Host-Only Networks over Forwarded Ports

    1. Guest machines may access the services running on host machine

      This feature would solve your problem.

    2. Guest machines may access the services running on other guest machine

      This feature is very useful to separate services onto multiple machines to more accurately mimic a production environment.

    3. Secure

      Outside machines have no ways to access the services running on the guest machines

    4. Less work

      No need to configure every single Forwarded Port


  • How to configure Host-Only Networks

    config.vm.network :"hostonly", "192.168.0.0" # Vagrant Version #1

    config.vm.network :private_network, ip: "192.168.0.0" # Vagrant Version #2

    Having this line in your Vagrantfile will instruct vagrant to create a private network that has a static IP address: 192.168.0.0

    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.0.1.

Community
  • 1
  • 1
Mingyu
  • 31,751
  • 14
  • 55
  • 60
  • 2
    In the same vein (also from `Vagrant: Up and Running`), you could set up a bridged network. On a bridged network, other machines in your local network can access your virtual machine, and vice versa. But since the IP address is assigned via DHCP, you'd have to `ifconfig` in the virtual machine to find its IP address. – nucleartide Aug 05 '13 at 15:50
  • 32
    The fact that when you setup config.vm.network :private_network, ip: "192.168.50.4" means that the guest will access the host by going to "192.168.50.1" is the key bit of information here. I cannot find that little tidbit documented anywhere. – Owen Allen Aug 26 '13 at 21:08
  • 1
    I found using the answers address of `192.168.0.0` didn't work - curling / pinging the host machine was resulting in connection t/o's. Using @Nucleon's address (consistent with the [Vagrant docs](http://docs.vagrantup.com/v2/networking/private_network.html) on the topic) worked as advertised. – markdsievers Oct 31 '13 at 19:59
  • @markdsievers, the last sentence of the answer actually states if you want to access the host machine from VM, the IP address is 192.168.0.1. It seems that Nucleon does agree with the answer. Anyway, I am glad your problem is resolved. – Mingyu Oct 31 '13 at 20:21
  • 8
    @Mingyu No - using your configuration line `config.vm.network :private_network, ip: "192.168.0.0"` and curling / pinging the host on `192.168.0.1` was resulting in connection time outs. Configuring the network to be `192.168.50.4` resolved it ie host available at `192.168.50.1`. – markdsievers Oct 31 '13 at 20:27
  • 4
    "192.168.0.0" is not a good example, x.x.x.0 normally is for broadcast ing – number5 Dec 13 '13 at 01:11
  • For windows at least, the host adapter (192.168.x.1) is going to have the firewall deployed. This can make it tricky to reach services on the host machine, or could require extra hostside configuration (which I try to avoid as much as possible since well I'm using Vagrant to push that stuff to VMs). – Frank Schwieterman Aug 11 '14 at 17:44
  • @FrankSchwieterman I'd amend that to say the host *may* have a firewall deployed; I don't see the issue with possible additional host configuration to use the VMs. – Dave Newton Sep 15 '14 at 16:33
  • The `ip` command is very helpful with debugging/configuring networking on linux - it's well worth learning! For example `ip l` will show all NICs, `ip a` shows all assigned addresses/masks and `ip r` will show all routing (default route will be via router which in this case must be the host computer) – derekdreery Aug 18 '15 at 09:22
  • @Nucleon Help me to understand how the guest will access the host by going to "192.168.50.1"? – DarkForce Mar 07 '16 at 14:44
83

You can access ports on the host machine through the default gateway inside the guest OS. (Which typically has an IP of 10.0.2.2.)

For example, if you have a webserver running on port 8000 on your host machine...

echo 'Hello, guest!' > hello
python -m SimpleHTTPServer 8000

You can access it from inside the Vagrant VM at 10.0.2.2:8000 (provided 10.0.2.2 is the ip of the guest's default gateway):

vagrant ssh
curl http://10.0.2.2:8000/hello # Outputs: Hello, guest!

To find the IP of the default gateway inside the guest OS, run netstat -rn (or ipconfig on a Windows guest) and look for the row with a destination IP of 0.0.0.0 (or the field labeled "Default Gateway" on Windows):

$ netstat -rn
Kernel IP routing table
Destination     Gateway         Genmask         Flags   MSS Window  irtt Iface
0.0.0.0         10.0.2.2        0.0.0.0         UG        0 0          0 eth0
10.0.2.0        0.0.0.0         255.255.255.0   U         0 0          0 eth0
192.168.33.0    0.0.0.0         255.255.255.0   U         0 0          0 eth1

You can extract this IP programmatically with netstat -rn | grep "^0.0.0.0 " | tr -s ' ' | cut -d " " -f2.

Sources: How to connect with host PostgreSQL from vagrant virtualbox machine; Connect to the host machine from a VirtualBox guest OS?

Community
  • 1
  • 1
Ajedi32
  • 45,670
  • 22
  • 127
  • 172
10

Add following to your ~/.ssh/config on the host machine:

Host 127.0.0.1
RemoteForward 52698 127.0.0.1:52698

It lets you access a service on host machine port 52698 from Vagrant, as long as you logged in via vagrant ssh.

You can confirm it works by running netstat -lt on vagrant VM and taking a note on the following lines:

tcp      0    0 localhost:52698         *:*                 LISTEN
tcp6     0    0 ip6-localhost:52698     [::]:*              LISTEN
stacker-baka
  • 333
  • 6
  • 12
  • 2
    +1 This was a huge help to me. I added the given text replacing with port 5037 to allow my vagrant box to be able to listen to the android emulator running on my host box. – rob Dec 26 '18 at 15:17
2

I can access services running on my host machine via its local IP address (not its loopback address). I tested by creating an http server on port 80 (and then on port 987) and curling 197.45.0.10:80 and 197.45.0.10:987 (actual ip address changed to protect the innocent). It worked both times, and I don't have any special vagrant configuration (no public_network, no forwarded_port) and while I do have some ports forwarded via PuTTY, I don't have ports 80 and 987 forwarded. So maybe try using the host machine's local or public IP address.

And if you want to access (ssh into) one guest vagrant instance from another, you can enable public_network as well as forwarding from port 22 in the Vagrantfile like this:

config.vm.network "public_network"
config.vm.network "forwarded_port", guest: 22, host: 2200

Then as long as that port is open (ie do some more port forwarding in your router config) you can access that machine from anywhere, even the outside world.

Dave Newton
  • 158,873
  • 26
  • 254
  • 302
B T
  • 57,525
  • 34
  • 189
  • 207