tl;dr
The root cause is that the default route was not set to the router's IP address.
My journey to resolve the issue:
The issue is that port mapping can work with my raspberry pi while it couldn't work with a virtual machine in the same LAN.
I firstly think it must be a bug from the router. I upgrade the router to its latest firmware, but it still doesn't work.
I google back and forth, I learned much from all kinds of answers, but they were just not my case. I almost decided to give up.
Then I found the following answer from E. van Putten, he answered this question and nobody gave his answer a "Like"!!!
In case you landed on this page because you can't reach a server running inside a Xen Guest from the internet (but can connect locally), then read on...
- The fritzbox can get confused by different OS'es appearing from the same MAC-address etc. (could happen while you are setting up / experimenting with Xen)
- The fritzbox has seemingly duplicate entries in the list, but with different settings, you need to delete the portmap from the incorrect entry, cleanup the list and reapply the portmap settings.
- It might be that your guest OS has no default gateway IP-address set. You'd expect a default gateway set to the local IP-address of your fritzbox.
The symptoms of a missing default gateway is that your LAN PCs can access the server running inside the guest just fine, but external users from the internet cannot connect.
He gave three possible causes, and my case is the third one! here's my solution
opts = {
:name => "yt-gateway",
:ip => "192.168.178.173",
:mem => "1024",
:cpu => "1"
}
Vagrant.configure("2") do |config|
config.vm.box = "bento/ubuntu-20.04"
config.vm.hostname = opts[:name]
config.vm.network :public_network, ip: opts[:ip], bridge: "eno1"
config.vm.provision "shell", run: "always", inline: "route add default gw 192.168.178.1 || true"
config.vm.provider "virtualbox" do |v|
v.name = opts[:name]
v.customize ["modifyvm", :id, "--memory", opts[:mem]]
v.customize ["modifyvm", :id, "--cpus", opts[:cpu]]
v.customize ["modifyvm", :id, "--name", opts[:name]]
end
end
I love you E. van!