A phone joins the Pi's hotspot, gets an address, and the page still fails. The Pi is running a hotspot helper, Pi-hole and a VPN client, and each one believes it owns part of the path. Most of these builds fail not because a component is broken but because two components do the same job. Assign one owner per function before tuning any of them.

Assign one owner per function

Four functions matter here, and each needs exactly one owner. The table below names the function, a workable owner and what goes wrong when two services claim it.

FunctionWorkable ownerDuplicate-owner symptom
Client addressesOne DHCP server, such as the hotspot helperCompeting offers and changing leases
DNS receptionPi-hole on port 53Bind failure or queries answered by the wrong process
Forwarding and NATOne firewall managerDouble translation and broken return paths
VPN routingOne client configurationRoute flapping and traffic escaping outside the tunnel

The overlap usually arrives one package at a time. The hotspot helper installs its own dnsmasq instance, Pi-hole wants port 53, and the VPN client adds routes. Each step looks reasonable alone, and together they produce a machine where the second service to start quietly changes the first one's behavior.

Write the owners down before enabling anything else. A short table in the build notes prevents a later install from taking over a function that already had an owner.

Pick one range and keep it away from the tunnel

Choose the hotspot range, the Pi's address on it, the DHCP pool and the resolver the clients receive. Keep that range separate from the upstream LAN and from the VPN tunnel range, because overlapping subnets turn a routing problem into an address-translation project. A range that overlaps the tunnel makes the Pi an accidental router between two identical prefixes. Write the range and pool into the hotspot configuration instead of leaving them to a default.

If NetworkManager's shared mode owns the hotspot, inspect the effective connection before adding a DHCP server. Shared mode starts its own helpers and enables forwarding, so it is already the address-plan owner for that interface. Adding a second server because it is available creates competing offers rather than redundancy.

Decide IPv6 deliberately. Router advertisements and DHCPv6 come from a different helper than DHCPv4 in many setups, and leaving IPv6 on while the VPN policy covers only IPv4 gives clients a path that bypasses the tunnel. Either plan the IPv6 side or disable it on the hotspot interface with a written reason.

Who actually answers on port 53

List every process listening on port 53 before changing a configuration. On a Pi that runs a local resolver stub, Pi-hole and a sharing helper, the listener list is the only reliable map of who answers queries:

sudo ss -lunpt '( sport = :53 )'
ip -4 addr show
ip route

Pi-hole's interface guide explains that a reception mode limited to one interface can still use a wildcard socket and discard arrivals elsewhere. That is not the same as binding only selected interfaces, which is the arrangement intended when another DNS service must share the machine.

Two processes normally cannot bind the same address and port, though SO_REUSEPORT can make a shared bind succeed; even then, a wildcard listener can take arrivals meant for the narrower service. Choose the documented mode for the role you want and restart the services in the intended order.

Keep Pi-hole's administration page off the hotspot network. Clients need a resolver, not the web interface or API that can change the resolver's configuration.

Two DNS legs, one policy each

A client query travels from the phone to the Pi, and a separate query travels from the Pi to its upstream resolver. A routing rule that matches forwarded hotspot traffic does not automatically apply to the second leg, because the Pi generates that traffic locally. If the VPN is supposed to carry DNS, the local path needs its own policy.

Watch for a loop. Pointing Pi-hole's upstream at an address the Pi itself serves, directly or through a port-forward, produces queries that circle until they time out. Give it a real upstream or a conditional forwarder for the domains it cannot answer.

Decide what happens when the tunnel drops. Falling back to the local resolver keeps browsing alive but can leak names outside the VPN; blocking keeps the policy intact and turns the outage into a visible error. Either choice is defensible, but it has to be chosen rather than inherited from a default.

Prove the path and the outage behavior

Test in layers: the client gets an address, the client resolves a name through the Pi, the Pi resolves through the intended upstream, and an application completes a request. A successful ping says nothing about DNS, and a successful lookup says nothing about forwarding.

dig @192.168.70.1 example.com
curl -sS -o /dev/null -w '%{http_code}\n' https://example.com/
ip -4 route get 1.1.1.1

Then stop the tunnel and repeat. The intended behavior should appear within a few seconds, not after a manual restart of Pi-hole or the hotspot service. Check the client's resolver setting during the outage, because a secondary public resolver will keep answering even when the policy expected failure.

Keep one owner for forwarding and NAT and verify it from a client, not from the Pi itself. A request that leaves the Pi successfully can still be dropped on the way back, and the client is the only place where the whole path is visible.

Ingingo zihuye