The server moved to a new address, clients still connect, and nothing they send reaches the internet. That split is the clue: the listening socket and the port forward survived the move, so the tunnel comes up, while the source translation applied to forwarded packets still names an address the host no longer owns. Replies to those rewritten packets go to a machine that is not there any more.

Connecting and forwarding fail in different places

Establishment depends on the endpoint clients already know: the public address, the port forward in front of it, and the listener inside. Forwarded traffic depends on a second decision made after the packet enters the tunnel, when the host rewrites its source so replies can find their way back.

An address change breaks only the second decision, and that is why the symptom reads as "connected but no internet". It also explains why the usual client-side checks look healthy: the handshake completes, the client receives an address, and a ping to the server's tunnel address may even answer. Hours get spent on the client for a fault that lives on the other side, which is why the rule table is the first place to look.

Read the rule and its counters before editing

List the translation rules with counters and compare the configured source against the addresses the host actually holds. A rule that has been rewritten to a dead address usually shows traffic on the way in, because packets reach it and are translated, and nothing on the way back.

sudo iptables -t nat -L POSTROUTING -n -v --line-numbers
ip -4 addr show

Check three fields while you are there: the pool in the source match, the exit interface if the rule names one, and the exclusion that keeps tunnel-to-tunnel traffic from being rewritten. That exclusion is easy to lose during an edit, and losing it makes peer traffic appear to work while its replies take a strange path.

If the counters are stuck at zero, packets never reach this rule and the address is not the current problem. Look for a competing rule earlier in the chain, which is what happens when someone adds a replacement instead of editing the original. Compare the rule numbers against the output you noted a minute ago. Order is part of the configuration, not a cosmetic detail.

Replace the source, or stop naming one

When the host has a stable address, replace the rule in place rather than appending another one. Replacing by rule number keeps the ordering that the rest of the chain depends on.

sudo iptables -t nat -R POSTROUTING 1 -s 10.8.0.0/24 ! -d 10.8.0.0/24 -j SNAT --to-source 10.151.0.40

When the address is assigned dynamically, name no source at all and let the kernel choose the current one from the exit interface. That variant survives the next move without an edit, at the cost of hiding which address was used.

sudo iptables -t nat -R POSTROUTING 1 -s 10.8.0.0/24 ! -d 10.8.0.0/24 -o eth0 -j MASQUERADE

Confirm that IPv4 forwarding is still enabled through managed configuration, then persist the rule with the distribution's own mechanism. A change made only in the running kernel returns with the next reboot, usually during a maintenance window nobody connects to the change.

Two ways to get the replacement wrong

Translating the pool to the server's tunnel address instead of its LAN address sends replies straight back into the tunnel, where they are routed toward a client that never asked for them. The connection stalls in a way that looks like a routing loop because it is one.

Stacking a second translation above the old one is the other mistake. The first matching rule wins, so the stale entry keeps handling packets until it is deleted, and the new rule's counters stay at zero while everyone blames the replacement. Delete the duplicate before adding anything new. Then read the list once more and confirm that exactly one translation matches the pool.

If the tunnel also carries IPv6, repeat the whole review on the other stack. An IPv6 default route with no translation and no routed prefix fails just as silently, and it is easy to forget because everything above it looks identical.

Inbound services need the opposite translation

A service on a VPN client that must be reachable from outside needs destination translation, not source translation: the public port is rewritten to the client's tunnel address before it enters. The forward path then needs an explicit rule permitting that traffic.

sudo iptables -t nat -A PREROUTING -p tcp --dport 8080 -j DNAT --to-destination 10.9.8.2:8080

Never translate the port that carries the tunnel itself, because that rewrite interrupts the connection keeping the service reachable. Keep the tunnel port out of the destination rules entirely. Verify from both ends afterwards: counters on the new rule, a short capture on the tunnel device, and one request to an address inside the tunnel before you try the public one.

ບົດຄວາມທີ່ກ່ຽວຂ້ອງ