没有不值得去解决的问题,也没有不值得去学习的技术!

WireGuard Self-Hosted VPN Outage Review: From Sudden Handshake Failure to Port Blocking and Resolution via Port Switching and Smart Routing

The client shows no "latest handshake" and remains in a waiting-for-connection state. The client appears to be connected, but there is actually no handshake and no traffic forwarding. Received data remains at 0.

I. Background

  1. Self-hosted WireGuard service, originally using port 57586. Before 10:00 AM, both computer WiFi and phone 5G could handshake normally, bypass the firewall normally, and connect to domestic websites directly.
  2. The server had already been optimized (key command-line operations were organized in advance for easy future reuse): UFW firewall was stopped and disabled, iptables forwarding rules were configured and persisted, resulting in a clean network forwarding environment with no conflicts or lingering issues.
  3. The client originally used a smart routing scheme: domestic websites connected directly, while overseas traffic went through the VPN, paired with Alibaba public DNS to improve domestic resolution speed.

II. Prior Server-Side Optimization (Complete UFW and iptables command lines, must save!)
This step covers the optimizations completed before the failure, aiming to clean up server-side firewall conflicts and ensure normal WireGuard forwarding. Subsequent troubleshooting can directly rule out issues in this phase. Execute the command lines in order:

1. UFW Firewall Operations (Stop + Disable, to avoid conflicts with iptables)
Before configuring iptables rules, you must stop and disable the system’s built-in UFW firewall to prevent rule conflicts between the two that could cause network anomalies. Below are the complete operation steps executed on the actual server, including specific commands and execution feedback, which can be directly referenced for hands-on practice.

1.1. Check Current FORWARD Chain Rules (Pre-check)
Execute the following command to view the default policy and existing rules of the iptables FORWARD chain, confirming the initial state:

Plaintext
root@vultr:~# iptables -L FORWARD -n
Chain FORWARD (policy DROP)
target     prot opt source               destination
ACCEPT     all  --  0.0.0.0/0            0.0.0.0/0
ACCEPT     all  --  0.0.0.0/0            0.0.0.0/0
ufw-before-logging-forward  all  --  0.0.0.0/0            0.0.0.0/0
ufw-before-forward  all  --  0.0.0.0/0            0.0.0.0/0
ufw-after-forward  all  --  0.0.0.0/0            0.0.0.0/0
ufw-after-logging-forward  all  --  0.0.0.0/0            0.0.0.0/0
ufw-reject-forward  all  --  0.0.0.0/0            0.0.0.0/0
ufw-track-forward  all  --  0.0.0.0/0            0.0.0.0/0

Note: In the initial state, the default policy of the FORWARD chain is DROP (reject all forwarding), and it contains UFW-related forwarding rules. UFW needs to be disabled to clear the interference from these rules.

1.2. Stop the Currently Running UFW Firewall
Execute the command to immediately stop the UFW service:

Plaintext
root@vultr:~# systemctl stop ufw

Note: This command produces no additional output. After execution, the UFW service stops immediately and no longer takes effect.

1.3. Disable UFW from Starting on Boot (To prevent auto-start after reboot)
Execute the command to disable the UFW service from starting automatically on boot, thoroughly preventing it from interfering with iptables configurations after a reboot:

Plaintext
root@vultr:~# systemctl disable ufw
Synchronizing state of ufw.service with SysV service script with /lib/systemd/systemd-sysv-install.
Executing: /lib/systemd/systemd-sysv-install disable ufw
Removed /etc/systemd/system/multi-user.target.wants/ufw.service.
root@vultr:~# systemctl status ufw
○ ufw.service - Uncomplicated firewall
     Loaded: loaded (/lib/systemd/system/ufw.service; disabled; vendor preset: enabled)
     Active: inactive (dead)
       Docs: man:ufw(8)

Apr 27 07:51:53 guest systemd[1]: Starting Uncomplicated firewall...
Apr 27 07:51:54 guest systemd[1]: Finished Uncomplicated firewall.
Apr 29 06:55:20 vultr systemd[1]: Stopping Uncomplicated firewall...
Apr 29 06:55:20 vultr systemd[1]: ufw.service: Deactivated successfully.
Apr 29 06:55:20 vultr systemd[1]: Stopped Uncomplicated firewall.

