44Net Connect/Routed Subnet/Fedora RHEL Rocky CentOS: Difference between revisions

From 44Net Wiki
KN6DWI (talk | contribs)
Wrote firewall configuration section
KN6DWI (talk | contribs)
m Changed display title to align with existing routed subnet tutorials
 
(8 intermediate revisions by the same user not shown)
Line 1: Line 1:
{{DISPLAYTITLE:44Net Connect Routed Subnet: Fedora, RHEL, Rocky, or CentOS}}
This guide is for Fedora, Red Hat Enterprise Linux, Rocky, and CentOS Stream devices. For brevity, the rest of this article will just say Fedora.
This guide is for Fedora, Red Hat Enterprise Linux, Rocky, and CentOS Stream devices. For brevity, the rest of this article will just say Fedora.
   
   
Line 23: Line 25:


== Setting Up The Network Interface ==
== Setting Up The Network Interface ==
The recommended way to set up a Linux device as the router for your subnet is with two ethernet interfaces. The second can be provided by a USB ethernet adapter if your router's motherboard doesn't have multiple ports on its NIC or via a PCIe card. This section has the steps that are required regardless of whether you're using ethernet or WiFi. If you're using WiFi, you'll also need the steps in the following section. Otherwise, you can skip them.
=== Step 1: Create a new connection in nmcli ===
<code>nmcli</code> is the CLI interface for NetworkManager, which is the high level network configuration tool included
in Fedora and many other Linux distributions. These configuration steps can be completed using the NetworkManager GUI, but many people operate their devices in "headless" mode (without a screen or keyboard) and use SSH to remotely configure it. Thus, this tutorial uses a CLI tool to accommodate that use case.
An <code>nmcli</code> "connection" is an abstraction representing a network configuration attached to a device. Create a new connection by running
<code>sudo nmcli con add con-name <name> ifname <interface name> type <type></code>.
You can name the connection whatever you like, but it's recommended to name it something descriptive. For example, if you're configuring a 44net routed subnet for <code>eth1</code>, you might name it <code>44net-eth1</code>. The interface name is the name of the interface you're using, as described by <code>ifconfig</code>. The type is either <code>wifi</code> or <code>ethernet</code>. For a WiFi interface, you must also specify the BSSID (network name) by adding the parameter <code>ssid <BSSID></code> at the end.
=== Step 2: Configure the IP ===
Set the IPv4 method to manual using the following command:
<code>sudo nmcli con modify <name> ipv4.method manual</code>
Next, set the IP range for this interface.
<code>sudo nmcli con modify <name> ipv4.address <subnet></code>
Your subnet should be specified in CIDR notation. At this point, if you're configuring an ethernet interface, you're ready to start it up. If you're configuring a WiFi interface, don't start your interface yet, and move on to the next section for additional configuration.
=== Step 3: Starting the Interface ===
First, disable the existing connection, which is likely named <code>netplan-<interface></code>. If you're using <code>eth1</code> for your 44net clients, it may look like <code>netplan-eth1</code>. If you are configuring your Fedora machine over SSH, be careful not to deactivate the connection over which your SSH is traveling.
<code>sudo nmcli con down <name of existing connection></code>
After deactivating the regular connection, activate your new connection. If this succeeds, you're good to go.
<code>sudo nmcli con up <name of new connection></code>
== Setting up DHCP ==
[https://www.isc.org/kea/ Kea] is the recommended DHCP server for setting up a routed subnet. <code>dhcpd</code> is deprecated as of 2022.
Install <code>kea</code> by running
<code>sudo apt install kea</code>.
After installing, configure its settings by editing <code>/etc/kea/kea-dhcp4.conf</code>. This file uses an extended JSON syntax that supports shell style comments using <code>#</code>, C style single line comments with <code>//</code>, and C style multi-line comments with <code>/* */</code>.
=== Configure Interface ===
Inside the <code>Dhcp4</code> struct, under <code>interfaces-config</code>, add the interface you want your DHCP server to operate on to the <code>interfaces</code> list. For example, in a setup using 2 ethernet interfaces, you might have <code>eth0</code> connected to your LAN and <code>eth1</code> connected to your client devices. In this case, you would use <code>eth1</code>.
<nowiki>
"Dhcp4": {
    "interfaces-config": {
        "interfaces": [ "eth1" ]
    }
}
</nowiki>
=== Configure DNS ===
Inside the <code>Dhcp4</code> struct, under <code>option-data</code> set at least one DNS server. Cloudflare's DNS servers are <code>1.1.1.1</code> and <code>1.0.0.1</code>. Google's DNS servers are <code>8.8.8.8</code> and <code>8.8.4.4</code>.
<nowiki>
"Dhcp4": {
    "option-data": [
        {
            "name": "domain-name-servers",
            "data": "1.1.1.1, 1.0.0.1, 8.8.8.8, 8.8.4.4"
        },
    ],
}
</nowiki>
=== Configure your subnet ===
<code>subnet4</code> is a list (denoted with brackets) of structures (denoted with curly brackets) where each structure is one subnet. Inside each subnet structure, set the client IP range(s) in <code>pools</code>, and define at least one router in the <code>option-data</code> field. Comment out or delete the example DHCP reservations in the <code>reservations</code> field, since they're for the wrong subnet.
<nowiki>
"subnet4": [
    // Put your subnet here in CIDR notation.
    "subnet": "44.27.45.128/29",
    // Define the range of client IP addresses here.
    "pools": [ { "pool": "44.27.45.129 - 44.27.45.133" } ],
    // These options are subnet specific. You must configure at least one router.
    "option-data": [
        {
            "name": "routers",
            "data": "44.27.45.129"
        }
    ],
    "reservations": [
        // Comment out or delete the examples in this list, since they are for the wrong subnet.
    ]
]
</nowiki>
=== Ethernet Hot Plugging Workaround ===
At present, <code>kea</code> does not support hot plugging interfaces. This means that ethernet devices must have at least one client at the time the DHCP server starts, otherwise it will not properly bind to the interface. If you plan on hot plugging ethernet devices, this can be worked around by configuring <code>service-sockets-max-retries</code> to an extremely large number such as 9223372036854775807, the upper limit of a signed 64-bit integer. You may also wish to increase <code>service-sockets-retry-wait-time</code>, which specifies the retry time in milliseconds, though the default time of 5000 ms is typically fine. These options should go in the <code>interfaces-config</code> section at the top of your <code>Dhcp4</code> section in <code>/etc/kea/kea-dhcp4.conf</code>. Here is an example:


== Setting up DHCP ==
<nowiki>
=== Configure Interface ===  
"Dhcp4": {
    // Add names of your network interfaces to listen on.
    "interfaces-config": {
        // See section 8.2.4 for more details. You probably want to add just
        // interface name (e.g. "eth0" or specific IPv4 address on that
        // interface name (e.g. "eth0/192.0.2.1").
        "interfaces": ["eth1" ],
 
        // max retries is set to int64 max as a workaround for kea not supporting
        // hot plugging of interfaces.
        "service-sockets-max-retries": 9223372036854775807,
        "service-sockets-retry-wait-time": 2000
    },
 
    // The rest of this config is omitted for brevity.
}</nowiki>
 
=== Enable Kea ===
Enable and start <code>kea</code> by running <code>sudo systemctl enable --now kea-dhcp4-server</code>. Check that the server has started without issue by running <code>systemctl status kea-dhcp4-server</code>.


== Firewall Configuration ==
== Firewall Configuration ==
Fedora comes with <code>firewalld</code> installed and enabled by default. <code>firewalld</code> uses [https://firewalld.org/documentation/zone/ zones] to determine the trust level of a connection. On Fedora, all interfaces start in the <code>FedoraWorkstation</code> zone, which is has a <code>default</code> target. The <code>default</code> target drops all traffic except ICMP packets, so it's recommended to move it to another zone that permits your desired traffic or modify the FedoraWorkstation zone. Additionally, the <code>FedoraWorkstation</code> zone blocks traffic on ports below 1024, with the exception of SSH and Samba. Hosting a web server on either of the traditional ports (80 or 443) will require adding services to the <code>FedoraWorkstation</code> zone, or moving the subnet interface to a zone that permits traffic on those ports.
Fedora comes with <code>firewalld</code> installed and enabled by default. <code>firewalld</code> uses [https://firewalld.org/documentation/zone/ zones] to determine the trust level of a connection. On Fedora, all interfaces start in the <code>FedoraWorkstation</code> zone, which is has a <code>default</code> target. The <code>default</code> target drops all traffic except ICMP packets, so it's recommended to move it to another zone that permits your desired traffic or modify the FedoraWorkstation zone. Additionally, the <code>FedoraWorkstation</code> zone blocks traffic on ports below 1024, with the exception of SSH and Samba. Hosting a web server on either of the traditional ports (80 or 443) will require adding services to the <code>FedoraWorkstation</code> zone, or moving the subnet interface to a zone that permits traffic on those ports.


== Setting Up Routing ==  
See [[Firewalling Basics]] for more information.
 
== Setting up Routing ==
=== Enable IP Forwarding ===
To allow packets to be forwarded between different network interfaces, we must enable IP forwarding in the kernel. On Fedora, this may already be enabled. Check whether it's already enabled by running <code>sysctl net.ipv4.ip_forward</code>. If it's enabled, this will return <code>1</code>.
 
If IP forwarding is not enabled, enable it by adding <code>net.ipv4.ip_forward=1</code> to one of the drop-in files in <code>/etc/sysctl.d/</code>.
If no drop-in files exist, you can create one. The typical naming scheme is a two digit number indicating priority, a dash, and then the name of the file, such as <code>99-44net.conf</code>. A larger number indicates lower priority. It will require superuser privileges. For example:
 
<code>sudo nano /etc/sysctl.d/99-44net</code>
 
Next, reload your system configuration from config files by running <code>sudo sysctl --system</code>. Verify that IP forwarding has been successfully enabled
by running <code>sysctl net.ipv4.ip_forward</code>, which should print <code>net.ipv4.ip_forward = 1</code>. If the number is 0 instead of 1, IP forwarding has not been properly enabled, and you should check your drop-in file for typos.
 
=== Add the routing rule ===
Next, we need to add a routing rule to allow the clients on the routed subnet to exit via the WireGuard tunnel. The setup steps for creating the tunnel should have created the routing table <code>51820</code> where the default route is via the WireGuard interface, whatever you've named it. Verify that it exists by running the command <code>ip route show table 51820</code>. It should have a single line that says something like <code>default dev wg0 scope link</code>. In this case, <code>wg0</code> is the example WireGuard interface name. Yours may be different.
 
Run the command <code>sudo ip rule add from <subnet> table 51820</code>. Replace <code><subnet></code> with your routed subnet in CIDR notation. If you have other rules with desired priority order, set your priority in the above command accordingly. Though it's possible to do the same thing as this rule using <code>ip route</code>, it's much more difficult and is not recommended.
 
Verify that your routing is working correctly by running the following command:
 
<code>ip route get 1.1.1.1 from <address> iif <subnet interface></code>
 
<code><address></code> should be replaced by an address in your subnet, and <code><subnet interface></code> with the interface your routed subnet clients are connected to. This command will attempt to find the route to 1.1.1.1 (Cloudflare's DNS server, an arbitrary test IP) from an IP in the routed subnet. The output should look like this:
 
<code>1.1.1.1 from <address> dev wg0 table 51820</code>
 
If the output indicates that there is no route to host, or that your route does not proceed via the WireGuard interface, you may have an issue with your routing configuration.
 
This routing rule will not persist between reboots. To make it persist, we can add it to the <code>systemd</code> unit created for the tunnel. After the existing <code>ExecStart</code> line, add another that executes the rule we just added. Immediately after that one, before the existing <code>ExecStop</code> line, add an
<code>ExecStop</code> line that deletes the rule. This is done by running <code>ip rule del</code> rather than <code>ip rule add</code>. Your unit should look something like this:
 
<nowiki>
[Unit]
Description=WireGuard single device 44Net Connect tunnel
Requires=network-online.target
 
[Service]
Type=oneshot
RemainAfterExit=true
 
# Edit these lines if your config file is named differently.
ExecStart=wg-quick up /etc/wireguard/wg0.conf
ExecStart=ip rule add from 44.27.45.129/29 lookup 51820
ExecStop=ip rule del from 44.27.45.129/29 lookup 51820
ExecStop=wg-quick down /etc/wireguard/wg0.conf
 
[Install]
WantedBy=multi-user.target</nowiki>


== Troubleshooting ==
== Troubleshooting ==
=== Clients receive DHCP address but can't ping router interface ===
If clients plugged into the router are receiving DHCP addresses, but their traffic isn't being allowed to pass and they can't ping the router's interface, the firewall rules for the subnet interface are likely misconfigured. Even when there are routing rules, clients are typically able to ping the router's ethernet interface. Not being able to ping it may indicate that firewall rules are dropping the traffic to that interface. If you're testing client connectivity by having the client create an outbound connection, ensure the subnet interface is in a <code>firewalld</code> zone that will permit outgoing connections to the relevant recipient.
=== No route to outside hosts, but can ping router interface ===
If clients can ping the router interface, but attempting to ping any other devices shows "no route to host," the routing rules are likely misconfigured. In this circumstance, it's a useful troubleshooting step to ping the WireGuard interface, since this is the next hop from the subnet interface. The route between these is the one that's manually set up using <code>ip rule</code> in the tutorial.
If you're experiencing issues with routing, ensure all necessary rules are present, and check for duplicate rules. Duplicate rules often have the effect of dropping traffic rather than routing through one of the two copies of the rule.

Latest revision as of 16:55, 21 July 2026


This guide is for Fedora, Red Hat Enterprise Linux, Rocky, and CentOS Stream devices. For brevity, the rest of this article will just say Fedora.

Prerequisites

Set up a single-device tunnel to your Fedora device. Note the IP and name of your WireGuard interface. The name of your WireGuard interface is the same as the name of your config file. For example, if your config file is /etc/wireguard/wg0.conf, then your interface name is wg0. The IP of your WireGuard interface can be obtained from running ifconfig <interface> and finding the IP listed under the interface in the inet field.

Below is some example output of ifconfig wg0.

wg0: flags=209<UP,POINTOPOINT,RUNNING,NOARP>  mtu 1380
    inet 44.27.133.190  netmask 255.255.255.255  destination 44.27.133.190
    inet6 fe80::f728:a0b0:3af5:b5c6  prefixlen 128  scopeid 0x20<link>
    unspec 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00  txqueuelen 1000  (UNSPEC)
    RX packets 17331  bytes 5865364 (5.5 MiB)
    RX errors 0  dropped 0  overruns 0  frame 0
    TX packets 13389  bytes 2146828 (2.0 MiB)
    TX errors 0  dropped 1 overruns 0  carrier 0  collisions 0

Request a Subnet

Go to the Network tab of 44Net Connect, and request a network. Requests up to a /28 (16 IPs) are automatically approved. It's recommended to request at least a /29 (8 IPs), since at least 3 of your IPs must be set aside for network address, broadcast address, and the address of the subnet's interface on your router. That way, you have at least 6 usable addresses for your hosts.

Setting Up The Network Interface

The recommended way to set up a Linux device as the router for your subnet is with two ethernet interfaces. The second can be provided by a USB ethernet adapter if your router's motherboard doesn't have multiple ports on its NIC or via a PCIe card. This section has the steps that are required regardless of whether you're using ethernet or WiFi. If you're using WiFi, you'll also need the steps in the following section. Otherwise, you can skip them.

Step 1: Create a new connection in nmcli

nmcli is the CLI interface for NetworkManager, which is the high level network configuration tool included in Fedora and many other Linux distributions. These configuration steps can be completed using the NetworkManager GUI, but many people operate their devices in "headless" mode (without a screen or keyboard) and use SSH to remotely configure it. Thus, this tutorial uses a CLI tool to accommodate that use case. An nmcli "connection" is an abstraction representing a network configuration attached to a device. Create a new connection by running

sudo nmcli con add con-name <name> ifname <interface name> type <type>.

You can name the connection whatever you like, but it's recommended to name it something descriptive. For example, if you're configuring a 44net routed subnet for eth1, you might name it 44net-eth1. The interface name is the name of the interface you're using, as described by ifconfig. The type is either wifi or ethernet. For a WiFi interface, you must also specify the BSSID (network name) by adding the parameter ssid <BSSID> at the end.

Step 2: Configure the IP

Set the IPv4 method to manual using the following command:

sudo nmcli con modify <name> ipv4.method manual

Next, set the IP range for this interface.

sudo nmcli con modify <name> ipv4.address <subnet>

Your subnet should be specified in CIDR notation. At this point, if you're configuring an ethernet interface, you're ready to start it up. If you're configuring a WiFi interface, don't start your interface yet, and move on to the next section for additional configuration.

Step 3: Starting the Interface

First, disable the existing connection, which is likely named netplan-<interface>. If you're using eth1 for your 44net clients, it may look like netplan-eth1. If you are configuring your Fedora machine over SSH, be careful not to deactivate the connection over which your SSH is traveling.

sudo nmcli con down <name of existing connection>

After deactivating the regular connection, activate your new connection. If this succeeds, you're good to go.

sudo nmcli con up <name of new connection>

Setting up DHCP

Kea is the recommended DHCP server for setting up a routed subnet. dhcpd is deprecated as of 2022.

Install kea by running

sudo apt install kea.

After installing, configure its settings by editing /etc/kea/kea-dhcp4.conf. This file uses an extended JSON syntax that supports shell style comments using #, C style single line comments with //, and C style multi-line comments with /* */.

Configure Interface

Inside the Dhcp4 struct, under interfaces-config, add the interface you want your DHCP server to operate on to the interfaces list. For example, in a setup using 2 ethernet interfaces, you might have eth0 connected to your LAN and eth1 connected to your client devices. In this case, you would use eth1.

"Dhcp4": {
    "interfaces-config": {
        "interfaces": [ "eth1" ]
    }
}

Configure DNS

Inside the Dhcp4 struct, under option-data set at least one DNS server. Cloudflare's DNS servers are 1.1.1.1 and 1.0.0.1. Google's DNS servers are 8.8.8.8 and 8.8.4.4.

"Dhcp4": {
    "option-data": [
        {
            "name": "domain-name-servers",
            "data": "1.1.1.1, 1.0.0.1, 8.8.8.8, 8.8.4.4"
        },
    ],
}

Configure your subnet

subnet4 is a list (denoted with brackets) of structures (denoted with curly brackets) where each structure is one subnet. Inside each subnet structure, set the client IP range(s) in pools, and define at least one router in the option-data field. Comment out or delete the example DHCP reservations in the reservations field, since they're for the wrong subnet.

"subnet4": [
    // Put your subnet here in CIDR notation.
    "subnet": "44.27.45.128/29",

    // Define the range of client IP addresses here.
    "pools": [ { "pool": "44.27.45.129 - 44.27.45.133" } ],

    // These options are subnet specific. You must configure at least one router.
    "option-data": [
        {
            "name": "routers",
            "data": "44.27.45.129"
        }
    ],
    "reservations": [
        // Comment out or delete the examples in this list, since they are for the wrong subnet.
    ]
]

Ethernet Hot Plugging Workaround

At present, kea does not support hot plugging interfaces. This means that ethernet devices must have at least one client at the time the DHCP server starts, otherwise it will not properly bind to the interface. If you plan on hot plugging ethernet devices, this can be worked around by configuring service-sockets-max-retries to an extremely large number such as 9223372036854775807, the upper limit of a signed 64-bit integer. You may also wish to increase service-sockets-retry-wait-time, which specifies the retry time in milliseconds, though the default time of 5000 ms is typically fine. These options should go in the interfaces-config section at the top of your Dhcp4 section in /etc/kea/kea-dhcp4.conf. Here is an example:

"Dhcp4": {
    // Add names of your network interfaces to listen on.
    "interfaces-config": {
        // See section 8.2.4 for more details. You probably want to add just
        // interface name (e.g. "eth0" or specific IPv4 address on that
        // interface name (e.g. "eth0/192.0.2.1").
        "interfaces": ["eth1" ],

        // max retries is set to int64 max as a workaround for kea not supporting
        // hot plugging of interfaces.
        "service-sockets-max-retries": 9223372036854775807,
        "service-sockets-retry-wait-time": 2000
    },

    // The rest of this config is omitted for brevity.
}

Enable Kea

Enable and start kea by running sudo systemctl enable --now kea-dhcp4-server. Check that the server has started without issue by running systemctl status kea-dhcp4-server.

Firewall Configuration

Fedora comes with firewalld installed and enabled by default. firewalld uses zones to determine the trust level of a connection. On Fedora, all interfaces start in the FedoraWorkstation zone, which is has a default target. The default target drops all traffic except ICMP packets, so it's recommended to move it to another zone that permits your desired traffic or modify the FedoraWorkstation zone. Additionally, the FedoraWorkstation zone blocks traffic on ports below 1024, with the exception of SSH and Samba. Hosting a web server on either of the traditional ports (80 or 443) will require adding services to the FedoraWorkstation zone, or moving the subnet interface to a zone that permits traffic on those ports.

See Firewalling Basics for more information.

Setting up Routing

Enable IP Forwarding

To allow packets to be forwarded between different network interfaces, we must enable IP forwarding in the kernel. On Fedora, this may already be enabled. Check whether it's already enabled by running sysctl net.ipv4.ip_forward. If it's enabled, this will return 1.

If IP forwarding is not enabled, enable it by adding net.ipv4.ip_forward=1 to one of the drop-in files in /etc/sysctl.d/. If no drop-in files exist, you can create one. The typical naming scheme is a two digit number indicating priority, a dash, and then the name of the file, such as 99-44net.conf. A larger number indicates lower priority. It will require superuser privileges. For example:

sudo nano /etc/sysctl.d/99-44net

Next, reload your system configuration from config files by running sudo sysctl --system. Verify that IP forwarding has been successfully enabled by running sysctl net.ipv4.ip_forward, which should print net.ipv4.ip_forward = 1. If the number is 0 instead of 1, IP forwarding has not been properly enabled, and you should check your drop-in file for typos.

Add the routing rule

Next, we need to add a routing rule to allow the clients on the routed subnet to exit via the WireGuard tunnel. The setup steps for creating the tunnel should have created the routing table 51820 where the default route is via the WireGuard interface, whatever you've named it. Verify that it exists by running the command ip route show table 51820. It should have a single line that says something like default dev wg0 scope link. In this case, wg0 is the example WireGuard interface name. Yours may be different.

Run the command sudo ip rule add from <subnet> table 51820. Replace <subnet> with your routed subnet in CIDR notation. If you have other rules with desired priority order, set your priority in the above command accordingly. Though it's possible to do the same thing as this rule using ip route, it's much more difficult and is not recommended.

Verify that your routing is working correctly by running the following command:

ip route get 1.1.1.1 from <address> iif <subnet interface>

<address> should be replaced by an address in your subnet, and <subnet interface> with the interface your routed subnet clients are connected to. This command will attempt to find the route to 1.1.1.1 (Cloudflare's DNS server, an arbitrary test IP) from an IP in the routed subnet. The output should look like this:

1.1.1.1 from <address> dev wg0 table 51820

If the output indicates that there is no route to host, or that your route does not proceed via the WireGuard interface, you may have an issue with your routing configuration.

This routing rule will not persist between reboots. To make it persist, we can add it to the systemd unit created for the tunnel. After the existing ExecStart line, add another that executes the rule we just added. Immediately after that one, before the existing ExecStop line, add an ExecStop line that deletes the rule. This is done by running ip rule del rather than ip rule add. Your unit should look something like this:

[Unit]
Description=WireGuard single device 44Net Connect tunnel
Requires=network-online.target

[Service]
Type=oneshot
RemainAfterExit=true

# Edit these lines if your config file is named differently.
ExecStart=wg-quick up /etc/wireguard/wg0.conf
ExecStart=ip rule add from 44.27.45.129/29 lookup 51820
ExecStop=ip rule del from 44.27.45.129/29 lookup 51820
ExecStop=wg-quick down /etc/wireguard/wg0.conf

[Install]
WantedBy=multi-user.target

Troubleshooting

Clients receive DHCP address but can't ping router interface

If clients plugged into the router are receiving DHCP addresses, but their traffic isn't being allowed to pass and they can't ping the router's interface, the firewall rules for the subnet interface are likely misconfigured. Even when there are routing rules, clients are typically able to ping the router's ethernet interface. Not being able to ping it may indicate that firewall rules are dropping the traffic to that interface. If you're testing client connectivity by having the client create an outbound connection, ensure the subnet interface is in a firewalld zone that will permit outgoing connections to the relevant recipient.

No route to outside hosts, but can ping router interface

If clients can ping the router interface, but attempting to ping any other devices shows "no route to host," the routing rules are likely misconfigured. In this circumstance, it's a useful troubleshooting step to ping the WireGuard interface, since this is the next hop from the subnet interface. The route between these is the one that's manually set up using ip rule in the tutorial.

If you're experiencing issues with routing, ensure all necessary rules are present, and check for duplicate rules. Duplicate rules often have the effect of dropping traffic rather than routing through one of the two copies of the rule.