mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2026-09-09 19:57:14 +00:00
bd1c27b03d
* fix(amneziawg): stop H1-H4 generator misclassifying transport packets Both the Go generator and its frontend mirror picked a random *range* per H1-H4 field with only a minimum width enforced (no maximum). amneziawg-go's packet classifier only ever compares a fixed-size ciphertext prefix against these bounds, so a wide range buys no DPI resistance -- the boundaries themselves are never observable on the wire. It does cost real throughput: with randomTrailers on (the default here), the handshake-size checks relax from == to >, so a wide H-range misclassifies a proportional fraction of ordinary transport packets as handshakes and silently drops them (amnezia-vpn/amneziawg-go#183). A single value per field is strictly safer than any range, with no obfuscation trade-off. Live-tested: narrowing H1-H4 alone took AmneziaWG upload from 2-3 Mbit/s to 200+ Mbit/s on one box, and ~20 Mbit/s to 120-156 Mbit/s on another, single-variable, no other change. * fix(amneziawgnet): raise tunQueueDepth to absorb slow-start bursts 1024 was sized for a single-connection buffering problem (the gVisor-to-amneziawg-go TUN handoff channel needing slack for the download direction). tcpip.Stack.Stats() during a real many-connection download (20-28 concurrent TCP flows, e.g. a segmented speed test) showed SlowStartRetransmits jump by ~770 in a single second the moment CurrentEstablished crossed ~20 -- consistent with many connections' simultaneous slow-start growth briefly exceeding 1024 outstanding packets and gVisor treating the resulting silent drops as real network loss. * fix(amneziawg): trim comment blocks to the repo's 2-line cap Review feedback: four comment blocks in the previous commits exceeded CLAUDE.md's 2-line-per-block hard rule (up to 13 lines). Trimmed each to the one non-obvious fact plus the amneziawg-go#183 reference; the fuller rationale already lives in the commit message. Also refreshed the stale H1-H4 range example in docs/content/docs/en/config/amneziawg.mdx to match the new single-value generator output.
178 lines
7.7 KiB
Plaintext
178 lines
7.7 KiB
Plaintext
---
|
|
title: AmneziaWG
|
|
description: Set up an AmneziaWG inbound in 3x-ui — obfuscation parameters, native IPv6, per-client port-forwarding, and routing client traffic through Xray.
|
|
icon: Lock
|
|
---
|
|
|
|
**AmneziaWG** is a WireGuard fork that adds traffic obfuscation (junk packets,
|
|
randomized padding, and rewritten protocol magic values) so the tunnel doesn't
|
|
look like WireGuard to deep-packet inspection. It's a popular choice where
|
|
plain WireGuard is blocked but a WireGuard-shaped tunnel with a different
|
|
fingerprint gets through.
|
|
|
|
<Callout type="info">
|
|
AmneziaWG runs **embedded in the panel process** — `amneziawg-go` over a
|
|
userspace (gVisor) network stack, not a kernel module. There is no DKMS
|
|
build, no Secure Boot conflict, and no host network/kernel access
|
|
requirement, so it works the same way inside a container as on bare
|
|
metal. Each peer's decapsulated traffic relays into its own loopback Xray
|
|
SOCKS5 inbound, so a peer's routing, sniffing, and per-client stats all
|
|
come from Xray's own machinery — the same as any other protocol's
|
|
inbound, not a separate code path.
|
|
</Callout>
|
|
|
|
## Key settings
|
|
|
|
### Server / interface
|
|
|
|
| Field | What it is |
|
|
| ------------------------ | ------------------------------------------------------------------------ |
|
|
| **Subnet** | The tunnel's IPv4 subnet (e.g. `10.8.1.0/24`); each client gets an address from it. |
|
|
| **MTU** | Interface MTU. Leave at the default unless you have a reason to change it. |
|
|
| **DNS (primary/secondary)** | Seeded into downloadable client configs; the server's own interface doesn't need one. |
|
|
| **External interface** | The host NIC a peer's IPv6 address gets aliased onto when IPv6 is enabled (see below). Leave blank to auto-detect. |
|
|
|
|
### Obfuscation (AmneziaWG 3.1)
|
|
|
|
The same values must match on both ends of the tunnel, so the server stores
|
|
them once and every client config inherits them. The panel generates a
|
|
randomized set for you (with a **regenerate** button) — a static, reused
|
|
value defeats the point, since DPI can fingerprint it over time.
|
|
|
|
| Field | What it is |
|
|
| ------------ | ---------------------------------------------------------------------------- |
|
|
| **Jc** | Number of junk packets sent before the handshake. |
|
|
| **Jmin/Jmax** | Size range (bytes) for those junk packets. `Jmin` must not exceed `Jmax`. |
|
|
| **S1/S2** | Padding added to the handshake init/response packets. `S1 + 56` must not equal `S2` — amneziawg-go rejects a value that would make both packets the same size. |
|
|
| **S3** | Cookie-reply padding, `0`-`64`. |
|
|
| **S4** | Transport (data) packet padding, `0`-`32`. |
|
|
| **H1-H4** | Magic header values that replace WireGuard's standard message-type bytes. Each is a single integer or a `low-high` range; `1`-`4` are reserved (real WireGuard message types) and must not be used. |
|
|
| **I1-I5** | Optional signature packets — random bytes prepended before the handshake, e.g. `<r 148>`. Generated sets fill `I1` only, matching Amnezia's own generator. |
|
|
| **HeaderProtectionKey** | A base64 32-byte key for the 3.0 header-protection mechanism. Must match on every client config; blank disables it. |
|
|
| **ContentPaddingAddition** | A single integer or `low-high` byte range of extra padding on content packets. Kept `<= 64` by the generator so a 1420-MTU tunnel doesn't fragment. |
|
|
| **RekeyAfterTime / RekeyTimeout / RejectAfterTime / KeepaliveTimeout / MaxHandshakeAttempts** | Handshake-timing randomization: each is a `low-high` range (seconds; attempts for the last one) the peer samples from, so session timing stops being a WireGuard fingerprint. Every `RekeyAfterTime` value must stay below every `RejectAfterTime` value. Blank keeps the WireGuard default. |
|
|
| **RandomTrailers** | Appends a random number of bytes to the end of every packet. |
|
|
| **DisableCookies** | Never send cookie replies — removes a DPI-visible WireGuard message type, at the cost of WireGuard's handshake-flood mitigation. |
|
|
|
|
<Callout type="info">
|
|
If you enter obfuscation values by hand instead of using the generated
|
|
defaults, keep `H1`-`H4` **non-overlapping** and above `4`, and double-check
|
|
`S1 + 56 != S2` — a bad value here keeps the embedded interface from
|
|
coming up at all.
|
|
</Callout>
|
|
|
|
<Callout type="warn">
|
|
The 3.1 parameters need a **3.1-capable client**. Clients must run a
|
|
3.1-capable Amnezia app; blanking the 3.1 fields renders a config older
|
|
clients still understand. There is no host-side version requirement —
|
|
the panel ships its own pinned `amneziawg-go`, not whatever happens to be
|
|
installed on the system.
|
|
</Callout>
|
|
|
|
## Set it up in the panel
|
|
|
|
<Steps>
|
|
|
|
<Step>
|
|
### Add an inbound
|
|
|
|
Add a new inbound, choose protocol **AmneziaWG**, and set the port and tunnel
|
|
subnet.
|
|
</Step>
|
|
|
|
<Step>
|
|
### Leave obfuscation on defaults (or regenerate)
|
|
|
|
The panel fills in a randomized, kernel-valid obfuscation set automatically.
|
|
Use **Regenerate** if you want a fresh one; there's no need to hand-edit these
|
|
unless you have a specific reason to.
|
|
</Step>
|
|
|
|
<Step>
|
|
### Add a client
|
|
|
|
Each client gets its own keypair and tunnel address. Download the client's
|
|
`.conf` or copy its share link (`vpn://…`, importable by the official
|
|
AmneziaWG/AmneziaVPN apps) from the client list.
|
|
</Step>
|
|
|
|
<Step>
|
|
### Optional: enable IPv6
|
|
|
|
Turning on IPv6 allocates an IPv6 address alongside each client's IPv4 one
|
|
from the configured IPv6 subnet. The panel aliases that address onto the
|
|
external interface's host NIC so outbound connections carry the peer's own
|
|
distinct public IPv6 identity — no NAT66 needed.
|
|
</Step>
|
|
|
|
<Step>
|
|
### Optional: forward ports to a client
|
|
|
|
Set a client's forwarded ports (e.g. `80, 443, 8000-8100`) to open a real
|
|
listener on the host that relays that traffic straight to the client's
|
|
tunnel address — useful for a client that needs to expose a service through
|
|
the server.
|
|
</Step>
|
|
|
|
</Steps>
|
|
|
|
Every AmneziaWG inbound's traffic already goes through Xray — each peer
|
|
relays into its own loopback SOCKS5 inbound, tagged with the AmneziaWG
|
|
inbound's own tag, so it shows up as a normal source on the
|
|
[Routing](/docs/operations/outbounds-routing) page like any other protocol's
|
|
inbound. There is no separate toggle for this: unlike a kernel tunnel,
|
|
there's no other way for a peer's traffic to reach the internet once it's
|
|
decapsulated.
|
|
|
|
## What the configuration looks like
|
|
|
|
A client's downloadable `.conf` (also what the `vpn://` share link encodes,
|
|
base64url'd) looks like this:
|
|
|
|
```ini title="client .conf"
|
|
[Interface]
|
|
PrivateKey = <client private key>
|
|
Address = 10.8.1.2/32
|
|
DNS = 8.8.8.8, 8.8.4.4
|
|
Jc = 4
|
|
Jmin = 65
|
|
Jmax = 220
|
|
S1 = 87
|
|
S2 = 44
|
|
S3 = 21
|
|
S4 = 9
|
|
H1 = 463065432
|
|
H2 = 912345678
|
|
H3 = 1345678901
|
|
H4 = 1987654321
|
|
I1 = <r 148>
|
|
HeaderProtectionKey = 8Iu83eHDA3fMKKSGaEsVW9Ycd2lYYzc0MYlk1jJTvE4=
|
|
ContentPaddingAddition = 17-49
|
|
RekeyAfterTime = 111-139
|
|
RekeyTimeout = 4-7
|
|
RejectAfterTime = 187-251
|
|
KeepaliveTimeout = 9-14
|
|
MaxHandshakeAttempts = 19-36
|
|
RandomTrailers = on
|
|
DisableCookies = on
|
|
|
|
# my-client
|
|
[Peer]
|
|
PublicKey = <server public key>
|
|
AllowedIPs = 0.0.0.0/0, ::/0
|
|
Endpoint = your-server:443
|
|
PersistentKeepalive = 25
|
|
```
|
|
|
|
## Not yet covered
|
|
|
|
<Callout type="info">
|
|
|
|
- **Multi-node (sub-nodes)** and **Telegram bot** — AmneziaWG inbounds haven't
|
|
been exercised through those paths yet. They likely work (the reconciler
|
|
runs the same way regardless of how the panel itself is deployed), but
|
|
that's not the same as a confirmed, tested claim — treat it as unverified
|
|
rather than assume it either way until someone reports back.
|
|
|
|
</Callout>
|