How to setup Proton VPN with uci

Hi,

I have trouble setting up Proton VPN with uci.

I am running OpenWrt 24.10.0 x86/64 on a VM. Its ip is 10.0.0.3/16

I start from a very simple setup and it works:

  • LAN interface -> the bridge device "br-lan"
  • WAN interface -> VLAN (802.1q) device connecting to my ONT

So, everything works fine I connect directly through my ISP

Then, I am trying to setup Proton VPN (wireguard) using UCI (because I want to fully understand what I am doing and then script it)

I followed this guide https://knowleaks.org/blog/protonvpn-wireguard-openwrt/
and so executed the following commands:

#setup-firewall:
  uci rename firewall.@zone[0]="lan"
  uci rename firewall.@zone[1]="wan"
  uci del_list firewall.wan.network="proton"
  uci add_list firewall.wan.network="proton"
  uci commit firewall
  /etc/init.d/firewall restart

#setup-network:
  #uci -q delete network.proton
  uci set network.proton="interface"
  uci set network.proton.proto="wireguard"
  uci set network.proton.private_key="(redacted)"
  uci add_list network.proton.addresses="10.2.0.2/32"

#add-vpn-peers:
  #uci -q delete network.wgserver
  uci set network.wgserver="proton"
  uci set network.wgserver.public_key="(redacted)"
  uci set network.wgserver.endpoint_host="149.(redacted)"
  uci set network.wgserver.endpoint_port="51820"
  uci set network.wgserver.route_allowed_ips="1"
  uci set network.wgserver.persistent_keepalive="25"
  uci add_list network.wgserver.allowed_ips="0.0.0.0/0"
  uci add_list network.wgserver.allowed_ips="::/0"
  uci commit network
  /etc/init.d/network restart

#enable:
  uci set network.proton.auto='1'
  uci commit network
  /etc/init.d/network restart

So I end up with the following config:

> uci show network | sort
network.@device[0].name='br-lan'
network.@device[0].ports='eth0'
network.@device[0].type='bridge'
network.@device[0]=device
network.@device[1].ifname='eth1'
network.@device[1].macaddr='(redacted)'
network.@device[1].name='eth1.12'
network.@device[1].type='8021q'
network.@device[1].vid='12'
network.@device[1]=device
network.@rule[0].disabled='1'
network.@rule[0]=rule
network.globals.packet_steering='1'
network.globals.ula_prefix='(redacted)'
network.globals=globals
network.lan.device='br-lan'
network.lan.ip6assign='60'
network.lan.ipaddr='10.0.0.3'
network.lan.netmask='255.255.0.0'
network.lan.proto='static'
network.lan=interface
network.loopback.device='lo'
network.loopback.ipaddr='127.0.0.1'
network.loopback.netmask='255.0.0.0'
network.loopback.proto='static'
network.loopback=interface
network.proton.addresses='10.2.0.2/32'
network.proton.auto='1'
network.proton.private_key='(redacted)'
network.proton.proto='wireguard'
network.proton=interface
network.wan.device='eth1.12'
network.wan.proto='dhcp'
network.wan=interface
network.wgserver.allowed_ips='0.0.0.0/0' '::/0'
network.wgserver.endpoint_host='149.(redacted)'
network.wgserver.endpoint_port='51820'
network.wgserver.persistent_keepalive='25'
network.wgserver.public_key='(redacted)'
network.wgserver.route_allowed_ips='1'
network.wgserver=proton

From what I understand those two line are important to force routing through the vpn:

