How to (re-)route *only* port 80 traffic over a vpn?

Our ISP in Thailand has the nasty habbit of intercepting http traffic and showing ads.
At the moment, I reject all http traffic going to WAN, but this isn't a great solution; for example, I have to modify my apt source lists to https...
As a workaround, I would like to reroute only http traffic requests coming from my LAN, destined for WAN, to go to a wireguard (or openVPN) interface.
I have been looking at different scenarios in the openwrt docs, but none of them seem to match my scenario and with my limited knowledge I fear it is not possible.
But, is it possible (and how)?

Another option I will test is using a port forward for LAN to WAN traffic on port 80, to forward it to port 81 on the router and use nginx and a server block to return a 303 status and rewrite the location to https.

I think you could probably use fwmark and ip rule to do this. There may or may not be a way to do this using OpenWRT specific tools, so you might need to create hooks and/or a script I suppose?

Use Policy Based Routing either the full package or in this case make a routing table and a rule to add port 80 to the routing table

You can use a hotplug script to start the routing when the interface is up

Here is an example:

The script only only has routing of interface and IP address you can add dport 80 instead.

Will add it to the script when I have time :slight_smile:

Alternatively add a static route via the VPN , unfortunately the use of dport/sport is not yet supported in UCI as far as I know so just the manual routing and rule:

ip route add default dev <VPN-interface > table 100
ip rule add dport 80 table 100

Try from the command line and if it works add to startup (/etc/rc.local ) probably precede with sleep 20 to give the VPN interface time to start

What browser accessed site use http in 2024 ?
I'm surprised your browser would even allow access to such URLs.

If the ads aren't coming from sites hosted by the ISP, use AdBlock ?

1 Like

Thanks, this looks to be what I need, I will test it this weekend.

I think the browser (duckduckgo) is handling it wrong, the sites I use all support https. (BTW, I find it strange the urls in the apt source lists are http...)
It happens when I type a domain name in the address bar and press 'go' (enter).
Then the browser appears to default to http.
If you select a search result, it will go to the https variant.
Screen caps:

Initially I just added the ISP's ad domain to my pihole, but then you get the redirect to the ad domain and have to type the original domain's name again (incl. the https protocol. Now I just insert the missing 's'.

Another option is to use https-dns-proxy, to bypass the ISPs DNS hijacking.

They don't do that, it is 'just' the http interception.
However, I do use PiHole with Unbound which is configured to use AdGuard's public servers via DoT.

The easiest is using ip rule … dport 80 …, however it seems that neither UCI nor ip rule from busybox supports that.

  1. In your wg/openvpn interface configuration, set Advanced SettingsOverride IPv4 routing table and Override IPv6 routing table to 1000
  2. Install iproute2: opkg instlall ip
  3. run ip rule add ipproto tcp dport 80 lookup 1000

You'll need to add third command somewhere to the firewall or interface hook script.

There is no "http version" of, or most other web sites. The only thing you will get when accessing port 80 is a redirect to the https site. The browser then makes a new connection to and that is the page you see.

--2024-04-11 15:58:52--
Resolving (, 2001:c00:4618:2006::111e, 2001:c00:4618:2006::111d
Connecting to (||:80... connected.
HTTP request sent, awaiting response... 302 Moved Temporarily
Location: [following]

In other words a https connection through port 443 is required to read that site.

Well, no luck yet... I decided to try the other option I mentioned first as it looks like that should be possible with just uci commands.
I added a second uhttpd section, that should provide the actual redirects.
And, I created an IPSet 'localDest' with the local subnets as destination subnets.
Then I created a rule that redirects TCP port 80 packets to the second uhttpd section, where the match is '!localDest'.
(And I disabled the current rule that blocks outgoing traffic.)

It partially works, local http traffic still works, but the redirect for non local doesn't work.
The problem I encounter, is that the second uhttpd instance refuses to allow connections.
From a device on the lan, I can't telnet to,, and even (the last one obviously isn't accessible from anywhere other than the device itself.)
To be continued (next week.)