#3204·mihomo

[Bug]

Author: ItsRainingTodayCreated Sep 12, 2026Updated Sep 12, 2026
Labelsbug

[Bug] AmneziaWG v3 (Header Protection) handshake never completes — silent failure, no errors in logs

Description

WireGuard proxies configured with amnezia-wg-option.version: 3 and header-protection-key (AmneziaWG 3.0/3.1 protocol, per [official Amnezia spec](https://docs.amnezia.org/documentation/amnezia-wg/)) never establish a connection. The proxy is silently dropped from group delay-test results — no error is logged anywhere, even with log-level: debug.

Plain WireGuard and other proxy types (VLESS+Reality, Hysteria2, etc.) on the same mihomo instance work correctly. Raw UDP connectivity to the AmneziaWG server is confirmed open (nc -u -zv succeeds). The config was independently verified field-by-field against the actual struct definition in adapter/outbound/wireguard.go (commit 8453e58, "feat: support AmneziaWG v3.0") and against the [official Amnezia protocol documentation](https://docs.amnezia.org/documentation/amnezia-wg/) — every field name, type, and value matches the expected schema exactly.

Reproduction Steps

  1. Obtain an AmneziaWG v3 client config (.conf) from an Amnezia Premium/self-hosted server that has Header Protection enabled (i.e. the exported config includes HeaderProtectionKey).
  2. Convert it to mihomo YAML format (mapping confirmed correct against source):
yaml
proxies:
  - name: "amneziawg-v3-test"
    type: wireguard
    server: <server-ip>
    port: <port>
    ip: <client-tunnel-ip>/32
    private-key: <REDACTED>
    public-key: <REDACTED>
    udp: true
    pre-shared-key: <REDACTED>
    persistent-keepalive: 25
    amnezia-wg-option:
      jc: 6
      jmin: 10
      jmax: 80
      s1: 381
      s2: 865
      s3: 209
      s4: 12
      h1: 1
      h2: 2
      h3: 3
      h4: 4
      version: 3
      header-protection-key: <REDACTED, 32-byte base64>
      content-padding-addition: 10-100
      rekey-after-time: 100-120
      rekey-timeout: 3-8
      reject-after-time: 150-180
      keepalive-timeout: 7-13
      max-handshake-attempts: 15-20
  1. Add the proxy to a url-test group, or query directly:
    GET /proxies/{name}/delay?url=http://www.gstatic.com/generate_204&timeout=10000
  2. Observe: request returns 404 Not Found when queried individually by name; the proxy is simply absent from /group/{name}/delay batch results (all other proxies in the group return normally).

Expected behavior

The proxy either connects successfully, or mihomo logs a specific handshake/connection error (even at debug level) that would help diagnose a config mismatch.

Actual behavior

  • No log line is ever produced mentioning the proxy, WireGuard, or a handshake attempt/failure — confirmed via log-level: debug and /log print filtering on container, wireguard, and the proxy name.
  • The proxy is silently excluded from delay-test group results, exactly as if it never existed.
  • Direct /proxies/{name}/delay returns 404, even though the same name is confirmed present in /proxies (GLOBAL/group all list) and in /providers/proxies/{provider}.

What I've already ruled out

  • Config correctness: field names/types verified line-by-line against adapter/outbound/wireguard.go diff for commit 8453e58 (feat: support AmneziaWG v3.0). No typos, no missing/extra fields.
  • Network reachability: nc -u -zv -w5 <server> <port> from inside the mihomo container returns open.
  • mihomo version: reproduced specifically on v1.19.30 (release that introduced AmneziaWG v3.0/v3.1 support), confirmed via /version endpoint. Also briefly tested against a Prerelease-Alpha build (alpha-dca26db) with the same result.
  • Non-AmneziaWG proxies: dozens of other proxy types (VLESS+Reality, VLESS+gRPC, Hysteria2, standard WireGuard without amnezia-wg-option) on the exact same mihomo instance work normally.

Possible root cause (unconfirmed)

Other projects that implement AmneziaWG v3 support have independently documented that even officially tagged/published amneziawg-go artifacts have shipped without a fully working v3 UAPI implementation — see [amnezia-control v0.47.0 changelog](https://github.com/mihsergeev/amnezia-control/releases/tag/v0.47.0):

"The published amneziavpn/amneziawg-go image — even tagged 3.0.2 — still ships amneziawg-tools v1.0.20210914 and an engine without the 3.0 UAPI keys, so awg setconf rejects HeaderProtectionKey outright (verified on a live node)."

mihomo depends on github.com/metacubex/amneziawg-go (a fork, not upstream amnezia-vpn/amneziawg-go). It's possible this fork has a similar staleness/incompleteness issue specifically around the v3 UAPI handshake path, even though the Go struct/config-parsing layer (AmneziaWGOption) is fully wired up correctly.

Confirmed working reference implementations (v3.1, full Header Protection)

Importantly, this is not an inherent protocol limitation — multiple independent, actively maintained community projects have successfully implemented full AmneziaWG 3.1 support (including HeaderProtectionKey, ContentPaddingAddition, and all the other v3+ timing/obfuscation fields), which strongly suggests the gap is specific to metacubex/amneziawg-go's handshake path rather than something fundamentally unsupportable:

Since at least one of these (LamFex/openwrt-amneziawg3) uses the same userspace-Go-over-TUN architecture as mihomo rather than a kernel module, it may be a useful direct comparison point for whichever part of the v3 handshake/header-protection path is failing silently in metacubex/amneziawg-go.

Environment

  • mihomo version: v1.19.30 (also reproduced on alpha-dca26db)
  • Platform: MikroTik RouterOS 7.x, container package, linux/arm64 (also reproducible cross-platform in principle, not RouterOS-specific — the config/API-level symptoms are platform-independent)
  • Proxy type: wireguard with amnezia-wg-option.version: 3

Additional notes

Would be happy to provide a redacted pcap if a maintainer can point me to how to enable amneziawg-go-level debug tracing specifically (separate from mihomo's own log-level: debug, which does not surface anything for this code path).