This document details the design and implementation of a solution for routing traffic from a specific internal network (blue0) through a commercial WireGuard VPN provider (e.g., NordVPN), while ensuring all other traffic uses the standard WAN connection. This solution was developed for the IPFire firewall distribution, specifically on a system where the wg-quick utility is unavailable.
The solution is provided as a single, standalone control script that manages the VPN connection, routing policies, and firewall rules required for this selective routing scenario.
Primary Goals:
- Traffic from the Blue Zone (
192.168.2.0/24) must exit to the internet via the VPN tunnel. - Traffic from the Green Zone (
192.168.1.0/24) and the firewall itself must use the primary WAN connection. - Local services on the firewall (DNS, DHCP) must remain accessible to all internal clients.
IPFire's WebUI provides distinct configurations for "Roadwarrior" (a single client connecting in) and "Net-to-Net" (connecting two networks) setups. Our analysis focuses on the conflict that arises when a commercial VPN profile—which is functionally a roadwarrior profile with a peer AllowedIPs of 0.0.0.0/0—is used within IPFire's net-to-net logic. This specific mismatch triggers several problematic behaviors.
When a net-to-net tunnel is created with a commercial VPN profile, IPFire's backend scripts interpret the 0.0.0.0/0 peer as "the entire internet." Consequently, they modify the main routing table by inserting broad routes (0.0.0.0/1, 128.0.0.0/1) that force all traffic from all zones into the WireGuard tunnel. This all-or-nothing approach prevents selective routing and breaks local services.
IPFire's main FORWARD firewall chain is a complex sequence of jumps to other chains. We discovered that NEW packets from our blue0 zone destined for the wg9 interface were being dropped by the final DROP rule in the POLICYFWD chain because there was no explicit ACCEPT rule for this non-standard traffic flow.
The WGBLOCK chain is designed to filter traffic coming from a WireGuard peer (-i wg+), not traffic going out to one. Attempting to place an outbound ACCEPT rule here is ineffective, as the traffic is never sent to this chain.
The correct way to integrate custom rules is via IPFire's custom hooks. By using the CUSTOMFORWARD and CUSTOMPOSTROUTING chains, our rules are processed early and are safe from being overwritten by system updates.
To overcome these issues, we avoid IPFire's net-to-net logic entirely and use a more precise Policy-Based Routing strategy, orchestrated by a manual control script.
This approach leaves the main routing table untouched. Instead, a single ip rule identifies traffic from the Blue Zone (192.168.2.0/24) and directs it to a custom routing table (blue-vpn). This table provides a complete routing environment for VPN clients, containing:
- Routes for all local networks (Green, Blue) to ensure local traffic is handled correctly.
- A new default route that sends all other traffic through the
wg9WireGuard interface.
Firewall integration is handled cleanly using the CUSTOMFORWARD and CUSTOMPOSTROUTING hooks for our ACCEPT and MASQUERADE rules, respectively.
The entire process is managed by a self-contained script that accepts start, stop, and show commands. As wg-quick is unavailable on IPFire, the script uses the native wg command to configure the tunnel. This approach requires a minor modification to the commercial VPN profile, which is detailed in the configuration steps below.
-
do_start(): Performs the setup sequence in the correct order:- Creates the
wg9virtual interface and assigns its IP address. - Applies the cryptographic keys from the
.conffile usingwg setconf. - Brings the interface up.
- Builds the
blue-vpnrouting table with both local and default routes. - Inserts the necessary
MASQUERADEandACCEPTrules into theCUSTOMPOSTROUTINGandCUSTOMFORWARDchains. - Activates the policy by adding the
ip ruleafter all other components are in place.
- Creates the
-
do_stop(): Tears down the configuration in the reverse order, ensuring the system is returned to its original state. It removes the policy rule, flushes the routes and firewall rules, and finally deletes the WireGuard interface. -
do_show(): Provides a comprehensive diagnostic overview of the routing table, policy rules, firewall chains, and WireGuard interface status, making it easy to verify and troubleshoot the configuration.
You must have a valid WireGuard configuration file from your VPN provider. This file should contain your [Peer] information, including their PublicKey and Endpoint.
- Save the control script on your IPFire machine as
/root/nordvpn.sh. - Save your provider's WireGuard configuration file in the same location (e.g.,
/root/your_wireguard.conf).
-
Edit the Control Script (
/root/nordvpn.sh):- Verify that the network variables (
BLUE_NETWORK,GREEN_NETWORK, etc.) match your environment. - Update
WG_LOCAL_IPwith the localAddressfrom your provider's config. - Update
WG_CONFto point to your WireGuard configuration file.
- Verify that the network variables (
-
Edit the WireGuard Config File:
- In the
[Interface]section, remove theAddressandDNSentries, leaving only yourPrivateKey.
- In the
- To START the tunnel and apply all rules:
/root/nordvpn.sh start
- To STOP the tunnel and cleanly remove all rules:
/root/nordvpn.sh stop
- To SHOW the current status of the configuration:
/root/nordvpn.sh show