RU Русский | EN English
# AmneziaWG 3.x Installer: Advanced Documentation This is a supplement to the main [README.en.md](README.en.md), containing deeper technical details, explanations, and advanced options for the AmneziaWG 3.x (3.1 by default) and 2.0 installation and management scripts. For a step-by-step VPS deployment guide (VPS choice, OS choice, install flow, first client, update, uninstall, troubleshooting), see [INSTALL_VPS.md](INSTALL_VPS.md). ## Table of Contents - [✨ Features (Detailed)](#features-detailed-adv) - [🔐 Obfuscation Parameters (3.1 and 2.0)](#awg2-params-adv) - [Presets](#presets-adv) - [🆕 The third AmneziaWG line for self-hosted servers](#awg3-adv) - [What 3.1 added](#awg3-31-adv) - [Which module line you get](#awg3-lines-adv) - [What 3.0 changes on the wire](#awg3-wire-adv) - [The new 3.0 parameters](#awg3-params-adv) - [What has to match and what does not](#awg3-must-match-adv) - [Three things that can cost you an evening](#awg3-gotchas-adv) - [The 3.1 profile: what the installer turns on and what it leaves out](#awg3-not-yet-adv) - [Where 2.0 is installed instead of 3.1](#awg3-fallback-adv) - [⚙️ Client Configuration Details](#config-details-adv) - [AllowedIPs](#allowedips-adv) - [Device IPv6, `::/0` and the local network](#client-ipv6-adv) - [What a site can see when traffic is split by destination](#split-detect-adv) - [Client Isolation](#client-isolation-adv) - [IPv6 Dual-Stack Tunnel (v5.15.0+)](#ipv6-tunnel-adv) - [PersistentKeepalive](#persistentkeepalive-adv) - [DNS](#dns-adv) - [Your Own DNS Server for Clients](#own-dns-adv) - [Changing Default Settings](#change-defaults-adv) - [🔒 Server Security Settings](#security-adv) - [UFW Firewall](#ufw-adv) - [Kernel Parameters (Sysctl)](#sysctl-adv) - [The kernel module and user namespaces](#userns-module-adv) - [Fail2Ban (Automatic Setup)](#fail2ban-adv) - [Rotating the server key](#server-key-rotation-adv) - [🧹 Server Optimization](#optimization-adv) - [📋 Configuration Examples](#config-examples-adv) - [🖥️ CLI Parameters](#cli-params-adv) - [install_amneziawg.sh](#install-cli-adv) - [manage_amneziawg.sh](#manage-cli-adv) - [🧑💻 Full List of Management Commands](#manage-commands-adv) - [🤖 JSON interface for automation (--json)](#json-api-adv) - [🛠️ Technical Details](#tech-details-adv) - [Script Architecture](#architecture-adv) - [DKMS](#dkms-adv) - [Key and Config Generation](#keygen-adv) - [🔄 How to Update Scripts](#update-scripts-adv) - [❓ FAQ (Additional Questions)](#faq-advanced-adv) - [🩺 Diagnostics and Uninstall](#diag-uninstall-adv) - [Diagnostic Report Contents](#diagnostic-report-adv) - [🔧 Troubleshooting (Detailed)](#troubleshooting-adv) - [📊 Traffic Statistics (stats)](#stats-adv) - [⏳ Temporary Clients (--expires)](#expires-adv) - [📱 vpn:// URI Import](#vpnuri-adv) - [📱 MTU and Mobile Clients](#mtu-mobile-adv) - [🚧 Host Unreachable from Russia (Hetzner): AS-based Blocking](#as-blocking-adv) - [🛡️ Active Probing and Obfuscation Without a Proxy](#active-probing-adv) - [📋 Client Compatibility](#client-compat-adv) - [Which AmneziaWG generation a client speaks](#client-gen-adv) - [🐧 Debian Support](#debian-support-adv) - [🔧 Raspberry Pi and ARM64 Support](#arm-support-adv) - [🐧 Connecting a Linux machine as a client](#linux-client-adv) - [A split route list and the server address](#linux-client-loop-adv) - [📦 LXC / Docker via amneziawg-go (userspace)](#lxc-userspace-adv) - [🗄️ AmneziaWG on a Synology NAS (DSM)](#synology-adv) - [⚠️ Known Limitations](#limitations-adv) - [🤝 Contributing](#contributing-adv) - [💖 Acknowledgements](#thanks-adv) --- > For the full version history, see [CHANGELOG.en.md](CHANGELOG.en.md). --- ## ✨ Features (Detailed) * **AmneziaWG 3.1 by default:** header encryption (`HeaderProtectionKey`, a key of its own per install) and extra padding (`ContentPaddingAddition`) on top of junk packets, `S1`-`S4` padding and the `I1` concealment packet. AmneziaWG 2.0 is installed with the `--protocol=2.0` flag (for clients without 3.1) or automatically where the installer does not issue 3.1 (ARM, kernel older than 6.7): [details](#awg3-fallback-adv). * **Native key generation:** Keys are generated via `awg genkey/pubkey`, configs via Bash templates, QR codes via `qrencode`. The external Python/awgcfg.py dependency has been completely removed. * **Automated installation:** Installs AmneziaWG, DKMS module, dependencies, configures networking, firewall, and sysctl. * **Resume after reboot:** Uses a state file (`/root/awg/setup_state`) to continue after required reboots. * **Automated system optimization:** * Removal of unnecessary packages (snapd, modemmanager, etc.) * Hardware-aware swap and network buffer tuning * **Secure by default:** * `UFW`: Policy `deny incoming`, SSH rate-limiting, VPN port allowed. * `IPv6`: Disabled by default via `sysctl` (the prompt defaults to yes, `--yes` disables it without asking; keep it with `--allow-ipv6`). * `File permissions`: Strict permissions (600/700) on all keys and configs. * `Sysctl`: BBR congestion control, anti-spoofing, TCP optimization. * `Fail2Ban`: Automatic installation and SSH protection. * **Backup:** `backup` command in the management script (including client keys). --- ## 🔐 Obfuscation Parameters (3.1 and 2.0) These obfuscation parameters exist in both profiles, 3.1 and 2.0; only the lower bounds of `S3`/`S4` and the form of `H1`-`H4` differ (the "3.1 profile" column). The parameters that exist only in 3.1 (`HeaderProtectionKey`, `ContentPaddingAddition`) are in [The 3.1 profile](#awg3-not-yet-adv). All values are generated at install time and handed to clients exactly as they are on the server. The source of truth for the `manage` commands and for a reinstall is the live `/etc/amnezia/amneziawg/awg0.conf`; the copy of the set in `/root/awg/awgsetup_cfg.init` is used only when `awg0.conf` is absent, which normally means the first install. The `HeaderProtectionKey` is not written to the init: it lives in `awg0.conf` and in `/root/awg/server_hpk.key`. | Parameter | Description | 2.0 profile | 3.1 profile | Example (2.0) | |-----------|-------------|-------|-------|---------| | `Jc` | Number of junk packets | 3-6 | the same | `5` | | `Jmin` | Min junk size (bytes) | 40-89 | the same | `55` | | `Jmax` | Max junk size (bytes) | Jmin+50..Jmin+250 | the same | `200` | | `S1` | Init message padding (bytes) | 15-150 | the same | `72` | | `S2` | Response message padding (bytes) | 15-150, S1+56≠S2 | the same | `56` | | `S3` | Cookie message padding (bytes) | 8-55 | 12-55 | `32` | | `S4` | Data message padding (bytes) | 4-27 | 12-27 | `16` | | `H1` | Init message identifier | uint32 range | `1` | `134567-245678` | | `H2` | Response message identifier | uint32 range | `2` | `3456789-4567890` | | `H3` | Cookie message identifier | uint32 range | `3` | `56789012-67890123` | | `H4` | Data message identifier | uint32 range | `4` | `456789012-567890123` | | `I1` | CPS concealment packet | Tags `` / `--protocol=2.0, or where the installer picked 2.0 by itself (a stock Debian 12 with kernel 6.1, ARM) - gets the mark as expected. Removing it takes a 3.1 server, that is, a reinstall with every profile reissued, and all your clients have to understand 3.1.
--protocol=2.0: the second-line profile is a working path for it rather than a temporary compromise. On routers the third line comes from third-party projects: AWG Manager for Keenetic (v2.19.16 of 14 October 2026; with the stock module on KeeneticOS 5.2 Alpha 11 and later, on other firmware with its own kernel module or its bundled sing-box), awg-openwrt for OpenWrt (only the packages for OpenWrt 25.12.5 and 24.10.8, replaced on 22 September 2026 under the same tags, give the third line; ones downloaded earlier and packages for older OpenWrt do not), and for MikroTik and RouterOS amneziawg-mikrotik-c (v1.4.3 of 8 October 2026) and AmneziaWG-MikroTik. The table is in Which AmneziaWG generation a client speaks.
--protocol=2.0.
AllowedIPs: a full tunnel unlocks the feature, while a partial subnet list is treated as already split at the routing level, so the client hides its toggle with that message. The full-tunnel form it reliably recognizes is the pair 0.0.0.0/0, ::/0, and that is exactly what a default install hands out. The message shows up when the client was handed a subnet list instead of 0.0.0.0/0, ::/0: that is what the "Amnezia" mode (--route-amnezia), your own network list (--route-custom=) and an individual AllowedIPs set through modify all produce. Fix, no docker needed: switch the client to a full tunnel - replace the line in its .conf with AllowedIPs = 0.0.0.0/0, ::/0 and re-import, or re-issue the client in "All traffic" mode (--route-all). The split tunneling page in the app then opens and you pick sites/apps there. If you only need part of the traffic in the tunnel (a network-level split), AllowedIPs already does that - the app feature is not required for it.
I1 concealment packet (CPS) and hung on connect; this has not been rechecked on current versions of the app. Mobile (iOS/Android) and CLI clients handle CPS and connect fine. Install with the --no-cps flag: the installer drops I1 from the server config and all clients, and the desktop connects. Only the CPS layer is lost, the rest of the obfuscation (Jc/S1-S4/H1-H4, and on a 3.1 server the header encryption) stays. On an already-installed server it is the same via reinstall (which does not change the protocol generation): sudo bash install_amneziawg_en.sh --force --no-cps, then reissue existing clients sudo bash /root/awg/manage_amneziawg.sh regen (without this the client config still carries I1, and that is exactly what the desktop app chokes on). To re-enable CPS later, reinstall with any set-regeneration flag, e.g. --preset=default - note that this regenerates the WHOLE obfuscation set (H1-H4/S1-S4 too), so after re-enabling you need a regen of all clients again. The flag drops only I1: if you added I2-I5 manually, they stay in the configs. Issue #159.
ListenPort in /etc/amnezia/amneziawg/awg0.conf. 2. Change AWG_PORT in /root/awg/awgsetup_cfg.init. 3. Update UFW (sudo ufw delete allow <old_port>/udp, sudo ufw allow <new_port>/udp). 4. Restart the service (sudo systemctl restart awg-quick@awg0). 5. Regenerate ALL client configs (sudo bash /root/awg/manage_amneziawg.sh regen) and distribute them.
sudo bash ./install_amneziawg_en.sh --uninstall) and reinstall, specifying the new subnet during initial setup. A reinstall over a live server (--force) with a different subnet aborts while clients exist in the config - their addresses were issued in the old subnet.
MTU = 1280 is set automatically. To change it, stop the tunnel (sudo systemctl stop awg-quick@awg0) and edit the MTU = <value> line in the [Interface] section of /etc/amnezia/amneziawg/awg0.conf and in client .conf files. In the same awg0.conf, change the --set-mss values in the PostUp and PostDown lines: 40 less than the MTU for the iptables rules, 60 less for the ip6tables rules (if PostUp has them). For MTU 1200 that is 1160 and 1140. Otherwise large packets stop fitting into the tunnel and some sites open only now and then. Then start the tunnel: sudo systemctl start awg-quick@awg0. Stopping it before the edit lets the old MSS rules be removed with their old values. See MTU and Mobile Clients for details.
[Interface] section of the server config /etc/amnezia/amneziawg/awg0.conf. That file is the source of truth for manage: add and regen read the values for client configs from there. A reinstall (--force) takes them from there too, unless --preset/--mobile/--jc/--jmin/--jmax regenerate the set. A copy of the parameters (AWG_Jc, AWG_S1..S4, AWG_H1..H4, AWG_I1..I5) also lives in /root/awg/awgsetup_cfg.init, but it is used only when awg0.conf is absent, which normally means the first install: an edit made only there reaches neither the server nor the clients. manage warns when the init was changed after awg0.conf and their values disagree. The steps for a manual edit are in the next question. On a 3.1 server [Interface] also holds HeaderProtectionKey and ContentPaddingAddition, and the key has an extra copy in /root/awg/server_hpk.key.
[Interface] section of /etc/amnezia/amneziawg/awg0.conf; write the key names exactly as they are in the file.sudo systemctl restart awg-quick@awg0.sudo bash /root/awg/manage_amneziawg.sh regen. regen reads live values directly from awg0.conf..conf / QR codes / vpn:// URIs to clients.HeaderProtectionKey comes with a reinstall (--uninstall plus an install), and every profile is issued again.
--force --preset=default), followed by a regen of every client.
manage add/remove/list/--expires), with prebuilt ARM modules and a headless mode for automation.AS24940). Ordinary junk does not help; what gets through is an I1/CPS packet disguised as QUIC with an allowlisted SNI (7-zip.org for Hetzner). The method does not work on every ISP. Field results and instructions are in the Host Unreachable from Russia section.
--endpoint=<external_IP> flag during installation: sudo bash ./install_amneziawg_en.sh --endpoint=1.2.3.4. On an installed server, put the address into /root/awg/awgsetup_cfg.init (the line export AWG_ENDPOINT='1.2.3.4') and reissue the clients: sudo bash /root/awg/manage_amneziawg.sh regen. With AWG_ENDPOINT empty, regen detects the external IP itself.
--endpoint=EXTERNAL_IP. 3. Make sure the provider's firewall allows incoming UDP on that port.
modify command for each client: sudo bash /root/awg/manage_amneziawg.sh modify <name> DNS "8.8.8.8,1.0.0.1". Then regenerate configs: sudo bash /root/awg/manage_amneziawg.sh regen. The DNS for new clients is set by a CLIENT_DNS line in awgsetup_cfg.init, see Changing Default Settings.
sudo awg show. 2. Transfer stats: sudo awg show awg0 transfer. 3. Service logs: sudo journalctl -u awg-quick@awg0 -f. 4. Overall status: sudo bash /root/awg/manage_amneziawg.sh check.
s3, s4 or I1, it is older than the second line; if over HeaderProtectionKey or ContentPaddingAddition, it does not understand 3.1. Update the client: amneziawg-windows-client 3.1.0+ for a 3.1 server (2.0.0+ for a 2.0 server) or Amnezia VPN 5.0.1.5+ (4.8.12.7+ for 2.0). Other clients are in the table Which AmneziaWG generation a client speaks.
S3>0 or S4>0 (cookie / data padding from AWG 2.0), an AWG 1.0 client cannot handshake with it. This is a known upstream issue: amnezia-vpn/amneziawg-linux-kernel-module#168. My installer always generates both >0: S3=8..55 and S4=4..27 in the 2.0 profile, from 12 in the 3.1 profile.
.conf files generated by manage add) there is no issue: manage always writes S3 / S4 into the client .conf. The risk arises only when:
.conf files are hand-edited to remove S3 / S4;wg-quick on an older kernel without the amneziawg module);S3=0 / S4=0.S3 / S4 in the client .conf identical to the server. A real AWG 1.0 fallback is out of scope for the standard install — track upstream issue #168 for a fix.
dkms status. 2. Try rebuilding: sudo dkms install amneziawg/$(dkms status | grep amneziawg | head -1 | awk -F'[,/ ]+' '{print $2}'). 3. Make sure kernel headers are installed: sudo apt install linux-headers-$(uname -r). 4. If the error persists, run diagnostics: sudo bash ./install_amneziawg_en.sh --diagnostic.
apt upgrade of the kernel DKMS did not always rebuild the amneziawg module by the next reboot. Symptom: awg-quick@awg0 fails with modprobe: FATAL: Module amneziawg not found, and the VPN is down until manual recovery.
/etc/apt/apt.conf.d/99-amneziawg-post-kernel — after apt upgrade the helper /usr/local/sbin/amneziawg-ensure-module --hook rebuilds DKMS for the new kernel. Log: /var/log/amneziawg-ensure-module.log (weekly rotate, 4 copies).amneziawg-ensure-module.service — at boot, before awg-quick@awg0, the helper iterates kernels with already-installed headers, rebuilds DKMS for the current kernel, runs modprobe amneziawg, and verifies the load via lsmod. If headers are not yet installed, it logs a WARN and exits successfully so it does not block boot. Logs in journal: journalctl -u amneziawg-ensure-module.service.sudo bash /root/awg/manage_amneziawg.sh repair-module installs kernel-headers (with AWG_ALLOW_APT_IN_ENSURE=1), rebuilds DKMS, restarts awg-quick.sudo apt install linux-headers-$(uname -r) sudo dkms autoinstall sudo modprobe amneziawg sudo systemctl restart awg-quick@awg0Limitations:
.deb rather than DKMS - auto-repair is not engaged. After a kernel upgrade rerun the installer: it will pick a fresh prebuilt or fall back to DKMS. manage repair-module cannot replace a missing prebuilt module.uname -r suffix (e.g. linux-headers-azure). If you have a custom kernel or an unusual flavor, manage repair-module does the same in reactive mode.sudo bash /root/awg/manage_amneziawg.sh backup. 2. Copy the archive: scp root@old_server:/root/awg/backups/awg_backup_*.tar.gz .. 3. Install AmneziaWG of the same generation as the old server on the new one (for a 2.0 server, with --protocol=2.0): restore brings the server back to the generation of the backup and warns about that. A backup of a 3.1 server carries the header protection key too, so after the move clients need new configs only for the new address. If you want to move from 2.0 to 3.1 along the way, do not restore the backup; hand out new profiles to your clients instead. 4. Copy the backup: scp awg_backup_*.tar.gz root@new_server:/root/awg/backups/. 5. Restore: sudo bash /root/awg/manage_amneziawg.sh restore (interactive selection, or specify the full archive path). 6. Check what came over from the old server: the PostUp/PostDown lines in /etc/amnezia/amneziawg/awg0.conf carry the old machine's network interface name (-o eth0 and so on). If the new server names it differently (ip route get 1.1.1.1), replace the name and restart the service (sudo systemctl restart awg-quick@awg0). ListenPort must match the port open in UFW. If /root/awg/awgsetup_cfg.init sets AWG_ENDPOINT, put the new address there or leave it empty for auto-detection. 7. Regenerate configs with new IP: sudo bash /root/awg/manage_amneziawg.sh regen. 8. Distribute new configs to clients.
MTU = 1280 line in the [Interface] section of the server and client configs: the installer has set it by itself since v5.7.4, and older configs need it added (cellular networks have lower MTU than the default 1420, and iOS is strict about PMTU, see MTU and Mobile Clients). If the line is there and the handshake still does not complete on cellular, it is usually I1 or the port: see The handshake never completes on cellular, and for an unstable connection the next question. A client of a 3.1 server needs 3.1 support, see the client table.
0.0.0.0/5 range, which covers the reserved 0.0.0.0/8. The iOS kernel chokes on that block and never reaches the rest of the routes, so the tunnel comes up and then stalls after ~10 seconds (easy to mistake for DPI). Traced and fixed by @LiaNdrY (Issue #42). In v5.16.1 the first range is split into 1.0.0.0/8, 2.0.0.0/7, 4.0.0.0/6 - the same coverage without the problematic zero block, and private networks still stay outside the tunnel.
/root/awg/awgsetup_cfg.init and a plain --force reinstall does not change it (it is read back from the config). So: (1) quick per-client fix - replace the AllowedIPs = ... line in the iOS client config with AllowedIPs = 0.0.0.0/0; (2) keep the "Amnezia" mode list - edit /root/awg/awgsetup_cfg.init, replace the leading 0.0.0.0/5 with 1.0.0.0/8, 2.0.0.0/7, 4.0.0.0/6, then recreate the client (remove + add); (3) or a clean reinstall (--uninstall, then install v5.16.1) regenerates the list correctly.
I1 concealment packet decides the handshake, while the number and size of junk packets (Jc, Jmin, Jmax) do not affect it. If the connection is merely unstable, try the --preset=mobile flag (since v5.10.0): it sends fewer and smaller junk packets (Jc=3). In Discussion #38 (@elvaleto), on Tattelecom (Letai) with Jc=4-8 it took multiple attempts to connect, and after setting Jc = 3 it worked immediately.
sudo bash install_amneziawg_en.sh --preset=mobile --yesExisting install — manual edit:
/etc/amnezia/amneziawg/awg0.conf and change Jc to 3. If I1 looks like <r N> with N above 64, replace it with a DNS-shaped string (where to get one is in the diagnosis) or with <r 64>. Leave a DNS-shaped I1, written by installs of v5.33.0 and newer, as it is.sudo systemctl restart awg-quick@awg0sudo bash /root/awg/manage_amneziawg.sh regen <client_name> for each client.I1, see the diagnosis.
| Carrier | Parameters | Recommendation | Result |
|---|---|---|---|
| Tattelecom (Letai) | Jc=3, I1=<r 64> | --preset=mobile | ✅ |
| Yota (Moscow) | I1=<b 0xce...>, Jmax=261 | --preset=mobile | ✅ |
| Yota/Tele2 (Moscow) | Jc=3, Jmin=40, Jmax=70 | --preset=mobile | ✅ |
| Tele2 (Krasnoyarsk) | earlier I1=absent; May 2026: I1=<r 48> | --preset=mobile; in the May wave I1=<r 48> | ✅ |
| MTS (Primorsky Krai) | Jc=3, I1=<r 48> (May 2026) | --preset=mobile + I1=<r 48> | ✅ |
| MTS (Moscow) | a random I1=<r 96> and longer does not pass, <r 64> and a DNS-shaped I1 pass; Jc/Jmin/Jmax make no difference (measured, September 2026) | DNS-shaped I1 (written by the installer on fresh installs since v5.33.0) or <r 64>, see the diagnosis | ✅ |
| Beeline | default | --preset=default | ✅ |
| Megafon (Moscow) | Jc=3, Jmin=80, Jmax=268 | --preset=mobile | 🔄 testing |
| Megafon (regions) | I1=absent | --preset=mobile + remove I1 | ✅ |
| T-Mobile (Moscow and region) | narrow profile (like the Amnezia app): Jc=6, Jmin=10, Jmax=50, DNS-mimic I1=<r 2><b 0x8580...> (full value in the routers section below); full tunnel 0.0.0.0/0, ::/0 | manual parameters; the diagnose --carrier=tmobile_us profile (the name is historical, the profile is for this carrier) checks Jc/Jmin/Jmax and that I1 is binary; --preset=mobile does not fit here | ✅ |
| Tele2 + Megafon (Kemerovo, region 42) | random I1 (<r N>) stopped passing after 2+ days; works with QUIC-mimicry I1=<b 0xc3...> or I1=absent | --preset=mobile + I1=<b 0xc3...> (QUIC) or remove I1 | ✅ |
/etc/amnezia/amneziawg/awg0.conf and in client .conf files, remove the I1 = ... line entirely (do not leave it empty). This is a mode without the concealment packet: the rest of the obfuscation stays, there is just no CPS (unless you set I2-I5), and the handshake clears DPI at some regional carriers where CPS packets themselves trigger blocks (Issue #42, @alkorrnd). On the server: sudo systemctl restart awg-quick@awg0. On clients - sudo bash /root/awg/manage_amneziawg.sh regen <name> for each, then redistribute the configs.
I1=absent option stopped working on Tele2 (Krasnoyarsk), while a short I1 = <r 48> cleared DPI. The same worked on MTS (Primorsky Krai). At the time this was put down to size: a smaller value <r 48> may be less conspicuous to DPI. ⚠️ The September 2026 measurement refines the cause: what decides is the SHAPE of the packet, not its size. A packet of random bytes is dropped whether it is large or small (small ones just less often), while a packet of the same length that resembles a real protocol gets through. A short <r 48> helps because there is little for the filter to catch on to in a short piece of noise, and that is weaker than a meaningful shape. Details and the table: the handshake never completes on cellular. If --preset=mobile or I1=absent do not help - try I1 = <r 48>. The diagnose --carrier=tele2_krasnoyarsk profile still reflects the earlier I1=absent (Issue #42), so for the May 2026 wave set I1 = <r 48> manually (Discussion #38, @alkorrnd + @etotent).
<r N> you can set I1 as a block that mimics the start of a QUIC packet: I1 = <b 0xc30000000108><r 8><b 0x08><r 8><b 0x0045dc><t><r 16>. The first bytes (0xC3 + version) look like a QUIC v1 long-header, and DPI that classifies UDP/443 as QUIC let the flow through in this report. It held for 2+ days on Tele2/Megafon (Kemerovo) (Issue #42, @Fourdot-co). This is a client-side parameter, changed only in client .conf files, no server sync needed; mind that editing just one exported .conf will be lost on the next client regen. Note: do not base it on a TLS ClientHello (<b 0x160301...>) - that is a TCP format, over UDP the DPI will see the TCP structure and drop the packet. For UDP mimicry use a QUIC long-header or DTLS (the same ClientHello handshake type, but with a record header that adds epoch and sequence number).
net.ipv4.conf.all.rp_filter = 1 (strict reverse-path filtering). On Hetzner and similar cloud hosters where the gateway is in a different subnet than the VPS IP, strict mode breaks routing — reply packets fail the reverse-path check. Symptoms: VPS periodically loses network (once a day), and the VNC console fills with [UFW BLOCK] lines from Fail2Ban, making it unusable. Discussion #41 (@z036). As of v5.8.2 rp_filter is set to 2 (loose mode), which validates source IP against any route in the table (not just the same interface), and kernel.printk = 3 4 1 3 is added to suppress non-critical kernel messages on the VNC console. If you are on a pre-v5.8.2 install — fix manually:
/etc/sysctl.d/99-amneziawg-security.confrp_filter = 1 to rp_filter = 2 (both lines: conf.all and conf.default)kernel.printk = 3 4 1 3sudo sysctl -p /etc/sysctl.d/99-amneziawg-security.confping does not work between server and clients inside the tunnelufw default deny incoming — this blocks all incoming traffic on every interface, including awg0. The forward rule ufw route allow in on awg0 out on <public_iface> only allows tunnel → internet; input on awg0 (packets from clients to the server itself, including ICMP echo-request) is not covered by it.
/etc/ufw/before.rules and replaced ACCEPT with DROP for ICMP without specifying an interface, those rules apply to every interface — including awg0.
awg0 in UFW:
sudo ufw allow in on awg0 sudo ufw reloadThis allows all incoming on the tunnel interface — narrow ICMP filtering is done via
-i in before.rules (see below).
/etc/ufw/before.rules, add -i <public_iface> to every ICMP DROP line:
# instead of -A ufw-before-input -p icmp --icmp-type echo-request -j DROP # use (ens3 — your public iface) -A ufw-before-input -i ens3 -p icmp --icmp-type echo-request -j DROPSame for
destination-unreachable, time-exceeded, parameter-problem. Find your public interface name: ip route get 8.8.8.8 | awk '{for(i=1;i<=NF;i++) if($i=="dev") print $(i+1)}'. Apply: sudo ufw reload.
ufw allow in on awg0 proto icmp — UFW does not support icmp via the proto flag (only tcp/udp/esp/ah/gre/ipv6).
ping <server_tunnel_IP>. From the server to a client (ping <client_IP>) the client itself may not reply: on Windows and iOS the built-in firewall often drops echo-request — testing client → server is the cleanest path.
AllowedIPs on the client for split tunneling (only some subnets go through the VPN - e.g. only Telegram/Discord, everything else stays direct), make sure the tunnel subnet (10.9.9.0/24 or your custom one) is in that list. Without it, the client does not route through the tunnel even packets destined for the server itself - ufw status verbose and iptables -L ufw-before-input -v -n can look correct, and ping still fails. Coverage depends on the routing mode chosen at install time: the default --route-all (full tunnel 0.0.0.0/0) includes the tunnel subnet automatically; --route-amnezia (Amnezia List, excludes 10.0.0.0/8) and --route-custom= do not, add it explicitly.
sudo ufw route allow in on awg0 out on awg0 && sudo ufw reload. AllowedIPs in client .conf depends on the routing mode chosen at install (see the paragraph above). Discussion #63.
amneziawg-go userspace implementation inside LXC, set up by hand: LXC / Docker via amneziawg-go.
--endpoint is rejected with "Invalid --endpoint" — what should I check?--endpoint is validated before it is written to config files. Three formats are accepted: FQDN (vpn.example.com), IPv4 (1.2.3.4), and bracketed IPv6 ([2001:db8::1]). Newlines, CR, single and double quotes, backslash, spaces, and tabs are rejected — they could inject lines into awgsetup_cfg.init and client .conf files. IPv6 addresses must be wrapped in []. If AWG_ENDPOINT in awgsetup_cfg.init fails validation on a later run, the installer emits log_warn and falls back to automatic detection via get_server_public_ip.
flock on /root/awg/.install.lock at the beginning of initialize_setup(). This prevents two parallel runs from racing each other on apt-get and corrupting package state. If you see this error but no second installer is actually running (hung / crashed process), remove /root/awg/.install.lock and try again.
--uninstall not disable UFW?/root/awg/.ufw_enabled_by_installer only if it had to enable UFW itself (UFW was in inactive state before the install). During --uninstall, UFW is disabled only when that marker is present. If UFW was already active on the VPS before this script was installed (for example, protecting SSH or web services), --uninstall will remove our own rules (VPN port, awg0 routing; the SSH rate-limit rule it added stays in place) but leave UFW running. This protects your firewall posture from destructive uninstall on a VPS that was already hardened. If you want to force UFW off anyway — run ufw disable manually.
regen says "required AWG parameters missing" — what do I do?load_awg_params reads AWG parameters directly from the live /etc/amnezia/amneziawg/awg0.conf instead of the cached awgsetup_cfg.init. If you edited awg0.conf by hand and accidentally removed or corrupted one of the required fields (Jc, Jmin, Jmax, S1-S4, H1-H4), regen will fail with this error instead of silently using stale values from the init file. This is split-brain protection between server and clients. How to fix: (1) check that all 11 fields are present with grep -E "^(Jc|Jmin|Jmax|S[1-4]|H[1-4]) = " /etc/amnezia/amneziawg/awg0.conf; (2) if a field was removed, restore it from /root/awg/awgsetup_cfg.init or from an awg0.conf.bak-* backup; (3) restart the service and retry regen. On a 3.1 server regen then also checks the HeaderProtectionKey in awg0.conf against its copy /root/awg/server_hpk.key; if the error is about the key, do not create a new one (it would cut off every client). awg0.conf holds the key configured for the server (the running interface picks up an edit of it only after a restart), and the file holds the key the profiles were issued from. If they differ, decide which one your clients have: compare with any client .conf. If the key in awg0.conf is right, move the file aside (mv /root/awg/server_hpk.key /root/awg/server_hpk.key.old) and run manage regen: manage restores a missing file from the config by itself. If the key in the file is right, put it back into the HeaderProtectionKey line of awg0.conf and restart awg-quick@awg0 (or restore the config with manage restore, keeping in mind the backup may predate your newest clients).
amneziawg-windows-client underlines H2-H4 in red and will not let me edit the configamneziawg-windows-client (a wireguard-windows fork with AWG patches). Its built-in config editor in ui/syntax/highlighter.go caps H1-H4 at [0, 2147483647] (2^31-1, INT32_MAX), even though the AmneziaWG spec allows the full uint32 (0-4294967295). Values above 2^31-1 work fine on the server, but the client underlines them as invalid and may block saving. Upstream issue: amnezia-vpn/amneziawg-windows-client#85 (open since February 2026, not yet fixed). As of v5.8.1 our installer generates H1-H4 in the safe half of the range [0, 2^31-1] — fresh installs are compatible with the Windows client out of the box. If you already have a v5.8.0 install with "bad" H values: (1) upgrade via --uninstall + reinstall with v5.8.1 — new H values will be in the safe range; or (2) manually edit H2/H3/H4 in awg0.conf to values less than 2147483647, restart the service, and regenerate client configs with manage regen <name>; or (3) use the cross-platform Amnezia VPN client instead of amneziawg-windows-client — it does not have this limit. Discussion: #40.
<name>.png with their own scanner, reconnected in under a second and kept the tunnel when the phone moved from Wi-Fi to mobile data. On iPhone, Mac and Windows, the lightweight AmneziaWG for your platform (for 3.1: iOS and macOS >= 3.1.4, Windows >= 3.1.0); iPhone and Mac were not part of that check. Amnezia VPN (>= 5.0.1.5 for 3.1, >= 4.8.12.7 for 2.0) is supported too and accepts the vpn:// link; on Android in the same check, version 5.0.3 took about 2 seconds to connect, and after Wi-Fi was switched off the tunnel did not recover, not even with the Connect button, until the app was restarted. On Linux, awg-quick from amneziawg-tools with a module or amneziawg-go that understands the server's generation (for a 3.1 server, the third line; a third-line build works with 2.0 too), see Connecting a Linux machine as a client. The standard WireGuard client does not support AWG parameters. See Client Compatibility for the full table.
S4 padding (0) instead of the configured one, and the server drops it (amneziawg-go#168; a fix is proposed in #184 and is not merged as of 13 October 2026). Losing the first packet usually means a TCP or DNS retry, so a delay; if the application does not retry, the request can time out. WG Tunnel is built on its own fork of that engine; whether the fork has this race we did not check. On its own this race does not point to a problem in the config or on the server.
tc (traffic control): sudo tc qdisc add dev awg0 root tbf rate 100mbit burst 32kbit latency 400ms. This limits total interface throughput. For per-client limits, a more complex setup with tc and iptables (mark + class) is required.
uname -r vs ls /lib/modules/. If they differ, update your kernel: sudo apt update && sudo apt upgrade, reboot, and re-run the installer.
Prebuilt installed in the install log (/root/awg/install_amneziawg.log); the Russian installer writes Предсобранный пакет установлен. If it is not there, the module was built with DKMS: on the fallback the log says falling back to DKMS build.