awg-config-gen
Generate and audit AmneziaWG configs, with the obfuscation rules actually enforced.
$ awg-config-gen new vpn.example.com -n 3
awg-configs/server.conf
awg-configs/client1.conf
awg-configs/client2.conf
awg-configs/client3.conf
$ awg-config-gen check ~/existing.conf
ERROR S1 + 56 must not equal S2 (S1=30, S2=86) — that makes the handshake
init and response the same size on the wire, which is the fingerprint
the padding exists to hide
WARNING H1=4 matches a standard WireGuard message type — that message stays
identifiable as WireGuard, so the header obfuscation is configured
but not doing anything
Why
AmneziaWG hides WireGuard's packet signature behind junk packets, message padding and randomised headers. It works, and the parameters are documented. The problem is what happens when you get one wrong:
Nothing happens. The tunnel comes up. Traffic flows. awg show looks
healthy. You just don't have the obfuscation you think you have.
S1 + 56 == S2makes the handshake initiation and response the same size on the wire — which is the exact fingerprint the padding was added to remove.- An
Hvalue of 1, 2, 3 or 4 leaves that message type looking like plain WireGuard. Configured, inert. Jmaxat or above the system MTU gets the junk packet fragmented, and a fragmented junk packet is more conspicuous than no junk packet.- Any shared parameter differing between the two ends means the handshake never completes, with no log line that says why.
None of these produce an error from AmneziaWG. This tool refuses to emit them, and finds them in configs it didn't write.
Install
pip install awg-config-gen
One dependency: cryptography, for
X25519. This tool's whole job is producing private keys, so the curve
arithmetic comes from the audited library rather than from us.
Use
Generate a server and its clients
$ awg-config-gen new vpn.example.com -n 5 --preshared
Writes server.conf and client1..5.conf, mode 0600. Every shared
parameter is identical across all of them; Jc/Jmin/Jmax appear on the
clients only, which is what upstream recommends since junk is client-local.
-n, --clients how many clients (default 1)
-o, --out output directory (default ./awg-configs)
--port server listen port (default 51820)
--subnet tunnel subnet (default 10.8.0.0/24)
--dns client DNS servers (default 1.1.1.1 1.0.0.1)
--mtu set MTU in the configs, and size junk against it
--preshared add a PresharedKey per peer
--force overwrite existing files
It will not overwrite an existing config without --force. These files
contain private keys, and replacing one silently locks out whoever is using
it.
Audit a config you already have
$ awg-config-gen check /etc/amnezia/amneziawg/awg0.conf
$ awg-config-gen check *.conf --mtu 1500
Exits non-zero if there are errors, so it drops into CI or a pre-deploy check. This works on any WireGuard or AmneziaWG config, whoever wrote it — by hand, from a forum post, or from a panel that doesn't know the rules.
Just the parameters
$ awg-config-gen params
Jc = 8
Jmin = 23
Jmax = 991
S1 = 137
S2 = 71
H1 = 1314739462
...
For when you have a config already and only want a valid parameter set to paste into it.
Just the keys
$ awg-config-gen keys
PrivateKey = gHlufQLvEgdHwsK9ikaA1oYqkE6GIIWVwUaKR7j5k20=
PublicKey = cV/vjb0ANP3qJxfu8ROrGJvcyQI5baDvTZsAEIRL0BU=
$ awg-config-gen keys -n 100 # private public, one pair per line
As a library
from awg_config_gen import generate_obfuscation, validate_obfuscation, check_text
obf = generate_obfuscation(mtu=1420)
validate_obfuscation(obf) # [] when it is sound
for finding in check_text(open("awg0.conf").read()):
print(finding)
What gets checked
Hard errors — AmneziaWG rejects these, or they stop the tunnel working:
Jcoutside 1–128;Jmin >= Jmax;Jmax > 1280S1 > 1132,S2 > 1188,S1 + 56 == S2H1–H4not all distinct, or outside a uint32Jc/Jmin/Jmaxgiven partially- Malformed or mismatched keys, all-zero public keys, missing
AllowedIPs, a peer with noPublicKey, a config with no[Peer]at all
Warnings — legal, and probably not what you meant:
- An
Hvalue matching a WireGuard message type (1–4) S1/S2below 12, which is less padding than header protection needsJmaxat or above the MTU- An endpoint peer with no
PersistentKeepalive - A plain WireGuard config with no obfuscation at all
Every rule comes from upstream:
amneziawg-linux-kernel-module
and amneziawg-go.
The output format was checked against awg-quick, which matches option names
case-insensitively and passes unrecognised [Interface] keys through to
awg setconf.
Notes
- Parameters are drawn with
secrets, notrandom. A censor who can predict your padding sizes can fingerprint you as well as if you had none. - The generator runs its own validator over what it produced before writing it. If those two ever disagree it is a bug, and failing is better than shipping it into a config.
I1–I5custom signature packets are parsed and preserved on a round trip, but not generated — a good signature packet imitates a specific real protocol, and a generic one is its own fingerprint.
Compatibility
Python 3.8+. Generates configs for AmneziaWG 1.5+ and plain WireGuard.
License
MIT.
Built by Yuix Networks, who run Unblock Master VPN on AmneziaWG.
Metadata
Release files for awg-config-gen 1.0.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| awg_config_gen-1.0.0.tar.gz | 22.8 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| awg_config_gen-1.0.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 41.6 kB
Release files / awg_config_gen-1.0.0.tar.gz
| Download URL | awg_config_gen-1.0.0.tar.gz |
|---|---|
| Size | 22.8 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
c1ec89ca8957555014f19b603468f10ea94302986bd2579dd37187a8e16960f8
|
|
BLAKE2b-256 checksum How to use checksums |
9caa2a2607a8402fe2b861ec4129b3d92c492f3e24cf1b3f36ce9c4cdf1be328
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.2
|
Release files / awg_config_gen-1.0.0-py3-none-any.whl
| Download URL | awg_config_gen-1.0.0-py3-none-any.whl |
|---|---|
| Size | 18.8 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
85b0daa7ed68890492226bb4500e5b02429ecb17298373ae1731de30d08df7e6
|
|
BLAKE2b-256 checksum How to use checksums |
7f06ec74a82e796c106fab3d951e5885e33d3a9723b7b5684ccb92c06ad7449e
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.2
|