When working with QEMU/KVM virtualization, we commonly use hostfwd
to forward host ports to guest VMs. However, the reverse operation - forwarding guest ports to the host - requires a different approach since QEMU doesn't provide a direct equivalent to hostfwd
for outbound forwarding.
Here are three effective methods to achieve guest-to-host port forwarding:
Method 1: Using libvirt NAT Rules
For libvirt-managed VMs, add the following to your network definition:
<network>
<name>default</name>
<forward mode='nat'/>
<nat>
<port start='1024' end='65535'/>
<forward port='6633' to='6633' toaddr='192.168.122.1'/>
</nat>
<ip address='192.168.122.1' netmask='255.255.255.0'>
<dhcp>
<range start='192.168.122.2' end='192.168.122.254'/>
</dhcp>
</ip>
</network>
Method 2: SSH Reverse Tunneling
From the guest VM, establish a reverse SSH tunnel:
ssh -NfR 6633:localhost:6633 user@host-machine
This forwards guest port 6633 to the host's 6633 port through an encrypted connection.
Method 3: Custom QEMU Network Configuration
When launching QEMU directly, use tap networking with iptables rules:
sudo qemu-system-x86_64 \
-net nic -net tap,script=/etc/qemu-ifup \
-m 2048 -hda vm.qcow2
Then create /etc/qemu-ifup
with:
#!/bin/sh
sudo /sbin/iptables -t nat -A PREROUTING -p tcp --dport 6633 -j DNAT --to-destination 192.168.122.1:6633
sudo /sbin/iptables -I FORWARD -d 192.168.122.1/32 -p tcp -m state --state NEW -m tcp --dport 6633 -j ACCEPT
- Ensure host firewall rules allow the forwarded traffic
- Verify the host IP in the guest's default route
- Check that the service is listening on the correct interface
- Confirm SELinux/apparmor isn't blocking the connection
For more complex scenarios, consider creating a bridged network where the guest appears as a separate host:
sudo brctl addbr br0
sudo brctl addif br0 eth0
sudo ifconfig br0 up
Then launch QEMU with:
sudo qemu-system-x86_64 -net nic -net bridge,br=br0 -m 2048 -hda vm.qcow2
When working with QEMU/KVM virtual machines, we often need bidirectional network communication between host and guest systems. While forwarding host ports to guests (using hostfwd
) is well-documented, the reverse scenario - exposing guest ports to the host - requires different approaches.
The default user-mode networking (-net user
) doesn't support guest-to-host port forwarding out of the box. This is because:
- User-mode networking implements NAT, making the guest appear behind the host
- By design, it only allows initiated connections from guest to external networks
Method 1: Using TAP Networking
The most robust solution is to configure a TAP interface:
# Create tap interface
sudo ip tuntap add dev tap0 mode tap
sudo ip addr add 192.168.123.1/24 dev tap0
sudo ip link set tap0 up
# Start QEMU with tap networking
qemu-system-x86_64 \
-netdev tap,id=mynet0,ifname=tap0,script=no,downscript=no \
-device virtio-net-pci,netdev=mynet0
On the guest system, configure a static IP (e.g., 192.168.123.2) and you can now access host services directly.
Method 2: SSH Reverse Tunneling
For quick temporary solutions, SSH can create reverse tunnels:
# From guest machine:
ssh -R 6633:localhost:6633 user@host
This forwards guest port 6633 to host port 6633.
Method 3: Using socat
For TCP forwarding without SSH:
# On host (assuming default SLIRP IP):
socat TCP-LISTEN:6633,fork TCP:10.0.2.2:6633
When implementing these solutions:
- Firewall rules may need adjustment on both host and guest
- For production environments, consider bridged networking instead of TAP
- Performance-critical applications may benefit from virtio-net drivers
Verify connectivity with these tools:
# Check listening ports on guest:
ss -tulnp
# Test connection from host:
telnet 192.168.123.2 6633
nc -zv 192.168.123.2 6633