network.wgserver.allowed_ips='0.0.0.0/0' '::/0'
network.wgserver.route_allowed_ips='1'
> uci show firewall | sort
firewall.@defaults[0].forward='REJECT'
firewall.@defaults[0].input='ACCEPT'
firewall.@defaults[0].output='ACCEPT'
firewall.@defaults[0].synflood_protect='1'
firewall.@defaults[0]=defaults
firewall.@forwarding[0].dest='wan'
firewall.@forwarding[0].src='lan'
firewall.@forwarding[0]=forwarding
firewall.@rule[0].dest_port='68'
firewall.@rule[0].family='ipv4'
firewall.@rule[0].name='Allow-DHCP-Renew'
firewall.@rule[0].proto='udp'
firewall.@rule[0].src='wan'
firewall.@rule[0].target='ACCEPT'
firewall.@rule[0]=rule
firewall.@rule[1].family='ipv4'
firewall.@rule[1].icmp_type='echo-request'
firewall.@rule[1].name='Allow-Ping'
firewall.@rule[1].proto='icmp'
firewall.@rule[1].src='wan'
firewall.@rule[1].target='ACCEPT'
firewall.@rule[1]=rule
firewall.@rule[2].family='ipv4'
firewall.@rule[2].name='Allow-IGMP'
firewall.@rule[2].proto='igmp'
firewall.@rule[2].src='wan'
firewall.@rule[2].target='ACCEPT'
firewall.@rule[2]=rule
firewall.@rule[3].dest_port='546'
firewall.@rule[3].family='ipv6'
firewall.@rule[3].name='Allow-DHCPv6'
firewall.@rule[3].proto='udp'
firewall.@rule[3].src='wan'
firewall.@rule[3].target='ACCEPT'
firewall.@rule[3]=rule
firewall.@rule[4].family='ipv6'
firewall.@rule[4].icmp_type='130/0' '131/0' '132/0' '143/0'
firewall.@rule[4].name='Allow-MLD'
firewall.@rule[4].proto='icmp'
firewall.@rule[4].src='wan'
firewall.@rule[4].src_ip='fe80::/10'
firewall.@rule[4].target='ACCEPT'
firewall.@rule[4]=rule
firewall.@rule[5].family='ipv6'
firewall.@rule[5].icmp_type='echo-request' 'echo-reply' 'destination-unreachable' 'packet-too-big' 'time-exceeded' 'bad-header' 'unknown-header-type' 'router-solicitation' 'neighbour-solicitation' 'router-advertisement' 'neighbour-advertisement'
firewall.@rule[5].limit='1000/sec'
firewall.@rule[5].name='Allow-ICMPv6-Input'
firewall.@rule[5].proto='icmp'
firewall.@rule[5].src='wan'
firewall.@rule[5].target='ACCEPT'
firewall.@rule[5]=rule
firewall.@rule[6].dest='*'
firewall.@rule[6].family='ipv6'
firewall.@rule[6].icmp_type='echo-request' 'echo-reply' 'destination-unreachable' 'packet-too-big' 'time-exceeded' 'bad-header' 'unknown-header-type'
firewall.@rule[6].limit='1000/sec'
firewall.@rule[6].name='Allow-ICMPv6-Forward'
firewall.@rule[6].proto='icmp'
firewall.@rule[6].src='wan'
firewall.@rule[6].target='ACCEPT'
firewall.@rule[6]=rule
firewall.@rule[7].dest='lan'
firewall.@rule[7].name='Allow-IPSec-ESP'
firewall.@rule[7].proto='esp'
firewall.@rule[7].src='wan'
firewall.@rule[7].target='ACCEPT'
firewall.@rule[7]=rule
firewall.@rule[8].dest='lan'
firewall.@rule[8].dest_port='500'
firewall.@rule[8].name='Allow-ISAKMP'
firewall.@rule[8].proto='udp'
firewall.@rule[8].src='wan'
firewall.@rule[8].target='ACCEPT'
firewall.@rule[8]=rule
firewall.lan.forward='ACCEPT'
firewall.lan.input='ACCEPT'
firewall.lan.name='lan'
firewall.lan.network='lan'
firewall.lan.output='ACCEPT'
firewall.lan=zone
firewall.wan.forward='REJECT'
firewall.wan.input='DROP'
firewall.wan.masq='1'
firewall.wan.mtu_fix='1'
firewall.wan.name='wan'
firewall.wan.network='wan' 'wan6' 'proton'
firewall.wan.output='ACCEPT'
firewall.wan=zone

