# Common issues and Debugging

## 1. VXLAN Setup Check List

It is crucial to ensure that you can directly connect to the services or games you are hosting using their IPv4 address and port. For instance, in this setup documentation, the [Ragnarok server](https://docs.tcpshield.com/sentry-tunnel-for-rathena-ragnarok#docs-internal-guid-01454216-7fff-023d-1756-215a6f207bb2) was accessible via `108.61.149.182:6900`. If your VXLAN tunnel is not functioning correctly, several potential causes may exist. Below are some best practices to follow to confirm that your service is properly set up and running.

### 1.1. Verifying tunnel creation

After running the setup script, you can run the following commands to check your tunnel configuration:

<pre><code><strong>ip -s link show vxlan_&#x3C;ID>
</strong></code></pre>

Example output:

```
root@admin:~# ip -s link show vxlan_47
418: vxlan_47: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000
    link/ether 12:cc:cb:ab:1f:e8 brd ff:ff:ff:ff:ff:ff
    RX: bytes  packets  errors  dropped missed  mcast   
    543784518  3037392  0       0       0       0       
    TX: bytes  packets  errors  dropped carrier collsns 
    154324621  1408584  0       0       0       0       
```

You should see 0 under the errors and dropped columns. Any other numbers would indicate packets being dropped (possibly from a firewall).

### 1.2. Interface traffic

To verify that your VXLAN tunnel has been properly established, you can ping the **`Private IP Address`** of your tunnel. You should see responses like the example below:

```
root@admin:~# ping 172.18.128.13
PING 172.18.128.13 (172.18.128.13) 56(84) bytes of data.
64 bytes from 172.18.128.13: icmp_seq=1 ttl=64 time=49.4 ms
64 bytes from 172.18.128.13: icmp_seq=2 ttl=64 time=49.4 ms
64 bytes from 172.18.128.13: icmp_seq=3 ttl=64 time=49.7 ms
64 bytes from 172.18.128.13: icmp_seq=4 ttl=64 time=49.4 ms
^C
--- 172.18.128.13 ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3005ms
rtt min/avg/max/mdev = 49.362/49.458/49.722/0.152 ms
```

The local IP address here corresponds to the VXLAN interface running on our anycast server, so the latency you observe will vary depending on your backend’s location. For further debugging, run:

```
arping -I vxlan_<ID> <private IP address>
```

as it can confirm whether the virtual link is properly resolving IP-to-MAC, something `ping` won't be able to show:

```
root@admin:~# arping -I vxlan_47 172.18.128.13
ARPING 172.18.128.13
42 bytes from 02:ab:cd:34:56:78 (172.18.128.13): index=0 time=44.839 msec
42 bytes from 02:ab:cd:34:56:78 (172.18.128.13): index=1 time=44.860 msec
42 bytes from 02:ab:cd:34:56:78 (172.18.128.13): index=2 time=44.852 msec
42 bytes from 02:ab:cd:34:56:78 (172.18.128.13): index=3 time=44.826 msec
42 bytes from 02:ab:cd:34:56:78 (172.18.128.13): index=4 time=44.827 msec
42 bytes from 02:ab:cd:34:56:78 (172.18.128.13): index=5 time=45.180 msec
42 bytes from 02:ab:cd:34:56:78 (172.18.128.13): index=6 time=45.047 msec
^C
--- 172.18.128.13 statistics ---
7 packets transmitted, 7 packets received,   0% unanswered (0 extra)
rtt min/avg/max/std-dev = 44.826/44.919/45.180/0.129 ms
```

In this example, the private interface IP resolves to a MAC address within the tunnel, which is `02:ab:cd:34:56:78`

As for your tunnel's `Public IP Address` , the reply should looks something like this (with <1ms latency):

```
root@admin:~# ping 104.234.6.128
PING 104.234.6.128 (104.234.6.128) 56(84) bytes of data.
64 bytes from 104.234.6.128: icmp_seq=1 ttl=64 time=0.033 ms
64 bytes from 104.234.6.128: icmp_seq=2 ttl=64 time=0.046 ms
64 bytes from 104.234.6.128: icmp_seq=3 ttl=64 time=0.060 ms
64 bytes from 104.234.6.128: icmp_seq=4 ttl=64 time=0.061 ms
```

You can also check the output of:

```
ip route
```

```
root@admin:~# ip route
...
172.18.128.0/24 dev vxlan_47 proto kernel scope link src 172.18.128.13 
192.168.0.0/24 dev eth0 proto kernel scope link src 192.168.0.89 
...
```

If the tunnel was properly created, you will see your private IP address in the output.

### 1.3 Firewall Configuration

There are two potential scenarios:

1. **Cloud Provider Firewall**: Major cloud providers like Linode, AWS, and Azure have default security group or firewall settings that may block traffic before it even reaches your VPS. In this case, you can navigate to your provider's control panel and allow traffic from [TCPShield](https://tcpshield.com/v4) to your backend ports.
2. **Server Firewall**: If you are using a server firewall such as `netfilter`, `iptables`, or `ufw`, you will need to open both the backend port and the VXLAN port to accept external connections, or, in rare cases, explicitly whitelist the VXLAN interfaces.

Using `iptables` to Accept Connections to Your Backend Port

```
iptables -I INPUT -p udp --dport <PORT> -j ACCEPT
iptables -I INPUT -p tcp --dport <PORT> -j ACCEPT
iptables -I OUTPUT -p tcp --sport <PORT> -j ACCEPT
iptables -I OUTPUT -p udp --sport <PORT> -j ACCEPT
```

{% hint style="warning" %}
Notes: To remove these rules, simply replace `-A` with `-D` to delete them.
{% endhint %}

Using `UFW` :&#x20;

<pre><code><strong>ufw allow &#x3C;port>/udp
</strong>ufw allow &#x3C;port>/tcp
</code></pre>

{% hint style="warning" %}
To delete these rules, use the following command:

`sudo ufw delete allow /udp`\
`sudo ufw delete allow /tcp`
{% endhint %}

**Whitelisting VXLAN Interface (Optional)**

Although this step is typically *not necessary*, you can whitelist the VXLAN interface explicitly using `iptables`:

```
iptables -I FORWARD -i vxlan_<ID> -j ACCEPT
iptables -I FORWARD -o vxlan_<ID> -j ACCEPT
```

Using `UFW`:

```
sudo ufw route allow in on vxlan_<ID> to any
sudo ufw route allow out on vxlan_<ID> to any
```

## 2. Error: Nexthop has invalid gateway (Pterodactyl / Wings).

If you're running **Pterodactyl** (or other Docker-based services), you might encounter the error:

> **Nexthop has invalid gateway**

This usually happens when the **VXLAN tunnel attempts to bind to an IP address** that is already reserved by Docker. For example, Pterodactyl’s default bridge network (`pterodactyl0`) may overlap with the subnet used by VXLAN (`172.18.0.0/16`), causing the tunnel setup to fail.

To debug:

1. **Check the Local IP Address for VXLAN**: It should resemble something like `172.18.132.2`.
2. Run `ip route` and you may see an entry like:

```
172.18.0.0/16 dev pterodactyl0 proto kernel scope link src 172.18.0.1 
```

In this case, the `172.18.132.2` IP address might conflict with the Docker network configurations. For example, if the `pterodactyl0` interface is using `172.18.0.1`, this could block the gateway you are trying to use (`172.18.132.2`), as it lies within the Docker subnet.&#x20;

#### **✅ SOLUTION: Switch Pterodactyl to use host networking**

To prevent Docker from reserving IPs that interfere with your VXLAN setup:

1. **Edit Pterodactyl config**\
   Open `/etc/pterodactyl/config.yml` and modify the Docker networking section:

   ```
   docker:
     network:
       name: host
       network_mode: host
   ```
2. **Restart the network stack and Wings daemon**<br>

   ```
   systemctl stop wings
   docker stop $(docker ps -q)
   docker network rm pterodactyl_nw
   systemctl start wings
   ```

This change puts all containers on the **host network**, removing the isolated Docker bridge and preventing subnet conflicts. Your VXLAN tunnel should now initialize without errors.

3. **Forcing outbound traffic to use the right path**

We need to check which block Pterodactyl is using to route outbound traffic:

```
ip route | grep pterodactyl
```

Assuming this output:

```
172.20.0.0/16 dev pterodactyl0 proto kernel scope link src 172.20.0.1
```

You should add this iptables rule:

```
iptables -t mangle -A PREROUTING -s 172.20.0.0/16 -m conntrack --ctstate ESTABLISHED,RELATED -j MARK --set-xmark 0x9
```

Which marks packets from the 172.20.0.0/16 network that belong to existing connections so that your routing rules know “this traffic belongs to TCPShield’s VXLAN, send it back through the tunnel.”&#x20;

## 3. Tunnel deletion

In case you need to delete the tunnel and re-run the setup script, here is how:

```
ip link del dev vxlan_<ID>
ip rule del fwmark 9 table 200
```

You can also remove the iptables rules in the script, by replacing `-A` and `-I` with `-D` , example:&#x20;

```
iptables -t mangle -D OUTPUT -s 104.234.6.137/32 -j MARK --set-xmark 0x9
iptables -t mangle -D POSTROUTING -s 104.234.6.137 -j MARK --set-mark 0
```

## 4. VXLAN tunnel stopped working on server reboot&#x20;

Sometimes, after rebooting your VM or dedicated server, the VXLAN script may not re-run, causing the service to stop working. To fix this, you can set up a persistent service to automatically run the VXLAN script after each reboot.

**Steps to Setup Persistent VXLAN Tunnel:**

1. Edit the `rc.local` file:

```
sudo nano /etc/rc.local
```

2. Add the following lines to execute the VXLAN script at boot:

```
#!/bin/bash
# rc.local - VXLAN auto setup at boot
sleep 5
<INSERT YOUR VXLAN SCRIPT HERE>
echo "VXLAN script executed"
exit 0
```

3. Save and exit the editor (`Ctrl+X`, then `Y` to confirm).
4. Make the script executable:

```
sudo chmod +x /etc/rc.local
```

Now, the VXLAN script will run automatically after each reboot, ensuring that the tunnel is re-established.&#x20;

## 5. Disable Reverse Path Filtering

By default, most Linux distributions have `rp_filter` (Reverse Path Filtering) enabled. This is a kernel security feature that drops packets if their **source address** does not match the expected interface route — a defense mechanism against IP spoofing.

However, in setups using **VXLAN** or **asymmetric routing**, this behavior can cause **legitimate packets** to be dropped if the kernel thinks they arrived from the "wrong" interface. During a `tcpdump` capture, you may see packets coming in, but no responses being sent by the kernel. For example:

```
root@admin:~# sudo tcpdump -nni any udp port 19132
tcpdump: data link type LINUX_SLL2
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on any, link-type LINUX_SLL2 (Linux cooked v2), snapshot length 262144 bytes
15:15:30.707370 vxlan_47 In  IP 14.231.20.10.62338 > 104.234.6.137.19132: UDP, length 33
15:15:43.571573 vxlan_47 In  IP 14.231.20.10.63192 > 104.234.6.137.19132: UDP, length 1172
15:15:44.084121 vxlan_47 In  IP 14.231.20.10.63192 > 104.234.6.137.19132: UDP, length 1172
15:15:44.598862 vxlan_47 In  IP 14.231.20.10.63192 > 104.234.6.137.19132: UDP, length 1172
```

As shown above, there is only ingress traffic from `14.231.20.10`, but no outgoing traffic from our VXLAN interface `104.234.6.137`. This means the system is silently dropping the replies.

To fix this, disable reverse path filtering for all interfaces and for your VXLAN interface specifically:

```
sysctl -w net.ipv4.conf.all.rp_filter=0
sysctl -w net.ipv4.conf.vxlan_<vxlan_id>.rp_filter=0
```

This disables strict source route validation, allowing the system to accept packets even if their return path differs — which is common in tunneling setups like VXLAN.

Once reverse path filtering is disabled, you should start seeing **bi-directional traffic** over your VXLAN tunnel. A successful exchange will show both incoming and outgoing packets during a `tcpdump` capture. Expected result:

```
root@admin:~# sudo tcpdump -nni any udp port 19132
tcpdump: data link type LINUX_SLL2
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on any, link-type LINUX_SLL2 (Linux cooked v2), snapshot length 262144 bytes
20:02:32.691465 vxlan_47 In  IP 14.231.20.10.55407 > 104.234.6.137.19132: UDP, length 1164
20:02:32.691550 vxlan_47 In  IP 14.231.20.10.55407 > 104.234.6.137.19132: UDP, length 1164
20:02:32.691665 vxlan_47 In  IP 14.231.20.10.55407 > 104.234.6.137.19132: UDP, length 1112
20:02:32.696211 vxlan_47 Out IP 104.234.6.137.19132 > 14.231.20.10.55407: UDP, length 43
20:02:32.726227 vxlan_47 Out IP 104.234.6.137.19132 > 14.231.20.10.55407: UDP, length 550
```
