mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2026-11-06 13:15:01 +03:00
ed31ee432c
The node gate assumed a node-assigned sidecar row would never converge,
because the master's reconcile loops only read node_id IS NULL rows. But
a pushed row is local on the node's own panel, whose AmneziaWG, TUIC and
mtg loops run it like any other; node-adopted rows of these protocols
already worked. Only creating or cloning them from the master was blocked.
Open the three protocols on both lists and fix what assumed the master's
host for a node row:
- A node older than the release that introduced the protocol (MTProto
v3.5.0, AmneziaWG v3.7.0, TUIC v3.8.0) would hand it to Xray as-is, so
add and protocol-changing update refuse it, and a node that has not
reported its version yet. Dev builds ("dev+<sha>") track main and pass.
- MTProto's routeXrayPort is a loopback port on the host running mtg.
The master no longer allocates one, nor forwards a cloned source's, for
a node row; the node allocates its own and node sync adopts it back.
- AmneziaWG forwardedPorts were checked against the master's inbounds,
web port and id-derived relay ports. A node row is now checked against
its own node's inbounds; the node re-checks what only it knows.
UpdateInbound restores the stored nodeId before that check.
Verified on a docker master+node pair: AWG, routed MTProto and TUIC
created and cloned from the master start on the node (interface, mtg,
tuic-server); an AWG client added and an MTProto client edited on the
master apply on the node; the node-chosen egress port survives edits.
Closes #6306
182 lines
8.3 KiB
Plaintext
182 lines
8.3 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, `0`-`1552` / `0`-`1608`: the packets are `148 + S1` and `92 + S2` bytes and must fit the 1700-byte receive buffer amneziawg-go uses on iOS. The panel also rejects `S1 + 56 = S2`, which would give both packets the same size on the wire (amneziawg-go itself accepts it). An AmneziaWG outbound takes the remote server's values as they are, up to `65535`. |
|
|
| **S3** | Cookie-reply padding, `0`-`1636`: the reply is `64 + S3` bytes and must fit the 1700-byte receive buffer amneziawg-go uses on iOS. An outbound, as with S1/S2, takes the remote server's value up to `65535`. |
|
|
| **S4** | Transport (data) packet padding, `0`-`32`. |
|
|
| **H1-H4** | Header values that replace WireGuard's message-type field. Each is a single integer or a `low-high` range, and the four must not overlap — amneziawg-go and the kernel module refuse the whole device otherwise. `1`-`4` are WireGuard's own types and the engine default for a blank field: valid, but without a HeaderProtectionKey the type field then reads like plain WireGuard. |
|
|
| **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
|
|
```
|
|
|
|
## Multi-node (sub-nodes)
|
|
|
|
An AmneziaWG inbound can be created on, or cloned to, a sub-node. The node's
|
|
own panel runs the interface, so the node must run panel **v3.7.0** or newer;
|
|
the master refuses an older node, or one that has not reported its version yet.
|
|
A client's `forwardedPorts` are checked against the ports in use on that node.
|
|
|
|
## Not yet covered
|
|
|
|
<Callout type="info">
|
|
|
|
- **Telegram bot** — AmneziaWG inbounds haven't been exercised through the
|
|
bot yet. Treat it as unverified until someone reports back.
|
|
|
|
</Callout>
|