If you prefer the files in /etc/config/

cat /etc/config/network

config interface 'loopback'
	option device 'lo'
	option proto 'static'
	option ipaddr '127.0.0.1'
	option netmask '255.0.0.0'

config globals 'globals'
	option ula_prefix '(redacted)'
	option packet_steering '1'

config device
	option name 'br-lan'
	option type 'bridge'
	list ports 'eth0'

config interface 'lan'
	option device 'br-lan'
	option proto 'static'
	option ipaddr '10.0.0.3'
	option netmask '255.255.0.0'
	option ip6assign '60'

config device
	option type '8021q'
	option ifname 'eth1'
	option vid '12'
	option name 'eth1.12'
	option macaddr '(redacted)'

config interface 'wan'
	option proto 'dhcp'
	option device 'eth1.12'

config rule
	option disabled '1'

config interface 'proton'
	option proto 'wireguard'
	option private_key '(redacted)'
	list addresses '10.2.0.2/32'
	option auto '1'

config proton 'wgserver'
	option public_key '(redacted)'
	option endpoint_host '149.(redacted)'
	option endpoint_port '51820'
	option route_allowed_ips '1'
	option persistent_keepalive '25'
	list allowed_ips '0.0.0.0/0'
	list allowed_ips '::/0'
cat /etc/config/firewall

config defaults
	option input 'ACCEPT'
	option output 'ACCEPT'
	option forward 'REJECT'
	option synflood_protect '1'

config zone 'lan'
	option name 'lan'
	list network 'lan'
	option input 'ACCEPT'
	option output 'ACCEPT'
	option forward 'ACCEPT'

config zone 'wan'
	option name 'wan'
	list network 'wan'
	list network 'wan6'
	list network 'proton'
	option input 'DROP'
	option output 'ACCEPT'
	option forward 'REJECT'
	option masq '1'
	option mtu_fix '1'

config forwarding
	option src 'lan'
	option dest 'wan'

config rule
	option name 'Allow-DHCP-Renew'
	option src 'wan'
	option proto 'udp'
	option dest_port '68'
	option target 'ACCEPT'
	option family 'ipv4'

config rule
	option name 'Allow-Ping'
	option src 'wan'
	option proto 'icmp'
	option icmp_type 'echo-request'
	option family 'ipv4'
	option target 'ACCEPT'

config rule
	option name 'Allow-IGMP'
	option src 'wan'
	option proto 'igmp'
	option family 'ipv4'
	option target 'ACCEPT'

config rule
	option name 'Allow-DHCPv6'
	option src 'wan'
	option proto 'udp'
	option dest_port '546'
	option family 'ipv6'
	option target 'ACCEPT'

config rule
	option name 'Allow-MLD'
	option src 'wan'
	option proto 'icmp'
	option src_ip 'fe80::/10'
	list icmp_type '130/0'
	list icmp_type '131/0'
	list icmp_type '132/0'
	list icmp_type '143/0'
	option family 'ipv6'
	option target 'ACCEPT'

config rule
	option name 'Allow-ICMPv6-Input'
	option src 'wan'
	option proto 'icmp'
	list icmp_type 'echo-request'
	list icmp_type 'echo-reply'
	list icmp_type 'destination-unreachable'
	list icmp_type 'packet-too-big'
	list icmp_type 'time-exceeded'
	list icmp_type 'bad-header'
	list icmp_type 'unknown-header-type'
	list icmp_type 'router-solicitation'
	list icmp_type 'neighbour-solicitation'
	list icmp_type 'router-advertisement'
	list icmp_type 'neighbour-advertisement'
	option limit '1000/sec'
	option family 'ipv6'
	option target 'ACCEPT'

