Currently I'm using the following script to make several virtual machines access the Internet and allow some ports being forwarded through the host's NAT inside a host-only network.

host_interface=eth0 # name of host machine interface connected to the Internet
vnet_interface=vboxnet0 # name of host machine's local network interface
host_ip[0]=... # array contains external IP addresses for every guest
guest_ip[0]=... # array contains internal IP addresses for every guest
guest_ports[0]=21,22,80,443 # array of port lists for every guest

iptables -P INPUT ACCEPT
iptables -F INPUT
iptables -F OUTPUT
iptables -F FORWARD
iptables -t nat -F

echo "1" > /proc/sys/net/ipv4/ip_forward

for i in ${!host_ip[*]}
        iptables -t nat -A PREROUTING -i $host_interface -d ${host_ip[$i]} -p tcp -m multiport ! --dports "${guest_ports[$i]}" -j ACCEPT
        iptables -t nat -A PREROUTING -i $host_interface -d ${host_ip[$i]} -j DNAT -p tcp -m multiport --dports "${guest_ports[$i]}" --to-destination ${guest_ip[$i]}

# forward all packets from already established connections
iptables -A FORWARD -m state --state ESTABLISHED,RELATED -j ACCEPT

for i in ${!guest_ip[*]}
        # allow forwarding new connections from host to guest
        iptables -A FORWARD -i $host_interface -o $vnet_interface -d ${guest_ip[$i]} -m state --state NEW -j ACCEPT

        # allow forwarding new connections from guest to host
        iptables -A FORWARD -i $vnet_interface -o $host_interface -s ${guest_ip[$i]} -m state --state NEW -j ACCEPT

        iptables -t nat -A POSTROUTING -o $host_interface -s ${guest_ip[$i]} -j SNAT --to-source ${host_ip[$i]}

The only thing is missing here is an ability to access any guest machine by it's EXTERNAL IP address (within local network of course). I'm getting "Connection refused" message every time I trying to connect to the open port of the same machine or another guest (but able to connect to the host from any guest). Internal (private) IPs works fine, I'm able to connect to any guest and host from anywhere within local network. Tried adding something like

iptables -t nat -A PREROUTING -i $vnet_interface -d ${host_ip[$i]} -j DNAT --to-destination ${guest_ip[$i]}

but it seems that it is insufficient.

  • Try running tcpdump or wireshark on the both the host machine and guest machine to see what's happening. Also, you might want to label your question virtualbox since there might be something VirtualBox specific, e.g. the way the network card of the guest is configured. By the way, if I remember correctly, VirtualBox had something for port forwarding. – Cristian Ciupitu Nov 1 '10 at 0:39
  • Do you understand what the script does, or did you just copy it from somewhere and tried to use it in your environment? There are many things in it that don't make much sense. – Juliano Nov 1 '10 at 1:04
  • There is nothing VirtualBox-specific here. – Lux In Tenebris Nov 1 '10 at 22:08
  • That script is written completely from scratch only for my own system using several iptables tutorials. Unfortunately I'm not an iptables-guru yet. – Lux In Tenebris Nov 1 '10 at 22:11

If I understand correctly, your problem is that your VM guests can't access themselves or the other guests by their external IP addresses. The problem you are having is clearly illustrated on this page (just imagine the router is your VM host, and the web server is one of your VM guests). You need to configure "Hairpin NAT".

The solution, to quote that same page, is that

an additional NAT rule needs to be introduced on the [VM host] to enforce that all reply traffic flows through the [VM host], despite the client and server being on the same subnet.

In your case, such rules could look something like this:

iptables -t nat -A PREROUTING -s $host_only_network -d ${guest_ip[$i]} -o $vnet_interface -p tcp -m multiport --dports "${guest_ports[$i]}" -j MASQUERADE


host_only_network=  # replace with whatever applies to your guest network

I'll leave it to you completely debug this, as complicated NAT setups tend to give me serious headaches.


setting your input policy to accept by default is a really bad idea, you should use

iptables -P INPUT DROP

also forwarding by default is bad. You can always set an allow-all rule for traffic from specific interfaces to always be permitted on input or forward which is OK.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.