Note: The output shows that the UFW service status has been synchronized and the auto-start link has been removed, ensuring UFW will not start automatically after the server reboots.

1.4. Check UFW Status to Confirm It Is Stopped
Execute the command to verify whether the UFW service has been successfully stopped and disabled:

Plaintext
root@vultr:~# systemctl status ufw
○ ufw.service - Uncomplicated firewall
     Loaded: loaded (/lib/systemd/system/ufw.service; disabled; vendor preset: enabled)
     Active: inactive (dead)
       Docs: man:ufw(8)

Apr 27 07:51:53 guest systemd[1]: Starting Uncomplicated firewall...
Apr 27 07:51:54 guest systemd[1]: Finished Uncomplicated firewall.
Apr 29 06:55:20 vultr systemd[1]: Stopping Uncomplicated firewall...
Apr 29 06:55:20 vultr systemd[1]: ufw.service: Deactivated successfully.
Apr 29 06:55:20 vultr systemd[1]: Stopped Uncomplicated firewall.

Key verification points:

  • The Loaded line shows disabled: Indicates auto-start has been disabled;
  • The Active line shows inactive (dead): Indicates the UFW service is currently stopped;
  • The log shows Deactivated successfully: Indicates the UFW service has been successfully stopped.

2. Supplement: iptables Configuration and Rule Persistence (Connecting to actual operations)
After stopping UFW, you can configure iptables rules and use tools to persist the rules, preventing them from being lost after a reboot. Below are the complete steps executed in practice:

2.1. Configure iptables FORWARD Chain Rules
Change the default policy of the FORWARD chain to ACCEPT, and add WireGuard (wg0 interface) related forwarding rules (applicable to VPN scenarios):

Bash
# 设置 FORWARD 链默认策略为 ACCEPT(允许所有转发)
iptables -P FORWARD ACCEPT
# 允许从 wg0 网卡进入的流量转发
iptables -A FORWARD -i wg0 -j ACCEPT
# 允许从 wg0 网卡出去的流量转发
iptables -A FORWARD -o wg0 -j ACCEPT

Note: No additional output. After execution, the rules take effect immediately. You can run iptables -L FORWARD -n again to check if the rules were added successfully.

2.2. Install iptables Persistence Tool
Install the iptables-persistent tool to save iptables rules, ensuring they are not lost after the server reboots:

Plaintext
root@vultr:~# apt install -y iptables-persistent
Reading package lists... Done
Building dependency tree... Done
The following additional packages will be installed:
The following NEW packages will be installed:
  iptables-persistent netfilter-persistent
0 upgraded, 2 newly installed, 0 to remove and 5 not upgraded.
Need to get 13.9 kB of archives.
After this operation, 93.2 kB of additional disk space will be used.
Get:1 http://ubuntu.mirror.constant.com jammy/universe amd64 netfilter-persistent all 1.0.16 [7,440 B]
Get:2 http://ubuntu.mirror.constant.com jammy/universe amd64 iptables-persistent all 1.0.16 [6,488 B]
Fetched 13.9 kB in 1s (18.3 kB/s)
Preconfiguring packages ...
Selecting previously unselected package netfilter-persistent.
(Reading database ... 86643 files and directories currently installed.)
Preparing to unpack .../netfilter-persistent_1.0.16_all.deb ...
Unpacking netfilter-persistent (1.0.16) ...
Selecting previously unselected package iptables-persistent.
Preparing to unpack .../iptables-persistent_1.0.16_all.deb ...
Unpacking iptables-persistent (1.0.16) ...
Setting up netfilter-persistent (1.0.16) ...
Created symlink /etc/systemd/system/multi-user.target.wants/netfilter-persistent.service → /lib/systemd/system/netfilter-persistent.service.
Setting up iptables-persistent (1.0.16) ...
update-alternatives: using /lib/systemd/system/netfilter-persistent.service to provide /lib/systemd/system/iptables.service (iptables.service) in auto mode
Processing triggers for man-db (2.10.2-1) ...
Scanning processes...
Scanning candidates...
Scanning linux images...