config rule
	option name 'Allow-ICMPv6-Forward'
	option src 'wan'
	option dest '*'
	option proto 'icmp'
	list icmp_type 'echo-request'
	list icmp_type 'echo-reply'
	list icmp_type 'destination-unreachable'
	list icmp_type 'packet-too-big'
	list icmp_type 'time-exceeded'
	list icmp_type 'bad-header'
	list icmp_type 'unknown-header-type'
	option limit '1000/sec'
	option family 'ipv6'
	option target 'ACCEPT'

config rule
	option name 'Allow-IPSec-ESP'
	option src 'wan'
	option dest 'lan'
	option proto 'esp'
	option target 'ACCEPT'

config rule
	option name 'Allow-ISAKMP'
	option src 'wan'
	option dest 'lan'
	option dest_port '500'
	option proto 'udp'
	option target 'ACCEPT'

PROBLEM:
My internet still work but I still get my ISP public IP when I test.

> ifconfig proton
proton    Link encap:UNSPEC  HWaddr 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00  
          inet addr:10.2.0.2  P-t-P:10.2.0.2  Mask:255.255.255.255
          UP POINTOPOINT RUNNING NOARP  MTU:1420  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000 
          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)
> netstat -r
Kernel IP routing table
Destination     Gateway         Genmask         Flags   MSS Window  irtt Iface
default         dsl-(redacted)  0.0.0.0         UG        0 0          0 eth1.12
10.0.0.0        *               255.255.0.0     U         0 0          0 br-lan
(redacted isp ip)     *               255.255.255.0   U         0 0          0 eth1.12

I looked int the system logs but nothing really pop up, I see

Wed Feb 19 14:47:20 2025 daemon.notice netifd: Interface 'proton' is now up
Wed Feb 19 14:47:20 2025 daemon.notice netifd: Network device 'proton' link is up
Wed Feb 19 14:47:20 2025 user.notice firewall: Reloading firewall due to ifup of proton (proton)

Since this is the first time I am doing this type of config I am a bit out of my depth.
Is the problem that the the proton wireguard connection doesn't work or that my routing is wrong ? (or both?)

Many thanks for your help :pray:

I would use a /24 netmask for the address.

To get things started either reboot or do service network restart

It looks good, my notes how to setup a WireGuard Client:

1 Like

Hi,

Thank you for you help and guide.

I just redid the whole config following your guide and this time noting the uci command in the GUI and it works.

I made a diff of my old config and the new one but I am not exactly sure what was wrong (and yes I restarted the service and rebooted).

I have another question:
Your guide (and others) just advise to add the "proton" interface to the WAN zone of the firewall.
The official proton guide recommend to create a separate firewall zone.

What would be the best from a security point of view?
Let say I use the VPN all the time to access the internet.
But I still have an IP address from my ISP and someone could scan them and test this interface.
So next I would like to explore how to mitigate as much as possible this type of attack, I would guess it is then better to create a separate firewall zone for proton and work on the firewall to lock as much as possible the wan zone?

Once again, thank you :pray:

Security wise there is no difference whether you add the VPN interface to the WAN firewall zone or create a firewall zone of its own.

With one exception, if you want to make a killswitch, basically only forwarding from lan to vpn zone and not from lan to wan zone then you obviously need a separate vpn zone.
In contrast to OpenVPN a killswitch for WireGuard is not really needed as the interface stays up even if there is no connection.
That said if you misconfigure you can have a leak without a killswitch so if all your traffic is going through the VPN and you do not trust yourself and are an object of interest to the government then by all means use a killswitch :slight_smile:

Yes and that is needed as in the end the traffic from the VPN provider will be routed to your router with its ISP IP address.

But traffic from your LAN clients and from your router should show the VPN 's IP address.
You can check from your LAN clients by browsing to ipleak.net or whatismyip.com and on the router by SSH into the router and execute: curl ipinfo.io, provided curl is installed.

2 Likes

Thank you.

Actually since those VPN also offer a lot of malware and bad stuff blocking I will consider the killswitch :grin:

This topic was automatically closed 10 days after the last reply. New replies are no longer allowed.