This project demonstrates a small virtual infrastructure built with:
- Router VM (Debian 12)
- Server VM (Debian 12)
- Isolated virtual network (labnet)
- NAT + IP forwarding
- nftables firewall rules
⚠️ Warning: The interface names on your system may vary, please check the interface names before configuring the network.
Server → Internet
Server VM
│
│ default gateway
▼
Router VM (enp7s0)
│
│ NAT masquerade
▼
Router VM (enp1s0)
│
▼
Internet
Internet → Server (response)
Internet
│
▼
Router VM (enp1s0)
│
│ NAT translation
▼
Router VM (enp7s0)
│
▼
Server VM
| Device | Interface | Network | IP |
|---|---|---|---|
| Router VM | enp1s0 | external | DHCP |
| Router VM | enp7s0 | labnet | 192.168.100.1 |
| Server VM | enp1s0 | labnet | 192.168.100.10 |
Subnet:
192.168.100.0/24
Gateway:
192.168.100.1
What is KVM?
KVM (Kernel-based Virtual Machine) is a Linux kernel module that turns Linux into a hypervisor. It allows running virtual machines with near-native performance using hardware virtualization (Intel VT-x / AMD-V). KVM is built into the Linux kernel.
What is libvirt?
libvirt is a virtualization management API. It provides a unified way to manage:
- Virtual machines
- Virtual networks
- Storage pools
- Bridges
Instead of managing QEMU directly, we manage everything via libvirt.
What does virt-manager do?
virt-manager is a graphical interface for managing libvirt.
It allows:
- Creating VMs
- Configuring networks
- Editing hardware
- Viewing console
qemu-kvm
libvirt-daemon-system
libvirt-clients
virt-manager
bridge-utils
nftables/etc/network/interfaces
/etc/nftables.conf
/etc/sysctl.d/99-ipforward.conf
/etc/resolv.confip a
ip route
ping
traceroute
systemctl status nftables
sysctl -a
sysctl net.ipv4.ip_forwardEnable IP Forwarding
Debian 12 uses systemd-sysctl, which reads configuration from:
/etc/sysctl.d/*.conf
I created:
/etc/sysctl.d/99-ipforward.conf
With:
net.ipv4.ip_forward=1
Apply:
sysctl --system
NAT Configuration (nftables)
Example NAT configuration:
table ip nat {
chain postrouting {
type nat hook postrouting priority 100;
oifname "eth0" masquerade
}
}1️⃣ Server VM in Wrong Subnet
Problem:
Server network interface was not configured in the same subnet as Router VM.
Root Cause:
Incorrect network configuration inside VM.
Solution:
Reconfigured interface to:
192.168.100.10/24
Gateway: 192.168.100.12️⃣ IP Forwarding Reset After Reboot
Problem:
After reboot:
net.ipv4.ip_forward = 0
Cause:
Setting was changed manually but not persisted.
Solution:
Created persistent config file in:
/etc/sysctl.d/99-ipforward.conf
Because Debian 12 uses systemd-sysctl.
3️⃣ NAT / Masquerade Not Working
Problem:
Server had no internet access.
Cause:
Incorrect nftables configuration.
Solution:
Studied nftables manual and correctly implemented:
- NAT postrouting
- Forward chain rules
- Masquerade on external interface
4️⃣ Ping to Google Not Working
Problem:
Server VM could not ping 8.8.8.8.
Deep Root Cause:
IP address conflict.
Router VM:
192.168.100.1
Host machine (via virbr1):
192.168.100.1
libvirt automatically created a bridge (virbr1) and assigned the same IP address as my Router VM.
This created a routing conflict.
Solution:
I edited the XML definition of virtual network labnet:
virsh net-edit labnet
And removed host IP assignment from the bridge.
After that:
- No more IP conflict
- Correct routing
- Internet worked
5️⃣ Default Gateway Showing "onlink"
Problem:
default via 192.168.100.1 dev eth0 onlink
Cause:
Improper route configuration.
Solution:
Corrected subnet and gateway configuration in /etc/network/interfaces.
.
├── README.md
├── router/
│ ├── nftables.conf
│ ├── 99-ipforward.conf
│ └── interfaces
├── server/
│ └── interfaces
└── scripts/
├── setup_router.sh
└── setup_server.sh
- Linux networking
- Routing fundamentals
- NAT configuration
- nftables
- Troubleshooting methodology
- Understanding of libvirt networking
- Persistent kernel configuration
- Route analysis