Running kernel seems to be up-to-date.

Restarting services...
 /etc/needrestart/restart.d/systemd-manager
 systemctl restart multipathd.service packagekit.service polkit.service rsyslog.service ssh.service systemd-journald.service systemd-networkd.service systemd-resolved.service systemd-timesyncd.service systemd-udevd.service udisks2.service
Service restarts being deferred:
 systemctl restart ModemManager.service
 /etc/needrestart/restart.d/dbus.service
 systemctl restart networkd-dispatcher.service
 systemctl restart systemd-logind.service
 systemctl restart unattended-upgrades.service
 systemctl restart user@0.service

No containers need to be restarted.

No user sessions are running outdated binaries.

No VM guests are running outdated hypervisor (qemu) binaries on this host.
root@vultr:~# netfilter-persistent save
run-parts: executing /usr/share/netfilter-persistent/plugins.d/15-ip4tables save
run-parts: executing /usr/share/netfilter-persistent/plugins.d/25-ip6tables save
root@vultr:~# client_loop: send disconnect: Connection reset
PS C:\Users\Thinkpad> ssh root@139.180.154.26
ssh: connect to host 139.180.154.26 port 22: Connection timed out
PS C:\Users\Thinkpad> ssh root@139.180.154.26
root@139.180.154.26's password:
Welcome to Ubuntu 22.04.5 LTS (GNU/Linux 5.15.0-176-generic x86_64)

 * Documentation:  https://help.ubuntu.com
 * Management:     https://landscape.canonical.com
 * Support:        https://ubuntu.com/pro

 System information as of Wed Apr 29 07:13:48 AM UTC 2026

  System load:  0.0                Processes:               145
  Usage of /:   28.5% of 22.88GB   Users logged in:         1
  Memory usage: 25%                IPv4 address for enp1s0: 139.180.154.26
  Swap usage:   0%

 * Strictly confined Kubernetes makes edge and IoT secure. Learn how MicroK8s
   just raised the bar for easy, resilient and secure K8s cluster deployment.

   https://ubuntu.com/engage/secure-kubernetes-at-the-edge

Expanded Security Maintenance for Applications is not enabled.

1 update can be applied immediately.
To see these additional updates run: apt list --upgradable
Enable ESM Apps to receive additional future security updates.
See https://ubuntu.com/esm or run: sudo pro status

New release '24.04.4 LTS' available.
Run 'do-release-upgrade' to upgrade to it.


