---
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>
