A client authenticates, receives an address from the pool, and reaches services on the VPN host, yet every public destination times out. That is what a tunnel without egress looks like, and it stays that way until four separate things are true. The client must accept a default route, the server must forward, the firewall must permit the transit, and replies need a path back to the pool. All four failures share one symptom, so change a single item per attempt and note the result.

Push the default route and confirm what the client installed

The server-side line is short, and it only affects clients that accept pushed options. The def1 form installs two half-default routes instead of deleting the existing default, which keeps the current connection alive while still capturing every destination.

push "redirect-gateway def1"

After reconnecting, read the client's routing table rather than trusting the profile. On Linux the two /1 entries appear next to the original default, and Windows shows the same pair as 0.0.0.0/1 and 128.0.0.0/1. A client that ignores pushed options, or one configured to refuse them, keeps its old default and never sends internet traffic into the tunnel. Settle that question before changing anything on the server, because no server-side rule can compensate.

Forwarding is a server setting, not a VPN setting

Read the forwarding flag before you touch routing. A zero there means the kernel receives the client's packet and declines to pass it along, which looks exactly like a firewall block from the far end. Set the value through the system's configuration directory so it survives a reboot.

sysctl net.ipv4.ip_forward
echo 'net.ipv4.ip_forward=1' | sudo tee /etc/sysctl.d/99-vpn-forward.conf
sudo sysctl --system

Next, confirm the host itself has a working route to the internet exit. A request from the server's shell proves the upstream path is usable and says nothing at all about forwarding a client's packet, so treat those as two separate tests. If the server cannot reach the destination, no amount of forwarding configuration will help.

Permit the transit you intend, and nothing else

Forwarded packets cross the forward path; traffic addressed to the VPN host itself crosses input. Those are distinct decisions, and opening the input path does not permit transit through the machine. Mixing them up is the most common reason a firewall appears to allow everything while clients still time out.

A minimal policy accepts new connections from the pool toward the exit interface and accepts replies that belong to established flows. Put it in whichever ruleset owner your distribution uses, rather than appending a duplicate rule at every boot; duplicated rules accumulate and the counters stop meaning anything.

sudo iptables -A FORWARD -i tun0 -o eth0 -s 10.90.0.0/24 -j ACCEPT
sudo iptables -A FORWARD -i eth0 -o tun0 -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT

Switching every chain to accept makes the test pass and removes the reason the firewall exists. Keep the scope to the pool and the exit interface, and leave unrelated forwarding alone.

Give the replies somewhere to go

Pool addresses are private, so a public server cannot deliver a reply to them directly. Either the VPN host translates the source address on the way out, or a device upstream holds a route back to the pool.

sudo iptables -t nat -A POSTROUTING -s 10.90.0.0/24 -o eth0 -j MASQUERADE

Add exactly one translation layer. A second NAT further upstream hides the first and makes both logs nearly useless when something breaks later. If an upstream router already routes the pool back, adding translation on the host is redundant, and the return path then depends on that router's configuration rather than on yours.

Cloud instances add one more gate, because some platforms drop packets whose source address is not the instance's own unless that check is relaxed. That setting sits outside the guest and is easy to forget when a local test machine works.

Prove it from the client, not from the server shell

Start with a numeric IPv4 request, then a name lookup, then the application. A ping proves forwarding and translation; it proves nothing about resolution, because DNS options only take effect when the client integration installs them.

curl -4 -m 5 http://198.51.100.10/
dig +short example.com

Record the changes and the undo step as you go, so the egress policy can be reverted in one action when a test fails. This recipe covers IPv4 only; inventory IPv6 separately before claiming the deployment carries all traffic.

Lahatsoratra mifandraika