******************************PLEASE NOTE********************************
* If this a new instance, cloud-init may still be running and normal    *
* operations may not work as expected.                                  *
*                                                                       *
* Please use `cloud-init status' to check on the status of the instance *
* provisioning                                                          *
*                                                                       *
* Remove this message by editing /etc/motd                              *
*************************************************************************
Last login: Wed Apr 29 06:55:10 2026 from 183.221.85.7

Note: During installation, the dependency package netfilter-persistent is installed automatically, requiring no extra action.

2.3. Save iptables Rules (Persistence)
Execute the command to save the currently configured iptables rules to a persistent file:

Plaintext
root@vultr:~# netfilter-persistent save
run-parts: executing /usr/share/netfilter-persistent/plugins.d/15-ip4tables save
run-parts: executing /usr/share/netfilter-persistent/plugins.d/25-ip6tables save

Note: The output shows that the iptables rules for IPv4 (15-ip4tables) and IPv6 (25-ip6tables) have been successfully saved. The rules will load automatically after the server reboots.

3. Practical Operation Notes

  • Operating environment: This hands-on practice is based on the Ubuntu system (inferred from the software source http://ubuntu.mirror.constant.com). Other Debian-based systems can use this as a reference;
  • Permission requirements: All commands must be executed as the root user (in practice, using the root@vultr:~# terminal, no need to add sudo);
  • Rule verification: After each step, it is recommended to execute the corresponding view command (such as systemctl status ufw, iptables -L FORWARD -n) to confirm the operation took effect;
  • Persistence confirmation: After saving the rules, you can reboot the server (reboot) and check the iptables rules again to confirm they are not lost.

Note: After executing the above commands, the server-side network forwarding environment is stable. Subsequent failures are unrelated to UFW and iptables configurations, so there is no need to repeat these operations.

III. Sudden Failure Symptoms

  1. Suddenly stopped working in the afternoon. The client showed no “latest handshake” and remained in a waiting-for-connection state.
  2. Switched between home computer WiFi and phone 5G network; both devices and both networks failed to handshake.
  3. The client appeared to be connected, but there was actually no handshake and no traffic forwarding. Received data remained at 0. See Figure 1
The client shows no "latest handshake" and remains in a waiting-for-connection state. The client appears to be connected, but there is actually no handshake and no traffic forwarding. Received data remains at 0.

IV. Complete Troubleshooting and Localization Process

  1. Basic Connectivity Troubleshooting
  • Tested using ping [Server IP]: IP latency was normal with no packet loss, proving the server IP was not blocked and the routing path was normal.
Bash
# 电脑 Windows 命令提示符(CMD)执行,持续测试连通性
ping -t 139.180.154.26
# 测试完成后按 Ctrl+C 停止,查看丢包率(0% 丢包即为正常)
- PowerShell 测试 TCP 57586 端口连接失败:
# 电脑 PowerShell 执行,测试 TCP 端口(仅辅助判断)
Test-NetConnection 139.180.154.26 -Port 57586

Key misconception clarified: Test-NetConnection can only test TCP. WireGuard uses only the UDP protocol. TCP inaccessibility does not necessarily mean UDP is inaccessible, but it can assist in identifying port anomalies.

  1. Server-Side Status Check
    Log into the VPS and execute the following commands to check the WireGuard running status:
Plaintext
# 1. Check WireGuard running status (confirm wg0 interface is normal)
root@vultr:~# wg show
interface: wg0
  public key: XZ2LNJxO7RqjGKHyubFw35eR7AkRa1iHqltQJYdsY3g=
  private key: (hidden)
  listening port: 57586

peer: QnBvrNGpbGs+9JxCgZvT16sVr1g735JMgWGFIdqmsz8=
  preshared key: (hidden)
  endpoint: 183.221.85.7:18607
  allowed ips: 10.66.66.2/32, fd42:42:42::2/128
  transfer: 3.04 KiB received, 1.89 KiB sent

peer: TX/hWjKXFoDyhQncE6M5DuC7d4DffzjJWHL+errBsTU=
  preshared key: (hidden)
  endpoint: 183.221.85.7:18650
  allowed ips: 10.66.66.3/32, fd42:42:42::3/128
  transfer: 1.73 KiB received, 1.08 KiB sent
root@vultr:~# client_loop: send disconnect: Connection reset

Check results:

  • WireGuard service is running normally and listening on port 57586;
  • Existing client node records prove that the server configuration, program, listening, and forwarding rules are all normal.
    Ruled out failure causes: The server did not crash, there are no lingering issues from UFW/iptables configurations, and there is no server forwarding anomaly.

3. Root Cause Identification
3.1. Devices across different networks (home WiFi + phone 5G) all failed to handshake, ruling out single-device or single-broadband issues.
3.2. It worked normally in the morning and suddenly failed in the afternoon without any configuration changes.
3.3. Final diagnosis: Domestic ISP periodic QoS throttling; cross-border high-port UDP 57586 is silently intercepted and dropped by the backbone network. This is unrelated to client routing, DNS, or local configuration.

V. Solution Implementation Process

1. Change to an Available Port (Core solution, command line + backend operations)
Abandon the easily blocked high port 57586 and switch to the more block-resistant regular port 2096. Steps are as follows: See Figure 2

Abandon the easily blocked high port 57586 and switch to the more block-resistant regular port 2096. Steps are as follows:
Plaintext
# Step 1: Modify the WireGuard configuration file on the VPS (change the listening port) See Figure 2
vi /etc/wireguard/wg0.conf

# Find ListenPort = 57586, change it to 2096. Port 443 is also recommended (it looks almost exactly like normal HTTPS traffic and is very difficult to block precisely).
# Example: ListenPort = 2096

# Save and exit the vi editor

# Step 2: Restart the WireGuard service to apply the port change
root@vultr:~# wg-quick down wg0
[#] ip link delete dev wg0
[#] iptables -D INPUT -p udp --dport 57586 -j ACCEPT
[#] iptables -D FORWARD -i enp1s0 -o wg0 -j ACCEPT
[#] iptables -D FORWARD -i wg0 -j ACCEPT
[#] iptables -t nat -D POSTROUTING -o enp1s0 -j MASQUERADE
[#] ip6tables -D FORWARD -i wg0 -j ACCEPT
[#] ip6tables -t nat -D POSTROUTING -o enp1s0 -j MASQUERADE
root@vultr:~# wg-quick up wg0
[#] ip link add wg0 type wireguard
[#] wg setconf wg0 /dev/fd/63
[#] ip -4 address add 10.66.66.1/24 dev wg0
[#] ip -6 address add fd42:42:42::1/64 dev wg0
[#] ip link set mtu 1420 up dev wg0
[#] iptables -I INPUT -p udp --dport 57586 -j ACCEPT
[#] iptables -I FORWARD -i enp1s0 -o wg0 -j ACCEPT
[#] iptables -I FORWARD -i wg0 -j ACCEPT
[#] iptables -t nat -A POSTROUTING -o enp1s0 -j MASQUERADE
[#] ip6tables -I FORWARD -i wg0 -j ACCEPT
[#] ip6tables -t nat -A POSTROUTING -o enp1s0 -j MASQUERADE

# Step 3: Confirm the port change was successful (check if listening port is 2096)
root@vultr:~# wg show
interface: wg0
  public key: XZ2LNJxO7RqjGKHyubFw35eR7AkRa1iHqltQJYdsY3g=
  private key: (hidden)
  listening port: 2096

peer: QnBvrNGpbGs+9JxCgZvT16sVr1g735JMgWGFIdqmsz8=
  preshared key: (hidden)
  allowed ips: 10.66.66.2/32, fd42:42:42::2/128

peer: TX/hWjKXFoDyhQncE6M5DuC7d4DffzjJWHL+errBsTU=
  preshared key: (hidden)
  allowed ips: 10.66.66.3/32, fd42:42:42::3/128
root@vultr:~# client_loop: send disconnect: Connection reset

Step 4: Vultr Backend Firewall Configuration (Mandatory, otherwise the new port will be inaccessible)

  1. Log into the Vultr backend → find the corresponding VPS → click Firewall Groups on the left;
  2. Find the original rule allowing UDP 57586 and delete it;
  3. Add a new rule: Select UDP for Protocol, enter 2096 for Port, enter WireGuard for Description, and save;
    Step 5: Modify the port on the computer client → reconnect, restore handshake time, and the tunnel will be smooth.

2. Restore Smart Routing + Domestic DNS Optimization

Change the client configuration back to the optimal custom scheme. No command line is needed; just edit the client configuration file directly:
2.1. Change DNS to Alibaba public DNS: 223.5.5.5, 223.6.6.6 for faster domestic web resolution without detours;
2.2. Use split routing rules for AllowedIPs:
0.0.0.0/1, 128.0.0.0/2, ::/1, 8000::/1
0.0.0.0/1, 128.0.0.0/2: Achieves direct connection for domestic IPv4 and tunneling for overseas traffic
::/1, 8000::/1: Fully covers IPv6 addresses, routing overseas IPv6 traffic through the tunnel
2.3. Keep PersistentKeepalive = 25: Prevents router NAT timeouts and keeps the connection alive when the screen is locked or in the background.

3. Mobile Client Adaptation
3.1. The official WireGuard GUI on mobile phones lacks an entry to edit PersistentKeepalive, so the keepalive parameter cannot be entered manually;
3.2. Solution: Delete the old tunnel and create a new one by pasting the complete configuration text;
3.3. After pasting and importing, the underlying parameters take effect. Keepalive, routing, DNS, and port configurations all become active, ensuring stable background connectivity without disconnections.

VI. Summary of Key Knowledge Points

  1. WireGuard relies on UDP handshakes. High ports (50000+) are easily subject to periodic silent blocking by domestic ISPs; this is not a configuration issue;
  2. A successful ping to the IP only proves that the route is normal, not that the UDP port is available;
  3. PowerShell port testing only supports TCP and cannot be used to determine WireGuard UDP connectivity;
  4. ::/1, 8000::/1 is the full-coverage IPv6 routing notation, which, combined with IPv4 split routing, achieves smart routing for the entire network;
  5. The mobile client requires importing the complete configuration text for the keepalive parameters to take effect; the GUI cannot edit hidden configurations;
  6. Choosing regular disguised ports like 2096/4433 is much more stable than high ports like 50000+, eliminating the need to change ports frequently;
  7. Server-side UFW and iptables configurations should be set up and persisted once. No repeated operations are needed later, avoiding conflicts.

VII. Final Usable Configuration Template (Copy and use directly)

  1. Computer Client Configuration (IP: 10.66.66.2, independent and conflict-free)
Plaintext
[Interface]
PrivateKey = MNcoOjHNvao4gH1+xDV5I...
Address = 10.66.66.2/32, fd42:42:42::2/128
DNS = 223.5.5.5, 223.6.6.6

[Peer]
PublicKey = XZ2LNJxO7RqjGKHyubFw35eR7AkRa1iHqltQJYdsY3g=
PresharedKey = Fz04FNeapuPYQ+QAH+yN...
AllowedIPs = 0.0.0.0/1, 128.0.0.0/2, ::/1, 8000::/1
Endpoint = 139.180.154.26:2096
PersistentKeepalive = 25
  1. Mobile Client Configuration (IP: 10.66.66.3, independent and conflict-free)
Plaintext
[Interface]
PrivateKey = ADwndW5NwCU4YZJHC1UP...
Address = 10.66.66.3/32,fd42:42:42::3/128
DNS = 223.5.5.5, 223.6.6.6

[Peer]
PublicKey = XZ2LNJxO7RqjGKHyubFw35eR7AkRa1iHqltQJYdsY3g=
PresharedKey = Y2kt8vfHL+iCOJ0bxW...
Endpoint = 139.180.154.26:2096
AllowedIPs = 0.0.0.0/1, 128.0.0.0/2, ::/1, 8000::/1
PersistentKeepalive = 25

Note: If the AllowedIPs configuration is incomplete, please refer to: WireGuard Domestic Direct Connection + Overseas Tunnel Configuration Pitfalls and Perfect Solution (Tested and Working)

VIII. Backup Command Lines (For future failures, must save)

1. Restart WireGuard Service (Must use after port or configuration changes)

wg-quick down wg0 && wg-quick up wg0

2. View iptables Rules (Use when suspecting forwarding anomalies)

iptables -L FORWARD

3. Re-save iptables Rules (Use if rules are lost)

netfilter-persistent save

4. View VPS Network Status (Assists in troubleshooting port listening)

netstat -tulnp | grep wg0

5. Reboot VPS (Use when the port is silently blocked by a Vultr node)

reboot

系列导航

关于作者 · 持续学习与技术实践

我是一名拥有 15 年以上开发经验的技术从业者,自 2013 年起持续运营个人技术博客,记录工作与个人项目中遇到的真实问题,以及解决问题过程中的探索、实践和思考。

除了技术写作,我也在持续开发和维护自己的独立项目,探索新技术和新工具在实际场景中的应用。我始终相信,没有不值得去解决的问题,也没有不值得去学习的技术。

如果这篇文章对你有所帮助,欢迎浏览博客中的其他文章,也欢迎交流技术经验与想法。

关于我  ·  GitHub  ·  邮件联系