Container in VM Can't Reach Internet? Fix NAT and DNS

Server & Cloud Intermediate 👁 9 views 📅 Jun 27, 2026

Your container inside a VM can't reach the internet. The fix is usually a missing NAT rule or DNS setting. We'll show you the exact steps.

I know how frustrating this is. You set up a container inside a VM, and it just sits there with no internet. Ping fails, apt update fails, everything fails. But don't worry — I've seen this dozens of times. The fix is usually one of two things: a missing NAT rule or a broken DNS config. Let's fix it.

Quick Fix — Enable NAT on the VM

Most of the time, the VM's network adapter is set to "bridged" or "NAT" in your hypervisor. But the guest OS inside the VM doesn't forward traffic from the container. You need to turn on IP forwarding and set up a NAT rule. Here's how.

  1. First, log into your VM (not the container). Open a terminal as root or use sudo.
  2. Check if IP forwarding is on. Run this command:
    cat /proc/sys/net/ipv4/ip_forward
    If it returns 0, turn it on with:
    echo 1 | sudo tee /proc/sys/net/ipv4/ip_forward
    I prefer tee because it's cleaner than redirecting with >>.
  3. Now, make it permanent. Edit /etc/sysctl.conf and add this line:
    net.ipv4.ip_forward = 1
    Save and exit.
  4. Apply the change without rebooting:
    sudo sysctl -p
    You should see net.ipv4.ip_forward = 1 in the output.
  5. Now, add the NAT rule using iptables. This makes the VM act like a router for the container's traffic. Run:
    sudo iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
    Replace eth0 with your VM's external interface. Find it with ip a or ifconfig. On most Linux VMs, it's eth0 or ens33.
  6. Save the iptables rules so they survive a reboot. On Ubuntu/Debian, use iptables-save:
    sudo apt install iptables-persistent
    sudo netfilter-persistent save
    On CentOS/RHEL/Fedora, use service iptables save or iptables-save > /etc/sysconfig/iptables.
  7. Test from inside the container. Run:
    docker exec -it your-container-name ping google.com
    Or if it's an LXC container: lxc-attach -n container-name -- ping google.com. You should see replies now.

But Wait — Check DNS Too

If ping to an IP works (like ping 8.8.8.8) but ping to a domain fails, it's DNS. The container is using the wrong DNS server. Fix it by setting a known good DNS server in the container's config.

For Docker, edit /etc/docker/daemon.json and add:

{
  "dns": ["8.8.8.8", "1.1.1.1"]
}
Then restart Docker: sudo systemctl restart docker. For LXC, edit /etc/resolv.conf inside the container or set lxc.net.0.flags: up and lxc.net.0.link: lxcbr0 in the config file.

Why This Works

When you run a container, it usually gets a private IP (like 172.17.0.2 for Docker or 10.0.3.x for LXC). The VM's host sees this IP, but your router and the internet don't. The host VM needs to do network address translation (NAT) — it rewrites the container's private IP to the VM's own IP before sending traffic out. Without IP forwarding and a MASQUERADE rule, the packets from the container just vanish. The router receives them but doesn't know how to send replies back to the container's private address. Enabling forwarding and adding NAT fixes that.

Less Common Variations

Firewall Blocking Inside the VM

Some VM images come with firewalls that block forwarded traffic. On Ubuntu, ufw is common. Check with sudo ufw status. If it's active and blocking, allow forwarding:

sudo ufw default allow FORWARD
Or add a rule for your container subnet: sudo ufw allow in on docker0 from 172.17.0.0/16 (adjust subnet to match your container's range).

Hyper-V Virtual Switch Issue

If you're on Hyper-V, the external virtual switch might not allow traffic from the container's subnet. Right-click the VM, go to Settings > Network Adapter, and check "Enable virtual LAN identification" — leave it blank unless you need VLANs. Also, make sure the VM's network adapter in the guest OS is set to "Automatic" or "DHCP."

Podman or Rootless Docker

Rootless containers don't use the docker0 bridge by default. They use slirp4netns or pasta for networking. If you're using rootless Docker, you need to enable --net=host or use a CNI plugin. Simpler fix: switch to rootful Docker for this VM. Run sudo dockerd and keep your containers there.

Preventing This from Happening Again

Set up your VM's network once and forget about it. On the VM host, add the iptables rule and IP forwarding to startup scripts. Create a file /etc/rc.local with:

#!/bin/bash
iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
echo 1 > /proc/sys/net/ipv4/ip_forward
exit 0
Make it executable: sudo chmod +x /etc/rc.local. On systemd systems, enable it: sudo systemctl enable rc-local. For Docker, always set DNS in the daemon.json. For LXC, use a static bridge config. Test internet from inside a new container right after you create it — saves you hours later.

Was this solution helpful?