Ping succeeds from a VPN client, the TCP service times out, and ufw allow 443/tcp changes nothing at all. When the application runs on a host behind the gateway rather than on the gateway itself, that allowance was written for the wrong traffic path. The packet is not addressed to the firewall and is not delivered to a local process, so the input rules never see it. The repair is a route rule aimed at the forwarded flow, and the evidence for it is already in the log.

Decide whether the destination is local or forwarded

Read the packet as the kernel sees it. Traffic delivered to a service on the gateway is local input. Traffic the gateway routes onward to another host is forwarded, and UFW keeps separate rule sets for the two paths. The distinction is decided by the destination address and the routing lookup, not by which interface the packet arrived on.

A log line showing the same interface in both the IN and OUT fields can still describe a routed packet, because a tunnel that carries clients in and out of one device looks exactly like that. The destination address settles the question faster than the interface names do. Seeing the same name twice does not prove local delivery, and inventing a tunnel interface that the deployment never created does not help either.

Read the block before adding any rule

Reproduce one authorised connection attempt and capture its source, destination, protocol and destination port as the gateway recorded them. Compare those four values with the log entry and with the service's actual location. A successful ping earlier proves only that its own exchange was permitted, and a firewall may treat a TCP SYN to an application quite differently.

sudo dmesg | grep "UFW BLOCK" | tail -n 5
sudo ufw status numbered

The first command returns the verdict with its tuple, and the second shows what is already loaded and in which order. Read both before editing anything, because an earlier deny above your rule explains the same symptom without any missing rule.

Write the narrowest route rule that fits

For this walkthrough, clients arrive on tun0 from 172.20.8.0/24, the service listens on 10.30.0.15 at port 8443, and the gateway leaves through ens5. Those values were chosen to look nothing like a cloud VPC default of 10.0.0.0/16 or a home 192.168.0.0/16, and 8443 keeps the example away from the gateway's own 443 listener.

sudo ufw --dry-run route allow in on tun0 out on ens5 proto tcp from 172.20.8.0/24 to 10.30.0.15 port 8443

The dry run prints the rule set that would result, which is the cheapest way to see whether your rule lands before or after an existing deny. Confirm the interface names and inner addresses against the deployment rather than the example, and remember that when destination NAT runs first, the filter sees the translated destination.

Keep the return path stateful

UFW tracks allowed connections, so the replies to a permitted forwarded flow are admitted without an explicit reverse rule. Adding an unrestricted rule in the opposite direction to make things work widens the policy far beyond the single service and is not required for a normal request-reply exchange. Keep the return path implicit and the rule set readable.

Apply the rule only after the dry run matches your intent, then confirm the ordered list shows it in the expected position. Preserve the VPN listener and management rules as separate concerns; a change to those is a different decision from admitting one application. Note the change in the same place the topology is written down, so the next engineer does not rediscover it from a packet capture.

sudo ufw route allow in on tun0 out on ens5 proto tcp from 172.20.8.0/24 to 10.30.0.15 port 8443
sudo ufw status numbered

Check what UFW cannot enforce for you

A correct rule still needs kernel forwarding and a route that reaches the service. Confirm both before blaming the firewall a second time.

sysctl net.ipv4.ip_forward
ip route get 10.30.0.15

Then look outside the host. On a cloud instance the guest's UFW policy does not replace security groups, subnet ACLs or the provider's own forwarding configuration, so a local block is evidence about one layer rather than proof that every other layer permits the service.

Finish by testing a fresh connection with the firewall enabled, from an allowed source and from an unrelated one. Disabling UFW removes the symptom and destroys the evidence in the same command, which is why it should be the last experiment rather than the first.

Artihkkalat mat laktásit