* docs(cascade): bundle ru.zone snapshot as offline fallback awg-routing.sh now tries ipdeny -> repo snapshot (cascade/ru.zone via raw.githubusercontent) -> local last-good, so a fresh server where ipdeny is blocked still brings the cascade up instead of hard-failing. Add cascade/ru.zone (ipdeny ru-aggregated snapshot, 2026-07-06, 8626 networks) + cascade/README.md with attribution and refresh steps. Also clean the temp list file via a trap on exit. * Release v5.18.4: cascade offline fallback + onlink route retry Bump version to 5.18.4 across the 6 scripts, refresh the 4 helper SHA pins, bump the pinned install URLs and the version badge, and add the changelog entry (RU + EN). Cumulative since v5.18.3: bundled cascade/ru.zone snapshot as an offline fallback for awg-routing.sh, onlink route retry for out-of-subnet-gateway VPS (#158), DeepWiki wiki.json + badge (#161), CI setup-qemu 4.1 -> 4.2 (#157).
146 KiB
RU Русский | EN English
Changelog
All notable changes to this project are documented in this file.
The format is based on Keep a Changelog.
Unreleased
5.18.4 - 2026-07-06
v5.18.4 - cascade reliability and documentation. Cascade split-routing now survives ipdeny being unreachable: a snapshot of the Russian network list (cascade/ru.zone) is bundled in the repository, and the awg-routing.sh script uses it when www.ipdeny.com is blocked by the provider and no local copy exists yet - previously a fresh server in that situation would not bring the cascade up at all. The script also gained a workaround for the route error on VPSes whose default gateway sits outside the server subnet (Hetzner Cloud and similar with a /32 interface). The installer itself is functionally unchanged, so existing installs do not need updating. Support matrix unchanged: Ubuntu 24.04 / 25.10 / 26.04, Debian 12 / 13, x86_64 + ARM.
Documentation
- Cascade: bundled a snapshot of Russian networks
cascade/ru.zone(ipdeny aggregated zone, snapshot 2026-07-06, 8626 networks) as a fallback source. The order inawg-routing.shis now: ipdeny (the live list) -> the repo snapshot overraw.githubusercontent.com-> the previous local list; it aborts only if all three are unavailable. This brings the cascade up on a fresh server even when ipdeny is blocked (from Discussion #120) - Cascade:
awg-routing.shretries adding the route to the exit server with theonlinkflag when the default gateway sits outside the server subnet - otherwise on VPSes like Hetzner (real public IP on a/32interface, private gateway) the route failed withError: Nexthop has invalid gateway(#158, Discussion #120) - Added a
cascade/README.mdnote for the snapshot (source, date, how to refresh) and an Ask DeepWiki badge in both READMEs for quick code navigation (#161)
Infrastructure
- CI: bumped
docker/setup-qemu-actionfrom 4.1 to 4.2 in the ARM package build (#157)
5.18.3 - 2026-07-02
v5.18.3 - convenience and documentation. Confirmation prompts (for example, when removing a client or enabling UFW) now accept not only y but also yes in any case and with stray surrounding whitespace. UFW is enabled more reliably via ufw --force enable, so on some systems the firewall is no longer left disabled. The docs gain the T-Mobile (Moscow) mobile carrier and a Keenetic Speedster router note. Existing installs are unaffected. Support matrix unchanged: Ubuntu 24.04 / 25.10 / 26.04, Debian 12 / 13, x86_64 + ARM.
Fixed
- Confirmation prompts accept
yes, not onlyy. Previouslyconfirm_action(inmanage) and five installer prompts (reboot, unsupported OS, low disk space, UFW enable, backup on removal) matched a bareyonly, and answeringyesread as "no". They now accepty/Y/yes/YESwith any surrounding whitespace (issue #154) - UFW is enabled via
ufw --force enable. The old approach (feedingyintoufw enable) silently left the firewall off on some systems - only--forcehelped, and the installer now uses it directly (issue #154)
Documentation
- Added T-Mobile (Moscow) to the mobile carrier table: a narrow app-style profile (Jc=6, Jmin=10, Jmax=50 + DNS-mimic I1 + full tunnel); the
diagnose --carrier=tmobile_usprofile checks Jc/Jmin/Jmax and that I1 is binary-shaped (Discussion #45) - Added a Keenetic Speedster (firmware 5.0.6) router note: older firmware does not parse H1-H4 as ranges (
invalid H1), needs concrete values and calmer junk, with a userspace AWG Manager workaround (Discussion #81) - Added a diagnostics tip: the ByeByeVPN scanner helps tell whether a carrier blocks the server IP itself, separating an obfuscation issue from an AS/IP-level block
5.18.2 - 2026-07-01
v5.18.2 - installation robustness. On fresh Ubuntu servers the built-in unattended-upgrades often holds the dpkg lock for several minutes on first boot, which made the installer fail at the system-update step with an apt full-upgrade error. The installer now waits for the lock to be released instead of failing immediately. Existing installations are unaffected. Support matrix unchanged: Ubuntu 24.04 / 25.10 / 26.04, Debian 12 / 13, x86_64 + ARM.
Fixed
- A fresh-server install no longer aborts when the
dpkglock is busy. At the start of step 1 the installer setsDPkg::Lock::Timeout(via/etc/apt/apt.conf.d), so everyaptcall waits for the lock thatunattended-upgrades/apt-dailyhold on first boot. Ifapt full-upgradestill does not go through, the installer logs the process holding the lock, runsdpkg --configure -aand retries, and on a repeated failure exits with a clear message and recovery steps (issue #150)
5.18.1 - 2026-06-27
v5.18.1 - bug-fix release. Fixes --port on reinstall: install --force --port=N now actually changes the server port (previously the new port was silently ignored). Full-tunnel clients now get 0.0.0.0/0, ::/0 so AmneziaVPN on iOS accepts the "all traffic" mode. The default DNS is now a resolver pair 1.1.1.1, 1.0.0.1. --port now accepts any port 1-65535, including 443 (useful for mobile carriers that drop a non-standard high UDP port). Plus documentation fixes. Behaviour of existing installs and connected clients is unchanged; the improvements apply to new and re-issued (manage regen) configs. Support matrix unchanged: Ubuntu 24.04 / 25.10 / 26.04, Debian 12 / 13, x86_64 + ARM.
Fixed
install --force --port=Nnow changes the server port. Previously the new port was silently ignored: when rendering the server config, the port was re-read from the oldawg0.conf, overwriting the value passed via--port. The port for the new config is now taken from the saved install parameters (the user's intent), which correctly survives the reboots during--force. Clientregenis unaffected - it still reads the port from the liveawg0.conf- Full-tunnel clients (
AllowedIPs = 0.0.0.0/0) now get0.0.0.0/0, ::/0. With a bare0.0.0.0/0, AmneziaVPN on iOS treated the config as incomplete split tunneling and refused to bring the tunnel up.::/0sends IPv6 into the tunnel (and drops it if the server has no native IPv6), so nothing leaks past the VPN. Split tunneling (a custom route list) is not affected
Changed
- The default DNS in client configs is now a pair
1.1.1.1, 1.0.0.1instead of a single resolver (a fallback DNS in case the first one is unreachable) --portnow accepts ports 1-65535 (previously only 1024-65535). Low ports like 443/80/53 help with DPI evasion on mobile carriers: MTS, for example, drops a non-standard high UDP port but passes 443/udp. The VPN service runs as root, so privileged ports bind fine
Documentation
- ADVANCED: fixed the
S3/S4range in the minimal-config example (S3: 0-64,S4: 0-32 instead of the wrong 0-127); removed the stale link of the active-probing section to the already-closed issue #71; added notes on the mobile port and on direct IPv6 traffic bypassing the tunnel - README: added Ubuntu 26.04 to the subtitle; clarified the
--forcegate in the re-run FAQ
Tests
- Added
tests/test_v5181_bugfix.bats- the port from the saved parameters wins over the oldawg0.confon render; a full-tunnel client gets::/0, a split one does not; the default DNS pair; RU/EN parity of all three fixes
5.18.0 - 2026-06-26
v5.18.0 - the special-junk params I2-I5 now reach clients. Previously only I1 made it into the client config; I2-I5 were hard-coded empty in the vpn:// URI and never rendered into the .conf, so even if the admin set them in awg0.conf they could not reach the client. Now all five CPS params are carried into the client .conf, the QR code, and the vpn:// link. Workflow: set I2-I5 in the [Interface] of awg0.conf, restart the service, and distribute to clients with manage regen. No new install flags; when I2-I5 are unset, behavior is identical to before. Support matrix unchanged: Ubuntu 24.04 / 25.10 / 26.04, Debian 12 / 13, x86_64 + ARM (issue #71).
Added
- Pass-through of
I1-I5(not justI1) from the serverawg0.confinto client configs on generation andregen: the live-config parser readsI2-I5, the client.confrender appends the set values, and the previously hard-coded emptyI2-I5in thevpn://URI are replaced with the real ones. Values are carried verbatim; the admin picks the tag format (<r N>,<b 0xHEX>,<c>,<t>) - see the VoidWaifu list.I2-I5are optional and independent: unset ones are simply not emitted - The params inherit the same preservation semantics as the rest of the obfuscation:
--forcewithout--preset/--jc/--jmin/--jmaxreadsI2-I5from the liveawg0.confand keeps them;--preset/--jcregenerate the whole obfuscation set, which drops manually setI2-I5(same asH1-H4/S1-S4/I1)
Tests
- Added
tests/test_v5180_i2i5_passthrough.bats- parsingI2-I5fromawg0.conf, anti-stale protection across calls, client.confrender (present when set, absent when empty), and a realvpn://decode (values present in both the structured fields and the embedded raw config), plus RU/EN parity of every touched site
5.17.0 - 2026-06-24
v5.17.0 - the server firewall now clamps the TCP MSS to the tunnel MTU so large pages and downloads no longer hang on paths that filter ICMP (mobile carriers, double-NAT, two-server cascade). The install behavior is otherwise unchanged; update an existing server by re-running the installer. Support matrix unchanged: Ubuntu 24.04 / 25.10 / 26.04, Debian 12 / 13, x86_64 + ARM.
Added
- MSS/PMTU clamp in the server config PostUp/PostDown: a
TCPMSS --set-mssrule in themangletable'sFORWARDchain caps the advertised TCP MSS to a tunnel-safe value in both directions (-o %iand-i %i). This removes the PMTU blackhole - when ICMP "Fragmentation needed" is filtered along the path, oversized TCP segments with DF set are silently dropped at the 1280 tunnel and the page or download stalls. A common complaint on mobile carriers, behind double-NAT, and in cascade setups - The MSS value is derived from
AWG_MTUwhen the config is generated (IPv4: MTU-40 = 1240, IPv6: MTU-60 = 1220); a manual MTU change is picked up by re-running the installer with--force. IPv6 rules are only added when the IPv6 tunnel is enabled. It complements the existing conservativeMTU = 1280rather than replacing it
Tests
- Added
tests/test_v5170_mss_clamp.bats- asserts the rules in both directions, the mirrored-Din PostDown, IPv6 gating, and MSS auto-derivation fromAWG_MTU
5.16.1 - 2026-06-16
v5.16.1 - hotfix: iOS tunnel drop on the default routing mode (Issue #42). The default install behavior is otherwise unchanged. Support matrix unchanged: Ubuntu 24.04 / 25.10 / 26.04, Debian 12 / 13, x86_64 + ARM.
Fixed
- iOS: on the default routing mode (mode 2, "Amnezia List + DNS") the tunnel came up but traffic stopped after ~10 seconds (easy to mistake for DPI). The AllowedIPs list started with the
0.0.0.0/5range, which covers the reserved0.0.0.0/8; the iOS kernel chokes on that block and never reaches the rest of the routes. The first range is split into1.0.0.0/8, 2.0.0.0/7, 4.0.0.0/6- the same coverage without the problematic zero block, and split-tunnel is preserved. Traced and fixed by @LiaNdrY (Issue #42) - The
--expireserror message now lists30damong the valid formats (matching--help)
Documentation
- README and ADVANCED (RU + EN): added an FAQ entry about the iOS drop with instructions for already-installed servers (before v5.16.1)
- Cascade (CASCADE.md / CASCADE.en.md): the client config example now uses this installer's default Endpoint port
39743(was51820from upstream WireGuard); the troubleshooting section no longer references a nonexistentafter-awg1.confdrop-in - the autostart check now points at theawg-routing.serviceunit; removed a duplicated paragraph in step 1 - Full documentation audit: fixed minor inaccuracies (a duplicated pointer line in ADVANCED.en.md, an install-link anchor mismatch between README RU and EN, the import-files wording in INSTALL_VPS.md)
CI
- The ShellCheck workflow ("Lint and syntax check") is no longer path-filtered: the required status check now runs on docs-only PRs too, so it no longer blocks them (previously needed an admin override)
Tests
- Added
tests/test_v5161_ios_allowedips.bats- a structural guard against the mode-2 list reverting to0.0.0.0/5
5.16.0 - 2026-06-12
v5.16.0 - security and reliability hardening from a full code audit. This release closes the findings of a full review of all six scripts of the AmneziaWG 2.0 VPN installer for Ubuntu and Debian: it eliminates the peer-loss window on --force reinstall, removes secrets from process argv, pins the PPA GPG key by full fingerprint, makes the AWG parameter validator check H1-H4 non-overlap, and stops expired orphan clients from looping the cron job forever. The default install behavior is unchanged. Support matrix unchanged: Ubuntu 24.04 / 25.10 / 26.04, Debian 12 / 13, x86_64 + ARM.
Security
- The temp-file registry moved from world-writable
/tmpinto$AWG_DIR(0700): a predictable name in/tmpwould let a local user plant a list of arbitrary paths that cleanup would then delete as root; registry reads are additionally guarded against symlink swaps - Private keys (client and server) are now born with 0600 permissions via
umask 077- the brief world-readable window between write andchmodis gone; thekeys/directory is created with 0700 - The client private key and PSK are passed to the perl vpn:// URI generator via environment variables instead of argv (a process command line is visible to all users in
/proc/<pid>/cmdline) - The Amnezia PPA GPG key is requested by its full 40-character fingerprint instead of the short 32-bit ID (short IDs have known evil32 collisions) and is verified against the pin after download
uninstallno longer purges thefail2banpackage if it was installed before our installer (the.fail2ban_installed_by_installermarker, symmetric to the UFW marker); a user-owned fail2ban is restarted without our jailuninstallremoves only the exact lines written by legacy versions of this installer from/etc/sysctl.confinstead of any line containingdisable_ipv6(it could previously wipe user-added settings)- Library functions
generate_client/add_peer_to_server/remove_peer_from_server/regenerate_clientnow validate the client name themselves (defense-in-depth for cron and third-party scripts sourcing the library)
Fixed
- Step 6: existing [Peer] blocks are now carried over inside a single atomic write of the server config (
render_server_configappends peers before themv). Previously a crash between render and the separate append left the config without peers, and a re-run of the step backed up the already peer-less file - all clients were lost on--forcereinstall remove_peer_from_serverchecks the awk exit code and the presence of[Interface]in the result before replacing the server config - an awk failure on a full disk can no longer atomically replace a working config with a broken one- An expired client whose peer was already removed from the config manually or by a restore (an orphan expiry label) is now cleaned up properly: previously cron retried the failing removal every 5 minutes forever and the client artifacts were never reclaimed
regenrecovers the PresharedKey from the server config when the client.confis lost - previously the recreated config came out without a PSK while the server peer still had one, silently breaking the handshake- The public IP detection cache actually works now (file-based, survives subshells): previously the assignment inside
$(...)was lost, soregenover all clients performed a full curl round (up to 6 services, 5 s each) per client validate_awg_configchecks pairwise non-overlap of the H1-H4 ranges (the key AWG 2.0 invariant) and parses parameters the same way the loader does: arbitrary whitespace around=, last-wins on duplicates - a hand-editedJc=4no longer produces a false "parameter not found"- H1-H4 generation guarantees a strict gap between ranges (boundary touching is excluded) and a lower bound >= 5 (values 1-4 are reserved by the WireGuard protocol)
--apply-modeis validated at argument parse time: a typo like--apply-mode=restratused to silently behave assyncconf--diagnosticchecks for root before doing anything (previously it failed on every log write under a regular user and exited with a false success)- Debian 12: the PPA suite-mismatch repair now also covers the traditional
.listformat (previously only DEB822.sourceswas handled) - Step 2: the early apt update is now tolerant to Amnezia PPA errors - a leftover PPA file with a broken suite (404 Release) no longer kills the install BEFORE the repair logic runs (live repro on Debian 12); base repository errors remain fatal
check: when the port cannot be determined, the UFW rule check is skipped (previously it printed a meaningless warning about0/udp)list: a corrupted expiry file no longer causes a bash arithmetic error in the tablegenerate_vpn_uriverifies the port is numeric before generating the URI (an empty port produced syntactically broken JSON that Amnezia Client silently refused to import)- The public-IP detection error message in
manage addno longer suggests the--endpointflag that manage does not have
Improved
- Installer steps 1-2 no longer re-run
apt-get updatewithout a sources change (saves 10-60 seconds per run on slow mirrors, up to two redundant runs per install) backupadditionally takes the config lock: a paralleladd/removecan no longer produce a desynchronized file set inside the backup- Interactive port and subnet prompts during install re-ask on a typo instead of aborting the whole installation
- Reinstalling with
--preset/--jc/--jmin/--jmaxprints an explicit warning that the ENTIRE obfuscation parameter set is regenerated and existing client configs will needregen(the idempotency-guard message was clarified too) setup_fail2banwarns when UFW is inactive (bans withbanaction=ufware effectively inert in that case)- The
apt-get updateerror classification ignores known informational linesW: Target ... is configured multiple timesandW: ... legacy trusted.gpg- they no longer turn a tolerable failure into a false fatal diagnosemakes oneawg showcall instead of four;statsno longer spawnsdateper peer;list --jsondoes not read expiry files (the field is not part of the JSON output)- The expiry cron job runs the temp-file cleanup (fixes a registry-file leak on every firing)
- The random number generator fallback (when
/dev/urandomis unavailable) covers the full 31-bit range instead of 30 bits managehelp:regendocuments accepting multiple names,repair-modulelists itsrepairalias; the client-creation message mentions.pngonly when the QR was actually created- Dead code removed: the unreachable
help)dispatcher branch in manage, the unreachablereturnafterrequest_rebootin the installer, two redundantAWG_APPLY_MODEre-exports, stale shellcheck directives - CI/release scripts:
update-sha-pins.shpreserves file permissions on rewrite;build-arm-deb.shsurfaces xz stderr on failure;build-release-notes.shvalidates the version format before interpolating it into awk
5.15.6 - 2026-06-08
v5.15.6 - input validation, atomicity and a JSON status field. This release continues the code-audit hardening cycle: it sharpens input validation in manage, makes client-artifact writes atomic, refines interrupt handling, and adds a stable machine-readable status_code to list/stats --json. The default install is unchanged. Support matrix unchanged: Ubuntu 24.04 / 25.10 / 26.04, Debian 12 / 13, x86_64 + ARM.
Added
list --jsonandstats --jsonnow emit an extrastatus_codefield with a stable, language-independent value (active|recent|inactive|no_handshake|key_error|no_data). The existing localizedstatusfield is kept - the change is additive and backward-compatible, and convenient forjqand automation (the contract is documented inADVANCED.en.md)
Improved
manage modify <client>validates each DNS entry as a real IPv4/IPv6 address (via the shared_valid_ipv4/_valid_ipv6helpers) rather than a character set, so values likeabcor999.999.999.999are no longer accepted. The same octet-range check (0-255) now applies to the auto-detected server public IP--expiresduration is validated once before the client is created: an invalid value aborts the command up front without changing anything. A failure to write the expiry after creation is now reflected in a non-zero result and the log--pskis treated as an explicit request for a key: if the PSK cannot be generated, the command fails instead of silently degrading to a PSK-less client, and no artifacts are created.vpnuriand the temporary QR PNGs are written through the shared safe-temp mechanism with an atomicmv, so an interrupted write cannot leave an empty or truncated file over a working one. Client removal (manual and automatic on expiry) uses one shared helper that covers every client artifact- The expired-client auto-removal cron is compared by content and refreshed when the working directory changes (for example after a restore), not only when the file is absent
- Restore checks for the server config before stopping the service (an interruption no longer touches a working system), and an empty clients directory is treated as a valid case
- Ctrl+C or a termination signal now aborts the script with the correct exit code (130/143) instead of continuing past the interrupted operation; an interrupted restore still rolls back
Documentation
- Installer built-in help and the option tables in
ADVANCED.en.md:--endpointaccepts an FQDN, IPv4 or[IPv6]; clarified that--no-tweaksstill applies the minimal forwarding sysctl - The command tables in
README.en.mdnow includediagnoseandrepair-module - ARM support for Ubuntu 26.04 (built via DKMS) is documented; the OS / architecture / prebuilt-package matrix is now checked automatically for consistency
Tests
- Expanded automated coverage (bats): input validators, file-operation atomicity, signal handling, and the
status_codecontract
5.15.5 - 2026-06-07
v5.15.5 - fail2ban bugfix on Ubuntu 24.04 (thanks @stereomonk).
Fixed
- fail2ban failed to start on minimal Ubuntu 24.04 without rsyslog ("Have not found any log file for sshd jail"): the sshd jail now uses
backend = systemdon Ubuntu as well, matching Debian since v5.7.12 (PR #106, thanks @stereomonk) - fail2ban status after restart is now checked honestly:
systemctl restartreturns 0 even when the service dies right after start, so the installer used to report success on a crashed service. The state is now verified viasystemctl is-active(PR #106)
5.15.4 - 2026-06-06
v5.15.4 - a companion release: a new documentation section on a host being unreachable from Russia (autonomous-system blocking) and the I1/CPS workaround, plus housekeeping. The default install behavior and the support matrix are unchanged.
Documentation
- ADVANCED: a new section on host blocking by autonomous system (AS). It covers the symptom (the handshake completes, then traffic stalls), the AS-level cut on the operator's network, and the workaround via I1/CPS QUIC mimicry with an allowlisted SNI. The section includes field observations across several operators and links to the relevant discussion (Issue #71).
Internal
- Two bats test names were converted to ASCII. The full suite of 790 checks now also runs under bats on Windows (two tests with non-ASCII names were previously skipped there); the Linux CI always ran the full suite.
5.15.3 - 2026-06-04
v5.15.3 - a hardening release following four rounds of external code and documentation audits. No new features: it tightens the installer's input validators, fixes a number of correctness issues in manage, and hardens file-operation atomicity and the release process. A default install is unchanged. Support matrix unchanged: Ubuntu 24.04 / 25.10 / 26.04, Debian 12 / 13, x86_64 + ARM.
Fixed
- Early installer validators now match the canonical ones. The step-0 checks for port, subnet, endpoint and CIDR lists (before the shared library is downloaded) now reject ports with leading zeros (
0080is no longer accepted via octal interpretation), numbers longer than 5 digits (64-bit overflow guard), non-canonical subnet octets, edge-case bracketed IPv6 endpoints ([:::], double::), and newlines or empty items in route lists. --route-customis validated on the first run regardless of where the value came from: an invalid route list stops the install before the configuration is written.- An unknown command-line argument exits the installer with code 1 (it used to print help and exit 0); an explicit
--helpstill returns 0. manage restoreis robust against incomplete backups: restoring from an empty key set or a truncated backup no longer removes live clients.- Re-running the installer keeps all existing peers and the default clients when regenerating the server config.
manage modifyvalidates IP and CIDR values by range, not just by shape.- File-operation atomicity: config temp files are created on the destination filesystem (so
mvis actually atomic), the client QR PNG is written via temp +mv, and temp cleanup, comma validation in lists, andvpn://URI QR generation were tightened.
Internal
- Reproducible ARM builds: the upstream module is pinned to an explicit ref, and a build manifest is published alongside the packages.
release.ymlbuilds bilingual release notes (RU + EN from both changelogs) and a descriptive release title automatically.- Preflight and CI hardened: correct bats verdict, full OS/arch test matrix, the docs checker runs on path triggers, new guards against stale IPv6 wording and version placeholders.
- The documentation consistency check is about 8x faster (single-pass Unicode heading slugger) and now covers the ROADMAP.
- The test suite grew to 790 checks (new scenarios for the validators, restore, atomicity, the slugger and release notes).
Documentation
- Corrected descriptions of IPv6 routing, native IPv6 detection,
--jsonscope and the supported OS count; the CLI reference in ADVANCED is synced with the actual flags. - README and INSTALL_VPS point at
--ssh-portfor changing the SSH port; mobile carrier advice and the script integrity note were refreshed; the ROADMAP was brought up to date. - The release process is documented without contradictions (release-notes source, neutral review gate, checklist sync); Code of Conduct reports go to a private channel; blank issues are disabled - questions go to Discussions.
Verification
- Live runs on clean VPSes: Ubuntu 24.04 (x86_64, full cycle: negative validator tests, install with 2 reboot-resumes, the whole
manageCRUD), Ubuntu 26.04 (ARM64: PPA questing -> noble remap, DKMS module build), Debian 13 (custom routes via--route-custom, kernel headers fallback, DKMS against a kernel upgraded during the install). Real cross-continent AWG 2.0 handshakes and DNS through the tunnel confirmed.
5.15.2 - 2026-06-02
v5.15.2 - a small maintenance release. It points the install and update commands in the documentation at the current tag. No installer or management code changed, behavior is unchanged. Support matrix is unchanged: Ubuntu 24.04 / 25.10 / 26.04, Debian 12 / 13, x86_64 + ARM.
Fixed
- Install and update commands in the documentation point at the current release. The
wget/curlexamples in README, INSTALL_VPS and ADVANCED were pinned to the previous tag, so copying a command downloaded the previous version. They now point at this release, so following the instructions installs it.
Internal
- The documentation consistency check now verifies that pinned
raw.githubusercontent.comlinks match the current version, so install commands do not fall behind the release in the future.
5.15.1 - 2026-06-02
v5.15.1 - a maintenance release after a round of external code and documentation audits. No new features: it hardens the v5.15.0 dual-stack IPv6 work, tightens several management commands, and fixes a number of correctness and robustness issues. A default install is unchanged. Support matrix unchanged: Ubuntu 24.04 / 25.10 / 26.04, Debian 12 / 13, x86_64 + ARM.
Changed
- Split tunnel + IPv6 now mirrors the IPv4 intent (behavior change). When a client uses a custom
ALLOWED_IPS(split tunnel), the dual-stack config keeps that IPv4 split list and adds only the tunnel ULA for IPv6 - it no longer forces a full::/0IPv6 route. A full tunnel (ALLOWED_IPS=0.0.0.0/0) still gets::/0with native IPv6, or the tunnel ULA without it. This affects only clients created with both a split tunnel and--allow-ipv6-tunnel. If you relied on the old behavior of IPv6 going full-tunnel while IPv4 stayed split, recreate the client to pick up the new routing.
Fixed
vpn://URI now carries the server's real MTU, keepalive, and DNS instead of fixed values, so a config imported from the URI matches the.confeven after the server settings or amanage modifychanged them.- Stricter native-IPv6 detection. The server is treated as natively IPv6-capable only when it has a global (non-ULA) IPv6 address and a default IPv6 route, so a client gets a full
::/0route only when it will actually work. - The IPv6 host stack is re-enabled before detection when the tunnel needs it, so a server that had IPv6 disabled via sysctl still gets a working dual-stack tunnel.
installfails fast ifapt updateerrors out, instead of continuing a multi-step install against a stale package cache.manage modifyvalidates the Endpoint and AllowedIPs it is given (host:port, CIDR list) before writing them.manage addis safe against name reuse: it refuses a name that already exists and cleans up partial key or config artifacts if creation fails partway.manage restoreprunes stale clients and keys that are absent from the backup, so a restore yields exactly the backed-up state.manage helpexits 0 for an explicit help request and 1 only for a real usage error.manage --jsonkeeps stdout pure JSON by routing info and debug logging to stderr.- Log messages no longer double percent signs ("95%" stays "95%").
manage restorerecreates the expiry directory before restoring expiry timestamps.
Documentation
--subnethelp states the/24-only requirement;install --helplists Ubuntu 26.04.manage --helpand the README documentlist --json(including theclient_ipv6field).- Restored the changelog compare-links for 5.11.0-5.15.0, fixed several broken in-page anchors, refreshed
SECURITY.mdandCONTRIBUTING.md, and addeddocs/RELEASE_PROCESS.md.
Internal
- Tagging a release now runs a full preflight gate (syntax, shellcheck, tests, punctuation, version and SHA-pin consistency, documentation checks) before the GitHub Release is published, plus a lightweight documentation-consistency workflow. The signing design doc was aligned with the asset-upload draft.
5.15.0 - 2026-06-01
v5.15.0 - optional dual-stack IPv6 inside the tunnel. Requested by users in #24: the new --allow-ipv6-tunnel flag hands clients an IPv6 address from the private ULA subnet fddd:2c4:2c4:2c4::/64 alongside the usual IPv4. Off by default - without the flag the install is identical to v5.14.x. Support matrix unchanged: Ubuntu 24.04 / 25.10 / 26.04, Debian 12 / 13, x86_64 + ARM.
Highlights
- 🆕
--allow-ipv6-tunnelflag ininstall_amneziawg.sh(opt-in, off by default). Enables dual-stack IPv6 inside the VPN tunnel: the server and clients get addresses from the ULA subnetfddd:2c4:2c4:2c4::/64next to IPv4. The subnet can be overridden viaIPV6_SUBNET=inawgsetup_cfg.init. This is separate from the existing--allow-ipv6(host-level IPv6 via sysctl); the behavior of--allow-ipv6/--disallow-ipv6is unchanged. - 🌐 Dual-stack server and client configuration. With the flag on, the server
awg0.confgets IPv6 inAddressandAllowedIPs, an ip6tables MASQUERADE rule on the public NIC is set up, and the client.confplusvpn://URI become dual-stack. The installer detects native IPv6 on the server (ip -6 addr show scope global): with native IPv6 the client gets a full::/0route, without native IPv6 only the tunnel subnet, so IPv6 traffic does not vanish into a black hole (a warning is logged in that case). - 🔧
manage listandmanage regenare dual-stack aware. The client list shows a mixed state (new dual-stack clients next to legacy IPv4-only ones), and config regeneration correctly preserves the IPv6 address.
Migration
- Existing clients are unaffected. After upgrading and enabling IPv6, already-issued IPv4-only configs keep working as before - the server does nothing to them automatically.
- To add IPv6 to a client that already existed, after enabling
--allow-ipv6-tunnel(re-run the installer with the flag or setALLOW_IPV6_TUNNEL=1inawgsetup_cfg.init) recreate that client:manage remove <name>, thenmanage add <name>. Only recreation allocates an IPv6 for the client on the server and issues a dual-stack config. A plainregenkeeps the client IPv4-only, because its[Peer]entry on the server has no IPv6 yet. The new.confmust be re-imported on the device. - Details and troubleshooting are in ADVANCED.en.md.
Tests
- New file
tests/test_v515_sha_pins_lockstep.bats(4 tests): checks the realsha256sumof the four helper scripts against theCOMMON_SCRIPT_SHA256/MANAGE_SCRIPT_SHA256pins in both installers, so a partial bump cannot ship an installer with drifted pins. - New helper
scripts/update-sha-pins.sh(with a--verifyflag) to recompute and verify the SHA pins, andscripts/preflight-check.shfor a single pre-tag check run (syntax, shellcheck, bats, punctuation, version consistency, SHA pins).
Verification
- The automated test suite (bats) was extended with dual-stack coverage: server and client config rendering, IPv6 allocation, dual-stack
vpn://URI,manage list/regen, and the no-native-IPv6 path. The no-flag regression is identical to v5.14.x. - Verified on clean servers: the happy path on ARM64 / Ubuntu 26.04 with native IPv6 (the client gets a full
::/0route, ip6tables MASQUERADE, IPv6 internet egress), and the warning path on x86_64 / Debian 13 without native IPv6 (the client gets the tunnel subnet only). A cross-host tunnel was confirmed live: both IPv4 and IPv6 pass through it (loss-free ping6 to the server's in-tunnel address).
5.14.5 - 2026-05-25
v5.14.5 - the installer now detects the real SSH port and opens exactly that one in UFW. Previously, with SSH on a non-standard port, the firewall opened only port 22, and access to the server could be lost once it was enabled on the final step. No architectural changes, support matrix unchanged: Ubuntu 24.04 / 25.10 / 26.04, Debian 12 / 13, x86_64 + ARM.
Highlights
- 🔧 Automatic SSH port detection for the UFW rule in
install_amneziawg.sh. As observed by @userosos on Debian 13 (#91): with SSH on a non-standard port, the installer opened only the default port 22 in UFW, and access was lost once the firewall was enabled (ufw enable). Added real-port detection: first the--ssh-portflag, then the effectivesshd -Tconfig (thePortdirective andListenAddress host:port, honouring drop-in files insshd_config.d), then the realsshdlistening sockets viass, thensshd_configparsing, and port 22 as the default. UFW now opens every detected SSH port, the pre-enable warning names them explicitly, and the--yesmode also detects the port instead of assuming 22. - 🆕
--ssh-port=PORTflag to set the SSH port manually (comma-separated list allowed) for non-standard setups where auto-detection is not desired.
Tests
- New file
tests/test_ssh_port_detect.bats(18 tests): port detection from--ssh-port, fromsshd -T(thePortdirective andListenAddress, IPv4 and bracketed IPv6), union withsssockets, port normalisation and deduplication, UFW rule application in both branches (fresh setup and update), and parity between the RU and EN branches.
Verification
- Verified on clean servers with SSH on a non-standard port and a
--yesinstall: Ubuntu 24.04 (x86_64) and Ubuntu 26.04 (ARM64). UFW opens the right port and server access is preserved.
5.14.4 - 2026-05-24
v5.14.4 - small installer refinement: declining UFW activation during an interactive install (answering N to "Enable UFW?") now correctly continues the installation. A minor user-choice handling improvement, no architectural changes. Support matrix unchanged: Ubuntu 24.04 / 25.10 / 26.04, Debian 12 / 13, x86_64 + ARM.
Highlights
- 🔧 Declining UFW now continues the install correctly in
install_amneziawg.sh. As observed by @jay0x on Ubuntu 24.04 (#89): answeringNto the interactive "Enable UFW?" prompt stopped the installer instead of continuing. Adjusted the decline handling: the UFW rules stay configured (deny incoming, SSH rate limit, VPN port allow, routing) but the firewall is not activated, the install proceeds, and a hint is logged that the server is running without a firewall, along with the command to enable it later (sudo ufw enable). With the--yesflag the behaviour is unchanged - UFW is enabled automatically. Affects only the interactive path where the user declines the firewall themselves.
Tests
- New file
tests/test_v5144_ufw_optional.bats(6 tests): declining UFW continues the install and does not callufw enable; accepting enables UFW;--yesmode enables automatically without reading input; structural parity between the RU and EN branches.
5.14.3 - 2026-05-21
v5.14.3 - patch release with one fix: cleanup_system() no longer calls apt-get autoremove after purging cloud-init, which on clean Ubuntu 26.04 server in VirtualBox (subiquity, no cloud-init network management) could remove netplan-generator as a transitive dependency and leave the server unable to obtain an IP via DHCP after reboot. No architectural changes. Support matrix unchanged: Ubuntu 24.04 / 25.10 / 26.04, Debian 12 / 13, x86_64 + ARM.
Highlights
- 🛡️ Network stack protection in
cleanup_systemininstall_amneziawg.sh. Reported in #84 by @jay0x on a clean Ubuntu 26.04 server in VirtualBox: after the installer the server did not obtain an IP via DHCP. Root cause: an aggressiveapt-get autoremoveafterapt-get purge cloud-initcascaded into removingnetplan-generatoras a transitive cloud-init dependency. Withoutnetplan-generatorthe/etc/netplan/00-installer-config.yamlfile (subiquity creates it on ISO installs) was no longer translated into/run/systemd/network/*.network, andsystemd-networkdstarted with empty configuration. Changes incleanup_system(): theapt-get autoremovecall is dropped; before anyapt-get purgeanapt-mark holdis applied to critical network stack packages (netplan.io,netplan-generator,systemd-resolved,netcfg,ifupdown) - we first snapshot the user's existing holds viaapt-mark showholdand only add our own hold on packages the user has not already locked (and on unhold we release strictly the ones we placed); a default-route snapshot is taken before and after cleanup - if the route is lost, the installer attempts recovery (netplan.iois reinstalled unconditionally,netplan-generatoronly when it is available in the archive viaapt-cache show, so Debian 12 - which does not ship that package - does not abort the apt transaction), restartsystemd-networkd,netplan apply, then a wait loop polling the route every 1-5 seconds for up to ~26 seconds; then on failure a last-ditch interface bring-up viaip link set up, firstnetworkctl renewwith a route re-check, thendhclient -4if needed, and only then the installer stops with a hint to restore the network from the console (sudo dhclient -4 <iface>) and retry the installer with--no-tweaks. Orphan packages now stay in the system afterpurge(~50-200 MB) - acceptable trade-off for stability; users can manually runapt-get autoremove --no-install-recommendsafter installation. - 🪟 Ubuntu 26.04 whitelisted in
check_os_version. Previously 26.04 fell into the warning branch with an interactive prompt (passed automatically with--yes). Now it is recognised as a supported OS alongside 24.04 / 25.10. The release is tested on 26.04 server in VirtualBox after the Issue #84 fix.
Tests
+14 new bats (532 planned in bats tests/, up from 518 on v5.14.2):
test_v5143_cleanup_no_autoremove.bats(+14) - functional checks via mocks ofdpkg-query,apt-get,apt-mark,apt-cache,ip,systemctl,netplan,networkctl,dhclient,sleep:apt-get autoremoveis never invoked;apt-mark holdfires for the netplan and systemd-resolved packages before anypurge(withoutsystemd-networkd- that is not a standalone package on Ubuntu 24+, the binary lives insidesystemd); pre-existing user apt-mark holds are left alone (our hold/unhold cycle skips them); recovery path when default route is lost (installnetplan.iounconditionally,netplan-generatoronly behind anapt-cache showgate,netplan apply+ wait loop); last-ditch path after primary recovery fails (ip link set up+networkctl renewwith a route re-check, thendhclient -4as fallback);diepath on total failure with the--no-tweakshint; existing cloud-init guard (three marker checks) preserved. Structural checks: RU/EN line parity ofcleanup_system, presence ofapt-mark hold/unhold/diein both files, absence of a realapt-get autoremoveline (rationale comments are excluded).
Compatibility
- Backward compatible with v5.14.x. Behaviour on cloud images that carry cloud-init markers (Hetzner, Oracle Cloud) is unchanged. ISO installs of Ubuntu 26.04 in VirtualBox now correctly handle the absence of cloud-init netplan markers.
- The
--no-tweaksworkaround still works but is no longer required for the @jay0x scenario.
Upgrade
From v5.14.2 to v5.14.3:
wget https://raw.githubusercontent.com/bivlked/amneziawg-installer/v5.14.3/install_amneziawg_en.sh
sudo bash ./install_amneziawg_en.sh --force --yes
Step 5 of the installer pulls the latest manage_amneziawg.sh and awg_common.sh with SHA256 verification.
Thanks to @jay0x for the detailed repro with dpkg, journalctl, and ls /etc/netplan/ output - the root cause would have taken longer to pin without it.
Full list of changes since v5.14.2
5.14.2 - 2026-05-21
v5.14.2 - patch release with two small fixes: the .vpnuri.png QR is now scannable with a phone camera from a computer screen (long URIs with PSK used to trigger error 900 in AmneziaVPN on iOS), and the ARM .deb build script no longer silently picks the "first" /lib/modules/*/build directory on hosts with multiple installed kernels. No architectural changes. Support matrix unchanged: Ubuntu 24.04 / 25.10 / 26.04, Debian 12 / 13, x86_64 + ARM.
Highlights
- 📱
.vpnuri.pngQR is now scannable off a screen.awg_common.sh:generate_qr_vpnurinow invokesqrencodewith an explicit-s 6(the previous default was3). This is the real fix: at the default scale the PNG modules were too small for the iPhone camera to resolve when scanning off a computer screen, which produced error 900 ImportInvalidConfigError in AmneziaVPN on iOS for @haritos90 in issue #72 (Debian 12 + AmneziaVPN iOS 4.8.15.4). Increasing the module scale does not change QR data capacity - it makes each module physically larger so the camera can distinguish black/white blocks reliably. The currentqrencodedefaults are also pinned explicitly:-l L(lowest error-correction level) and-m 4(standard quiet zone) - so future default changes inlibqrencodecannot regress this fix. Pasting the text of.vpnuriinto the app already worked; the fix restores the primary camera-scan path. - 🛠️
scripts/build-arm-deb.sh: explicitKERNEL_VERSION+ fail on ambiguity. The ARM .deb builder used to pick the first matching/lib/modules/*/builddirectory through a simple loop; on developer hosts with several installed kernels this could build against an unintended target. An external code review on 8 May raised the risk. Version resolution has been extracted into a_resolve_kernel_versionhelper with three paths: whenKERNEL_VERSIONis set, the helper validates/lib/modules/$KERNEL_VERSION/buildand uses it; otherwise it counts candidates - zero is an error (unchanged), exactly one is the unambiguous choice (unchanged), two or more produce an explicit failure that lists every found version and asks the caller to setKERNEL_VERSION. The AmneziaWG CI matrix is unaffected because each QEMU container installs exactly one headers package; the defensive behaviour is needed when the script runs on user hosts.
Tests
+18 new bats (528 total, up from 510 on v5.14.1):
test_v5142_qr_high_density.bats(+7) - asserts thatqrencodereceives-l L,-s 6,-m 4, that-t pngis still passed, regression check that the PNG file is still produced from the.vpnuripayload, and byte-identical parity of the invocation line between RU and EN.test_v5142_build_arm_deb.bats(+11) - functional tests for_resolve_kernel_version: exactly one candidate, zero candidates, multiple candidates with an explicit list on stderr, directories without abuild/subdir ignored;KERNEL_VERSIONenv path (valid, used to disambiguate, missing target dir, empty string falls back to auto-detect); structural checks that the function exists, the source-guard allows safesourcefrom tests, and the old inline detection loop is gone from the main body.
Compatibility
- Backward compatible with v5.14.x. Default behaviour is unchanged:
qrencodestill produces.vpnuri.png, and on CI hosts with exactly one installed kernel_resolve_kernel_versionreturns the same result as the previous loop. - The workaround previously required for long QRs (manually copying
.vpnuricontents into the app) is no longer needed.
Upgrade
From v5.14.1 to v5.14.2:
wget https://raw.githubusercontent.com/bivlked/amneziawg-installer/v5.14.2/install_amneziawg_en.sh
sudo bash ./install_amneziawg_en.sh --force --yes
Step 5 of the installer pulls the latest manage_amneziawg.sh and awg_common.sh with SHA256 verification.
Full list of changes since v5.14.1
5.14.1 - 2026-05-19
v5.14.1 - patch release: manage regen now picks up the MTU from the server awg0.conf when regenerating client configs and no longer hardcodes 1280 in the client file. No architectural changes; default behaviour (MTU = 1280 on the server) is unchanged. Support matrix unchanged: Ubuntu 24.04 / 25.10 / 26.04, Debian 12 / 13, x86_64 + ARM (Raspberry Pi, Oracle Ampere, Hetzner CAX).
Highlights
- 📐 MTU sync between server and client configs on
regen. Before v5.14.1 bothawg_common.sh:render_client_configandrender_server_confighardcodedMTU = 1280. If the user hand-edited MTU in/etc/amnezia/amneziawg/awg0.conf,manage_amneziawg.sh regenstill wrote the stale1280into the new client.conf. MTU resolution is now ordered: value from the[Interface]section of serverawg0.conf(the source of truth for a running server), thenAWG_MTUfromawgsetup_cfg.init, then1280as fallback. The live-config parser (load_awg_paramsfor AWG parameters from awg0.conf) also reads theMTU = ...line now and exportsAWG_MTU. Values outside the sane range576..9100at any stage fall back to1280. Reported in Discussion #38 by @E-lmedano. - 🔧 Installer:
AWG_MTUvariable inawgsetup_cfg.init. Fresh installs writeAWG_MTU=1280into the config file; the user can override via environment before running the installer (AWG_MTU=1380 sudo bash install_amneziawg.sh ...) and the value is preserved. The variable is also added to thesafe_load_configwhitelist.
Tests
+18 new bats (510 in the matrix, was 492 on v5.14.0):
test_v5141_mtu_resolution.bats(+18) - functional tests for_extract_mtu_from_server_conf(valid MTU from[Interface], whitespace around=, no MTU, ignored MTU in[Peer], last-wins on duplicates, missing server file, non-numeric value); functional tests for_validate_mtu(accepts 1280, boundary 576 and 9100, rejects 0 / -1 / 9101 / 575 /abc/ empty); structural checks onrender_client_config(noMTU = 1280hardcode, uses${mtu}substitution),render_server_config(uses${AWG_MTU:-1280});safe_load_configwhitelist containsAWG_MTUin all 4 files; installer writesAWG_MTUtoawgsetup_cfg.init(RU + EN); byte-identical_extract_mtu_from_server_confbetween RU and EN.
Compatibility
- Backwards-compatible with v5.13.x and v5.14.0. Default scenario behaviour is unchanged: with
MTU = 1280on the server,regenstill produces1280in the client config. - The previous workaround (hand-editing
/root/awg/<name>.confafterregen) is no longer needed - regen picks up whatever is inawg0.conf.
Updating
From v5.13.x / v5.14.0 to v5.14.1:
wget https://raw.githubusercontent.com/bivlked/amneziawg-installer/v5.14.1/install_amneziawg_en.sh
sudo bash ./install_amneziawg_en.sh --force --yes
Step 5 of the installer pulls fresh manage_amneziawg.sh and awg_common.sh with SHA256 verification.
5.14.0 - 2026-05-19
v5.14.0 - small feature release: more reliable public IP detection (extra fallback services for AWS / NAT'd cloud) plus a new manage diagnose subcommand for one-line self-troubleshooting. Backwards-compatible with v5.13.x installs; no architectural changes. Support matrix unchanged: Ubuntu 24.04 / 25.10 / 26.04, Debian 12 / 13, x86_64 + ARM (Raspberry Pi, Oracle Ampere, Hetzner CAX).
Highlights
- 🌐 Extended public IP detection in
awg_common.sh:get_server_public_ip. The fallback cascade grew from 4 to 6 services -api.ipify.org,checkip.amazonaws.com,icanhazip.com,ifconfig.io,ifconfig.me,ipinfo.io/ip(alphabetical order, deterministic for diffs and tests).checkip.amazonaws.comis reachable from AWS / GCP / OCI private subnets behind a NAT Gateway whereifconfig.mecan rate-limit;ifconfig.iois a backup forifconfig.medowntime. First-wins behaviour preserved: when a service returns a valid IPv4, the rest are skipped. Successful detection is now traced into/root/awg/install_amneziawg.log(or the manage log file) - written directly to file, never to stdout, so the function's$()capture contract is preserved and the generated clientEndpoint =line is not corrupted. - 🩺
manage diagnose [--carrier=NAME]- new subcommand for one-line server self-troubleshooting. Without arguments it runs 6 health checks (kernel module loaded / service active / interface UP / sysctl ip_forward / BBR / UFW + AWG port + peer count). With--carrier=NAMEit additionally compares the current AWG 2.0 obfuscation parameters (Jc / Jmin / Jmax / I1) against a known carrier profile and prints OK/WARN/FAIL per check with a Fix: hint. Seven confirmed carriers fromADVANCED.en.mdoperator matrix:beeline_msk(default preset);yota_msk,tele2_msk,tattelecom(mobile preset, random I1);tele2_krasnoyarsk,megafon_regions(mobile preset, I1 must be absent);tmobile_us(binary I1, from Discussion #45). Exit code 1 only on FAIL or unknown carrier; WARN does not change the rc. Bilingual RU + EN. - 🔒 Release signing design (docs/SIGNING_DESIGN.md, planning only). Threat model, tool choice (minisign over cosign / GPG), signing flow with trusted-comment binding to tag + filename for rollback protection, and a draft
release-sign.ymlworkflow that uploads pre-generated.minisigfiles. Activation is gated on the maintainer generating an offline keypair and committingKEYS.txtto the repository root; until then the section inSECURITY.mddescribes the planned path.
Tests
+37 new bats (492 in the matrix, was 455 on v5.13.0):
test_v5140_public_ip_services.bats(+11) - structural RU/EN parity on the 6 endpoints, byte-identical service list across RU and EN, alphabetical-order assertions (first =api.ipify.org, last =ipinfo.io/ip), functional fallthrough (first service success / first fails-second succeeds / all 6 fail / invalid IP format skip / last-in-list success / cache short-circuit).test_v5140_diagnose.bats(+16) - structural RU/EN parity ondiagnose_serverand the_diagnose_carrier_known,_diagnose_carrier_list,_diag_linehelpers; CLI parser accepts--carrier=NAME; command dispatcher wires updiagnose; usage help mentions diagnose; functional checks on the carrier map (beeline_mskrow matches default-preset shape,tele2_krasnoyarskhasi1=absent,tmobile_ushasi1=binary+ Jc=6; unknown carrier returns 1); carrier list has 7 distinct confirmed entries; previously-included unconfirmedmts_msk+megafon_mskare intentionally removed.
Compatibility
- OS: Ubuntu 24.04 LTS, 25.10, 26.04 (with noble fallback). Debian 12 (bookworm), 13 (trixie).
- Arch: amd64, arm64 (Raspberry Pi 4/5, Oracle Cloud Ampere, Hetzner CAX, AWS Graviton, other ARM VPS).
- Russian carriers matrix in
ADVANCED.en.md. The newdiagnose --carrier=NAMErecognises 7 confirmed rows; "🔄 testing" rows (Megafon Moscow, MTS Moscow) intentionally excluded until the operator range is confirmed and locked.
Out of scope
- v5.14.1+: minor cleanups uncovered by post-release feedback.
- v5.15.x: minisign signature activation (after maintainer keypair generation), per-client CPS profiles (Issue #71),
--preset=mobile-awg1for I1=none carriers.
5.13.0 — 2026-05-12
v5.13.0 — AmneziaWG 2.0 VPN installer release with Ubuntu 25.10 (questing) and 26.04 support, plus a --force safety guard against accidental re-install on a configured server. Ubuntu 24.04, Debian 12 / 13, x86_64 + ARM (Raspberry Pi, Oracle Ampere, Hetzner CAX) support — unchanged.
Highlights
- 🛡️ PPA noble fallback for Ubuntu 25.10 / 26.04 (Issue #46). The Amnezia PPA does not yet publish packages for
questing(25.10) or upcoming Ubuntu codenames. The installer now auto-detects the 404 ondists/<codename>/Release, remaps the suite tonoblein/etc/apt/sources.list.d/amnezia-ppa.sourcesand re-runsapt update. If the server has leftover kernel headers from a previous 24.04 install (typical afterdo-release-upgrade), the installer also pulls ingcc-13fromquesting/universeso the DKMS autoinstall succeeds for every kernel. No manualsources.listedits, no DKMS surprises. The script also repairs a "sticky".sourcesfile from a previous (≤ v5.12.1) run that leftSuites: questingbehind after an apt failure. - 🔒
--forcesafety guard (Issue #78). Re-running the installer on a server with AmneziaWG already configured now requires an explicit--force(orAWG_FORCE_REINSTALL=1). Without it, the script early-exits with a clear "already installed and running" message. Server keys, peer configs, and obfuscation parameters survive a re-run, but Step 1 re-tunes sysctl/swap/BBR,apt-get upgrademay pull a new kernel (and require another reboot), and Step 7 restartsawg-quick@awg0— handshakes drop for a few seconds. The guard removes that foot-gun. - 🧹
manage_amneziawg.shlogging: WARN → stderr. In v5.12.1manage_amneziawg.sh:log_msgrouted only ERROR to stderr and leaked WARN to stdout — broke CI/automation parsing (stdout = "data", stderr = "diagnostics"). WARN and ERROR now both go to stderr, symmetric withinstall_amneziawg.sh:log_msg. - 💾 Precise
/swapfilecheck in/etc/fstab. The old substring checkgrep -q '/swapfile'matched commented lines and partial-name hits (/swapfile.bak); on re-run the installer could mistakenly skip adding a valid entry — swap then failed to mount on reboot. Switched to an anchored field-aware awk check:!/^[[:space:]]*#/ && $1 == "/swapfile" && $3 == "swap". Idempotent and comment-resistant.
Installation
wget https://raw.githubusercontent.com/bivlked/amneziawg-installer/v5.13.0/install_amneziawg_en.sh
chmod +x install_amneziawg_en.sh
sudo bash ./install_amneziawg_en.sh
3 commands → ~20 minutes → a working VPN server with traffic obfuscation. Full guide — README → Installation.
Upgrading an existing server
Run the latest install_amneziawg.sh with --force (if AmneziaWG is already running) — Step 5 fetches the fresh manage_amneziawg.sh and awg_common.sh with SHA256 verification. Full commands — ADVANCED.en.md → Updating the scripts.
Tests
+68 new bats (455 in the matrix, was 387 on v5.12.1):
test_v5130_ppa_noble_fallback.bats(+33) — RU/EN structural greps on the pre-check block and suite-mismatch detection, parity counts, functional tests with mockedcurl(404 → noble, timeout → noble, success → questing), LTS whitelist (noble/jammy/focal skip pre-check), suite mismatch deletes file on mismatch and preserves on match, corrupt.sources(missingSuites:) gets recreated, legacy.sourcesmismatch is removed, gcc-13 pre-install fires when stale headers are detected.test_v5130_force_guard.bats(+19) — RU/EN structural greps on the--force|-fCLI flag, theAWG_FORCE_REINSTALL=1env bridge, the idempotency guard[[ -f $SERVER_CONF_FILE ]] && systemctl is-active --quiet awg-quick@awg0, the help-section mention of-f, --force, RU/EN parity byFORCE_REINSTALLoccurrence count; functional matrix of 6 cases (clean install / configured+active+no-force / configured+inactive+no-force → repair flow / configured+active+--force / env bridge / strict=1env vsyes).test_v5130_bundled_fixes.bats(+16) — rcgr: RU/EN log_msg routes WARN to stderr (structural + functional, INFO still on stdout); i31a: awk check on/swapfilecorrectly detects a valid entry, rejects commented lines, rejects partial-name matches (/swapfile.bak), handles indented lines and an empty fstab.
Compatibility
- OS: Ubuntu 24.04 LTS, 25.10, 26.04 (with noble fallback). Debian 12 (bookworm), 13 (trixie).
- Arch: amd64, arm64 (Raspberry Pi 4/5, Oracle Cloud Ampere, Hetzner CAX, AWS Graviton, other ARM VPS)
- Russian carriers:
--preset=mobileworks on Yota, Beeline, MTS, Tattelecom, Tele2 (Moscow), Megafon (Moscow). See the operator matrix in README.
Out of scope
- v5.13.1: external review fixes (kernel ambiguity in
build-arm-deb.sh), backlog refinements. - v5.14.0:
--preset=mobile-awg1(I1=none fallback for Tele2 Krasnoyarsk / Megafon regions).
Full roadmap — Issue #79.
5.12.1 — 2026-05-08
v5.12.1 — patch release of the AmneziaWG 2.0 VPN installer: three small fixes for issues found in the first 48 hours after v5.12.0. No new features, no architectural changes. Support matrix unchanged: Ubuntu 24.04 / 25.10, Debian 12 / 13, x86_64 + ARM (Raspberry Pi, Oracle Ampere, Hetzner CAX).
Highlights
- 🔧
AWG_SKIP_APPLY=1works again inmanage add/manage remove. v5.12.0 added an unconditional pre-call toensure_amneziawg_kernel_modulebefore both actions to makeawg syncconfreliable. Side effect: it broke the offline edit-only flow on dev / CI machines without the kernel module loaded, whereAWG_SKIP_APPLY=1accumulates changes for batch apply (seeADVANCED.en.md— environment variables section). The pre-call is now wrapped inif [[ "${AWG_SKIP_APPLY:-0}" != "1" ]].manage restartis intentionally NOT gated — it is an explicit apply, AWG_SKIP_APPLY has no meaningful semantics for it. Only the literal1is honoured;yes,true, any other string — same behaviour as unset (apply happens). - ☁
linux-headers-cloud-${arch}in the repair-module fallback on Debian.awg_common.sh:_install_kernel_headers(used bymanage repair-module) on Debian only triedlinux-headers-${kernel_ver}andlinux-headers-${arch}. On AWS / Azure / GCP / cloud-Hetzner (kernel name contains-cloud-) the exact-version package can disappear from the mirror after a kernel upgrade, while the cloud metalinux-headers-cloud-${arch}stays available. The installer's step 2 already knew about cloud-headers via smart detection; nowrepair-moduleknows too and tries the cloud meta before the generic one. Standard kernels (no-cloud-in the name) — behaviour unchanged. - 📦 ARM prebuilt packages now decompress correctly with the in-tree kernel decoder (Issue #76).
scripts/build-arm-deb.shusedxz -9(CRC64 check, 64 MiB dictionary) — the userspacexz -ttool considered the stream valid, but the in-tree Linux decoder on Debian 13 trixie kernel6.12.85+deb13-arm64(build 2026-04-30) returneddecompression failed with status 6. Switched to a kernel-compatible presetxz --check=crc32 --lzma2=dict=1MiB— matches mainlinescripts/Makefile.modinst. Plus a build-time sanity gate: after compression,xz -t+xz -d -cround-trip; if anything fails —exit 1, no broken prebuilt ships to thearm-packagesrelease. On the v5.12.1 tag push, CI workflowarm-build.ymlre-publishes all 14 ARM prebuilt packages with the new xz flags.
Install
wget https://raw.githubusercontent.com/bivlked/amneziawg-installer/v5.12.1/install_amneziawg_en.sh
chmod +x install_amneziawg_en.sh
sudo bash ./install_amneziawg_en.sh
3 commands → ~20 minutes → a ready-to-use VPN server with traffic obfuscation. Details — README → Install.
Upgrading an existing server
Run a fresh install_amneziawg_en.sh — at step 5, manage_amneziawg.sh and awg_common.sh are updated automatically (with SHA256 verification). Full commands — ADVANCED.en.md → How to update the scripts.
Tests
+30 new bats tests (387 in the matrix, was 357 in v5.12.0):
test_v5121_skip_apply_regression.bats(+14) — RU/EN structural greps onadd/remove/restartblocks, plus runtime semantics of the gate for every documented value (unset / 0 / 1 / yes / true / YES); confirmsrepair-modulekeeps theAWG_ALLOW_APT_IN_ENSURE=1 ensure_amneziawg_kernel_module fullinvocation; bash -n syntax sanity.test_v5121_cloud_headers.bats(+9) — functional test of_install_kernel_headersvia mockedapt-getanddpkg: cloud kernel gets the cloud meta in candidates before the generic one, standard kernel does not, Ubuntu codepath untouched; the EN mirrorawg_common_en.shis verified separately.test_v5121_xz_kernel_compat.bats(+7) — structural greps for the new xz flags inbuild-arm-deb.sh, fail-fast on sanity-stage failure, local round-trip with the same flags (toolchain smoke test; kernel-decompressor compatibility itself is best validated on a real kernel boot — VPS or QEMU with the target kernel).test_v5115_regen_multiarg.bats— version assertion bumped from 5.12.0 to 5.12.1.
Compatibility and dependencies
- Fully backwards-compatible. All three fixes change behaviour only in narrow regression cases (offline edit / cloud-kernel repair / ARM prebuilt on Debian 13 trixie). The standard install + client flow is unchanged.
- No new dependencies.
5.12.0 — 2026-05-06
v5.12.0 — feature release of the AmneziaWG 2.0 VPN installer: one big feature — automatic DKMS module recovery on kernel upgrade. No architectural changes: compatible with all v5.11.x installs — the apt hook, systemd unit, and helper are deployed on the next run of install_amneziawg_en.sh. Support matrix unchanged: Ubuntu 24.04 / 25.10, Debian 12 / 13, x86_64 + ARM (Raspberry Pi, Oracle Ampere, Hetzner CAX).
Highlights
- 🛡 DKMS auto-repair on kernel upgrade — three layers of safety net. Before v5.12.0, after
apt upgradeof the kernel, DKMS did not always rebuild theamneziawgmodule by the nextreboot—awg-quick@awg0failed withmodprobe: FATAL: Module amneziawg not found, and the VPN was down until manual recovery. Now three safety nets work transparently:- apt hook (
/etc/apt/apt.conf.d/99-amneziawg-post-kernel) —DPkg::Post-Invokeruns/usr/local/sbin/amneziawg-ensure-module --hook, which iterates/lib/modules/*/build, rebuilds DKMS for every target kernel with installed headers, thendepmod -a. Log at/var/log/amneziawg-ensure-module.log(logrotate weekly, 4 copies). The stamp file/var/lib/amneziawg/ensure-module.stampsilences the hook on routine apt operations unrelated to the kernel. - systemd unit (
amneziawg-ensure-module.service) —Type=oneshot,Before=awg-quick@awg0.service,After=systemd-modules-load.service local-fs.target. At boot, beforeawg-quick, it iterates kernels with already-installed headers (/lib/modules/*/build), rebuilds DKMS, runsmodprobe amneziawg, and verifies vialsmod. If headers are missing, it logs a WARN and exits successfully — installing the headers themselves is the job of step 2 of the installer or ofmanage repair-module. Logs in journal (journalctl -u amneziawg-ensure-module.service).ConditionPathExists=/usr/local/sbin/amneziawg-ensure-module— the unit will not fail if the helper has been removed. - manage repair-module — explicit fallback for interactive recovery:
sudo bash /root/awg/manage_amneziawg.sh repair-module. SetsAWG_ALLOW_APT_IN_ENSURE=1(apt-get install of kernel-headers is allowed only in this context — the apt hook and systemd unit do not use it to avoid blocking on dpkg-lock).
- apt hook (
- 🧠 Smart kernel-headers meta-package detection. Step 2 of the installer now installs a meta-package matched to your kernel rather than pinning to
linux-headers-$(uname -r): on Ubuntu it extracts the flavor fromuname -r(aws/azure/gcp/oracle/kvm/lowlatency/raspi) with a fallback tolinux-headers-generic; on Debian —linux-headers-cloud-${arch}for cloud kernels, otherwiselinux-headers-${arch}. This protects against the case whereapt-get upgraderaised the kernel, but the new module fails to build without matching headers.
Other
- 🛠
manage_amneziawg.shpre-callsensure_amneziawg_kernel_moduleinadd/remove/restart. If the module is unloaded or doesn't match the current kernel, it tries to recover before the operation — this removes half of the "add a client doesn't work afterapt upgrade" reports. - 🧹
step_uninstallcleans up the auto-repair components. On--uninstallthe systemd unit is disabled, and the apt hook, helper, logrotate config, stamp directory/var/lib/amneziawg/, and rotated logs/var/log/amneziawg-ensure-module.log*are removed. Idempotent — installs from before v5.12.0 are unaffected.
Install
wget https://raw.githubusercontent.com/bivlked/amneziawg-installer/v5.12.0/install_amneziawg_en.sh
chmod +x install_amneziawg_en.sh
sudo bash ./install_amneziawg_en.sh
3 commands → ~20 minutes → a working VPN server with traffic obfuscation. Details — README → Install.
Upgrading an existing server
Run the fresh install_amneziawg_en.sh — at step 5 manage_amneziawg.sh and awg_common.sh are refreshed automatically (with SHA256 verification), and at step 2 the apt hook, systemd unit, helper, and logrotate config are deployed. For an existing server this is a safe re-run. Full commands — ADVANCED.en.md → Updating the scripts.
Tests
+32 new bats (357 total, was 325 in v5.11.5):
test_v512_dkms_repair.bats(+32) — structural coverage of the DKMS auto-repair deployment phases: 4 functions inawg_common.sh+_en.sh, ≥3 pre-calls in manage (add/remove/restart), themanage repair-module|repaircommand, theAWG_ALLOW_APT_IN_ENSUREgate; smart kernel-headers candidate-loop (Ubuntu flavor extraction, Debian cloud detection, RPi guard, fallback ordering: flavor BEFORE generic + cloud BEFORE arch); helper--hook|--systemdmodes, stamp fast-path gated to--hook, modprobe+lsmod in--systemdplus 2 exit-1 paths, helper does not use apt-get; systemd unit 12 directives, atomic deploy,daemon-reload+enable; byte-identical RU/EN for helper, hook, logrotate, unit; atomic deploy cleanup-on-failure for all 4 staging vars; helper body parses withbash -n. Mock-based runtime tests (kernel upgrade simulation) are run on VPS Ubuntu 24.04 + Debian 13 as part of the release test.
Compatibility and dependencies
- Fully backwards-compatible. v5.11.x installs continue to work as before; auto-repair components are deployed on the next run of
install_amneziawg_en.sh— re-run is safe. Step 2 now installs a meta-package for headers, which protects against kernel-upgrade-without-headers; no extra packages need to be installed manually. - No new dependencies. The helper uses
dkms,depmod,modprobe,systemctl— all from the base install. The apt hook is a POSIX-sh inner command (not bash). The systemd unit isType=oneshot, no timers needed.
5.11.5 — 2026-05-05
v5.11.5 — bug-fix release of the AmneziaWG 2.0 VPN installer: two small fixes after v5.11.4, no architectural changes. Support matrix unchanged: Ubuntu 24.04 / 25.10, Debian 12 / 13, x86_64 + ARM (Raspberry Pi, Oracle Ampere, Hetzner CAX).
Highlights
- 🔁
manage regen c1 c2 c3now regenerates all three clients, not just the first. Until v5.11.5 theregencase picked up only the first argument from the list — the rest were silently dropped.addandremovealready had the loop over arguments, butregenwas missing it. Behaviour is now consistent: each name is validated and processed individually, a missing client logs a warning and contributesrc=1, valid ones still get regenerated. A summary at the end printsProcessed: N of M. The no-args path (manage regenregenerates all clients) is unchanged. (#70, @Barmem) - 🛡 Step 2: a hard apt-get update error is no longer masked. In v5.11.4 I downgraded the
apt-get updatecheck at step 2 to a warning, so that a brief Launchpad PPA outage (issue #68) would not break the install. Side effect: real apt errors — DNS, GPG mismatch, dpkg lock contention on the base mirror — let the install continue on a staleapt-cacheand fail later with a less actionable error. The logic now distinguishes the two scenarios: errors only on the Amnezia PPA (issue #68) — continue,apt_wait_for_ppa_packageretries; any other non-source error —diewith concrete pointers (DNS //etc/apt/keyrings/ dpkg lock). The OOM / silent-crash edge case is also covered — apt failures with no classifiable lines are no longer swallowed even if a PPA URL appears in the output. (post-merge review on PR #69)
Other
- 📚 Docs: AWG 2.0 vs AWG 1.0 (S3/S4). Added a FAQ entry to
ADVANCED.en.mdnoting that an AmneziaWG 2.0 server withS3>0orS4>0is not compatible with AWG 1.0 clients (see upstream issueamnezia-vpn/amneziawg-linux-kernel-module#168). My installer always generatesS3=8..55andS4=4..27— both>0— so in the typical scenario (Amnezia VPN client + clients generated bymanage) this does not surface. Risk only when manually importing the server preset into a WireGuard/AWG 1.0 client.
Install
wget https://raw.githubusercontent.com/bivlked/amneziawg-installer/v5.11.5/install_amneziawg_en.sh
chmod +x install_amneziawg_en.sh
sudo bash ./install_amneziawg_en.sh
3 commands → ~20 minutes → a working VPN server with traffic obfuscation. Details — README → Install.
Upgrading an existing server
Run the fresh install_amneziawg_en.sh — at step 5 manage_amneziawg.sh and awg_common.sh are refreshed automatically (with SHA256 verification). Full commands — ADVANCED.en.md → Updating the scripts.
Tests
+13 new bats (325 total, was 312 in v5.11.4):
test_v5115_regen_multiarg.bats(+13) — RU/EN regen case iteratesARGS[@](the headline fix for #70);_regen_countcounter and the summary lineОбработано: N из M/Processed: N of M; no regression: single-argregen <name>and no-argsregenbehave as before; missing/invalid names yield a warning +rc=1and the batch keeps going; RU/EN structural parity on the regen branch control-flow tokens;apt_update_tolerantaccepts the--ppa-amnezia-tolerantflag withlocal ppa_tolerant=0declared in both installers; step 2 calls the helper with that flag anddies on a hard error; the OOM / silent-crash guard viaraw_had_non_src_errorsis present in both installers;SCRIPT_VERSION="5.11.5"is bumped in all six files.
Compatibility and dependencies
- Fully backwards-compatible. Single-arg
manage regen <name>and no-argsmanage regenare unchanged; only the multi-arg path is affected — names that used to be silently dropped are now processed. Step 2 behaviour during a normal install is unchanged too — strict mode only triggers on a real hard apt error that would have blocked the install anyway. - No new dependencies.
5.11.4 — 2026-05-04
v5.11.4 — bug-fix release of the AmneziaWG 2.0 VPN installer: two fixes for issues reported on top of v5.11.3, no architectural changes. Support matrix unchanged: Ubuntu 24.04 / 25.10, Debian 12 / 13, x86_64 + ARM (Raspberry Pi, Oracle Ampere, Hetzner CAX).
Highlights
- 🔑
vpn://import into the Amnezia VPN app now carries the PSK. Withmanage add --pskthe PresharedKey was correctly written to the server[Peer]and the client.confsince v5.11.1, but thevpn://URI was missing thepsk_keyfield that the AmneziaVPN parser reads — clients silently came up without the preshared key, the server (which had it) rejected the handshake, andawg show transferstayed at «never». Also tightened trailing CR / space stripping forPresharedKey =andAllowedIPs =so CRLF configs edited on Windows no longer leak\rinto the JSON. (#67, @haritos90) - 🔁 Install survives a brief Launchpad PPA outage. When
ppa.launchpadcontent.netis briefly unreachable (as on May 3rd per #68), the installer now waits foramneziawg-dkmsto show up inapt-cachefor up to 3 attempts with 30 s and 60 s backoff (and a freshapt-get updatebetween retries). Checkingapt-cachematters:apt-get updateitself is tolerant to an unreachable InRelease (returns 0 even when the PPA never downloaded), so a plain rc-based retry would not catch this case. After three failures a friendly message points the user at the issue and explains this is a Launchpad infrastructure outage, not a script bug. (#68, @saligin / @baikov)
Install
wget https://raw.githubusercontent.com/bivlked/amneziawg-installer/v5.11.4/install_amneziawg_en.sh
chmod +x install_amneziawg_en.sh
sudo bash ./install_amneziawg_en.sh
3 commands → ~20 minutes → a working VPN server with traffic obfuscation. Details — README → Install.
Upgrading an existing server
Run the fresh install_amneziawg_en.sh — at step 5 manage_amneziawg.sh and awg_common.sh are refreshed automatically (with SHA256 verification). Full commands — ADVANCED.en.md → Updating the scripts.
Tests
+16 new bats (312 total, was 296 in v5.11.3):
test_v5114_psk_uri.bats(+5) — happy path with PSK; no PSK → nopsk_keyfield; indentedPresharedKey; CRLF-edited config does not leak\rinto the JSON; emptyPresharedKey =line does not turn intopsk_key:""(which would mismatch a server with a real PSK anyway).test_v5114_ppa_retry.bats(+11) — success on first attempt; retry until success; exhausting max attempts; exponential backoff doubling; 1800 s cap against arithmetic overflow; RU/EN structural parity of the helper; issue #68 link present in both installers.
Compatibility and dependencies
- Fully backwards-compatible. On a stable network the retry helper adds zero delay — the first attempt passes and the rest of the run is unchanged.
manage add --pskwithoutvpn://import behaves the same as before (the PSK has always been written to the.confcorrectly). - No new dependencies. Just bash arithmetic and
sleep— both standard.
5.11.3 — 2026-04-28
v5.11.3 is a UX release for the AmneziaWG 2.0 VPN installer: five improvements driven by recent issues and discussions, no architectural changes. Ubuntu 24.04 / 25.10, Debian 12 / 13, x86_64 + ARM (Raspberry Pi, Oracle Ampere, Hetzner CAX) — supported as before.
Highlights
- 🍎 Shadowrocket on iOS / macOS now connects out of the box. The
--pskflag formanage addshipped in v5.11.1 but was not visible in the README — it is now in the Quick Reference and has its own FAQ entry. (#62, @andreykorobko) - 📡 Ping inside the tunnel — server ↔ clients — a step-by-step recipe for UFW +
/etc/ufw/before.rulesin the FAQ. Explicit warning:ufw allow ... proto icmpdoes not work (UFW only supportstcp/udp/esp/ah/gre/ipv6via theprotoflag). (#63, @PavelVVrn) - 🌐 Mobile carrier → I1 map extended. Megafon (regions) and Tele2 (Krasnoyarsk) updated to
I1=absent— the AWG 1.0 fallback for carriers where CPS packets themselves trigger DPI blocks. Exact commands below the table (systemctl restart awg-quick@awg0+manage regen <name>). (#42, @alkorrnd) - 🤖 Auto-scripts for cron / Ansible / Proxmox.
manage --yes(flag) orAWG_YES=1(env) skip the confirm prompt inremove,restore,restart. Default behavior is unchanged (opt-in). - 🗂️ Backups without collisions. Millisecond suffix in filenames (
awg_backup_2026-04-28_15-53-50.123.tar.gz) protects against overwrite when two backups land in the same second (e.g.,regen → backup → modify → backup). Legacy filenames (no.NNN) keep working.
Install
wget https://raw.githubusercontent.com/bivlked/amneziawg-installer/v5.11.3/install_amneziawg_en.sh
chmod +x install_amneziawg_en.sh
sudo bash ./install_amneziawg_en.sh
3 commands → ~20 minutes → a working VPN server with traffic obfuscation. More — README.en.md → Installation.
Upgrading an existing server
Re-run the latest install_amneziawg_en.sh — step 5 refreshes manage_amneziawg.sh and awg_common.sh automatically (with SHA256 verification). Full commands — ADVANCED.en.md → How to Update Scripts.
Tests
+34 new bats (295 total, up from 261 on v5.11.2):
test_yes_flag.bats(+11) — extractconfirm_actionviaawk+eval. Verifies that non-"1"values ofAWG_YES("yes","true","0") do not match the bypass branch under forced-interactive mode.test_backup_collision.bats(+8) —date +%3Nproduces distinct values under rapid fire;findpattern andsort -rcorrectly handle both legacy and ms-suffix names in the same directory.test_v5113_docs.bats(+15) — invariants for the ICMP FAQ, the carrier table, the--pskhighlight; protection against RU/EN cross-link drift in README → ADVANCED.
Compatibility and dependencies
- Fully backwards-compatible.
--yesis opt-in, default behavior unchanged. Backup ms-suffix is designed to coexist with legacy filenames. Downgrading to v5.11.2 is safe. - No new dependencies.
date +%3N(milliseconds) is part of standard GNU coreutils, available out of the box on Ubuntu/Debian.
5.11.2 — 2026-04-24
UX patch on top of v5.11.1. A second per-client QR code — rendered from the vpn:// URI — for one-tap import into the flagship Amnezia VPN app (Android / iOS / Desktop). The existing <name>.png (scan of .conf) is unchanged and keeps working with WireGuard-compatible clients (AmneziaWG Windows, wireguard-apple, wg-quick).
Added
- New
generate_qr_vpnurihelper inawg_common.sh/awg_common_en.sh. It reads/root/awg/<name>.vpnuri(the URI thatgenerate_vpn_urihas been producing for a while now — full Amnezia envelope: zlib-JSON withcontainers/defaultContainer/hostName/dns/mtu/protocol_version=2plus all AWG 2.0 params), pipes it intoqrencode -t png, writes/root/awg/<name>.vpnuri.pngwith mode 600. Writes are atomic: first into<name>.vpnuri.png.tmp.$$in the same directory,chmod 600, thenmv -fto the target path — ifqrencodeorchmodfails, the old file stays intact and the orphan.tmp.*is cleaned up. - Hooked into
generate_clientandregenerate_client. After a successfulgenerate_vpn_uri,generate_qr_vpnuriruns. If the URI itself cannot be built (missing perl modules, params not loaded), the vpn:// QR is silently skipped. The wg-quick QR and vpn:// QR are independent best-effort artifacts — a failure in one does not prevent the other. - Hooked into
manage regenandmanage remove.regennow refreshes both QR codes (conf and vpn://) together.removecleans up<name>.vpnuri.pngalongside<name>.conf/.png/.vpnuriand keys. - Backup / restore picks up
.vpnuri.pngautomatically — no new code paths needed: the existing*.pngglob in_backup_configs_nolockandchmod 600 *.pnginrestore_backupalready cover the new artifact.
Why
The flagship Amnezia VPN app (Android / iOS / Desktop) supports one-tap import by scanning a QR that encodes vpn://{base64url(zlib(json))}. I have been generating that URI for a while, but only as a plain text .vpnuri file that users had to copy over manually. Now you can point the phone camera at the second QR code instead of copying a file. The first QR (from .conf) remains the right one for classic WireGuard clients.
Tests
- +10 new bats (261 total, up from 251 on v5.11.1):
test_qr_vpnuri.bats(+10) — happy path (stdin → PNG), missing.vpnuri→ error,qrencodenon-zero exit → error, atomic write (pre-existing.vpnuri.pngis preserved on failure, no orphan.tmp.*left behind),chmod 600on Linux/Darwin, RU/EN structural parity of the helper (qrencode call +.vpnuri.pngtarget +command -vguard), hooks ingenerate_client/regenerate_client/ manage regen / cleanup in manage remove.
Breaking changes
None. Existing client .conf / .png / .vpnuri files keep working. The new .vpnuri.png is only generated for clients created or regenerated on v5.11.2 — for older clients, a single manage regen <name> is enough. Downgrading to v5.11.1 is safe (stale .vpnuri.png files just sit in /root/awg/ and are ignored).
Dependencies
No new ones: qrencode was already in the installer step-2 required list (used by generate_qr for .conf), and perl + Compress::Zlib + MIME::Base64 — already for generate_vpn_uri.
5.11.1 — 2026-04-23
UX patch. Three small improvements for manage on manual (non-installer) setups — e.g. amneziawg-go userspace in LXC. Credit to @Akh-commits for the detailed live-test in Issue #51 on 2026-04-22, which is where all three fixes came from.
Fixed / Added
manage addandregennow work without theserver_public.keycache. A new_ensure_server_public_keyhelper computes the server public key from the[Interface]PrivateKeyinawg0.confviaawg pubkeyif/root/awg/server_public.keyis missing (typical for installs made outside my installer — that cache is only populated there). The result is written atomically (tmp + mv) with mode 600. The awk extractor tolerates leading whitespace beforePrivateKey =(hand-edited configs).- Endpoint fallback chain for egress-restricted setups. Previously
manage addinside LXC without access to external IP services died with "Failed to determine server public IP". Now, aftercurltoifconfig.me/ipify/icanhazip/ipinfofails, I try the first non-loopback IPv4 on a global-scope interface (ip -4 -o addr show scope global). The user gets alog_warnsuggesting they hand-editEndpointin the client.confif the server sits behind NAT. - New
manage add --pskflag. Optionally enablesPresharedKeyin the client.confand in the server[Peer]. Generates a 32-byte key viaawg genpskfor every client in batch mode (distinct PSK per client). Off by default — AWG 2.0 obfuscation is sufficient in most scenarios, and PSK is an extra layer for the paranoid or for compatibility with classic WireGuard deployments. Documented inADVANCED.md/ADVANCED.en.mdmanage CLI section.
Tests
- +19 new bats (249 total, up from 230 on v5.11.0):
test_server_pubkey_autogen.bats(+7) — no-op when cache exists, reconstruct fromawg0.conf, edge cases (missing file, missingPrivateKey, ignorePrivateKeyin[Peer]sections, indentedPrivateKey, RU/EN parity).test_endpoint_fallback.bats(+5) — returns IPv4 on a global-scope interface, empty output when no global scope, skips loopback, picks first of many interfaces, RU/EN parity.test_psk_flag.bats(+7) —PresharedKeyabsent without flag, written whenCLIENT_PSKis set, correct ordering inside[Peer]blocks,CLIENT_PSK="auto"resolution ingenerate_client,--pskparsing in RU+EN manage, help mention.
Breaking changes
None. All three changes are additive — the existing install flow is unchanged, and without the --psk flag manage add behaves identically to v5.11.0.
5.11.0 — 2026-04-22
Robustness bundle — I closed a batch of scenarios where install or manage could leave the system in a half-configured state on failure: running install twice without reboot, a helpers download being interrupted, a kill during restore, a failed backup before a destructive modify, a race between concurrent regen calls. The CI ARM matrix now also ships prebuilt packages for Ubuntu 25.10 and Debian 13. Upgrading is recommended but not required — v5.10.2 remains working, no blocking bugs there.
Fixed — install_amneziawg.sh
- Running
installtwice without reboot no longer breaks DKMS.request_rebootnow saves/proc/sys/kernel/random/boot_idto$AWG_DIR/.boot_id_before_step2before the step 1→2 reboot. On entry to step 2 the installer compares the saved boot_id against the current one: if they match, the installer dies with "a reboot was expected before step 2". Previously re-running without the reboot attempted to build amneziawg-dkms against the wrong kernel and crashed on vermagic. setup_statewrite is now atomic. Usestmp + flock + mv -fvia a PID-specific tmp path (${STATE_FILE}.tmp.$BASHPID). Parallel-invocation scenarios can no longer read a half-written step number.awg_common.shandmanage_amneziawg.shdownload via mktemp + SHA256 + atomic mv. New helper_secure_download(): curl writes tomktemp, SHA256 is verified, the verified file ismv'd to the target in one step. An interrupted connection no longer leaves a half-written helper in/root/awg/. Same pattern applied to the GPG keyring during PPA import.
Fixed — manage_amneziawg.sh + awg_common.sh
restore_backupnow rolls back on failure. Before any destructive operationrestorecreates a pre-restore snapshot (this already existed as an undo aid). In v5.11.0 the snapshot is made known to the function (viaLAST_BACKUP_PATH) and all error paths are wrapped intrap _restore_cleanup RETURN. If anything fails aftersystemctl stop, the cleanup unpacks the snapshot back into place and runssystemctl start awg-quick@awg0. A pre-flightvalidate_awg_configcheck is added before service start — if the restored config does not validate, the service is not started "broken"; rollback kicks in instead. The trap clears its ownRETURNhandler first (trap - RETURN) to avoid leaking into subsequent calls._backup_configs_nolockno longer hides cp failures on critical files. The silent|| trueis gone. A cp failure on critical artifacts (awg0.conf,awgsetup_cfg.init,server_public.key,server_private.key, client*.conf,$KEYS_DIR/*,expiry/,/etc/cron.d/awg-expiry) now returns 1 — a corrupted backup is more dangerous than a missing one. Optional artifacts (QR*.png,*.vpnuri) keeplog_warnsemantics. Empty globs are distinguished from cp failures via acompgen -Gpre-check.modify_clientno longer runs a destructivesedafter a failed backup. Previouslycp "$cf" "$bak" || log_warn "..."— a warning in the log, thensed -iwould destroy the config with no way back. The backup is now a hard gate:if ! cp ...; then log_error + release lock + return 1.regenerate_clientis serialized under a lock and everysedis checked. The function now wraps its body in.awg_config.lock(flock, 10 s timeout) — concurrentregencalls on the same client name can no longer corrupt the client config. The threesed -istatements that restore user settings (DNS, PersistentKeepalive, AllowedIPs) each useif !— on failure the function returns 1 and the lock is released. The lock is held only while.confis being mutated; it is released beforegenerate_qr/generate_vpn_uri, which remain best-effort derived artifacts.modify_clientflock-timeout no longer leaks the fd. The "another operation holds the lock" branch now callsexec {modify_lock_fd}>&-beforereturn 1. Previously the fd stayed open until shell exit.manage_amneziawg.shversion is back in sync between RU and EN. The drifted5.10.0/5.10.1values converge to5.11.0.
CI / build
- ARM matrix: Ubuntu 25.10 and Debian 13 added, Ubuntu 22.04 removed.
.github/workflows/arm-build.ymlnow builds the prebuiltamneziawg.kofor 7 targets: 3× Raspberry Pi +ubuntu-2404-arm64+ubuntu-2510-arm64+debian-bookworm-arm64+debian-trixie-arm64. The matrix matches the installer supported-OS list exactly._try_install_prebuilt_armininstall_amneziawg.shwas updated in sync — new branches*-generic* + 25.10 → ubuntu-2510-arm64and*-arm64* + debian + 13 → debian-trixie-arm64; the dead 22.04 branch is gone. - Timeouts on every workflow job.
shellcheck:10m,test:10m,release:15m,arm-build prepare:5m,build:60m. A hung job no longer quietly burns CI minutes. (Already shipped in the polish PR #55 toward v5.10.2; listed here for completeness.)
Docs
- Minimum
awg0.conffor AWG 2.0 inADVANCED.md/ADVANCED.en.md. A new collapsible section with a ready example for manual setups (amneziawg-goin LXC, etc.): all 11 obfuscation parameters (Jc/Jmin/Jmax/S1-S4/H1-H4), notes about S3/S4 (added to AWG 2.0 later than S1/S2 — configs carried over from AWG 1.x may not have them),INT32_MAXupper bound on H1-H4,I1being optional. - Explanation of the
#_Name = <name>marker inside the "Full List of Management Commands" section — previously implicit in examples only. It is now explicit:list/remove/regen/modifyrely on this marker in each[Peer]block; if you migrateawg0.conffrom an old server, add#_Nameby hand. - "LXC / Docker via amneziawg-go (userspace)" section in ADVANCED (source: @Akh-commits, Issue #51). A working recipe for a privileged LXC on Proxmox 9 with a Debian 13 guest, security tradeoffs, prebuilt binary vs source build. Shipped to main before the v5.11.0 tag; listing it here for completeness.
Tests
- +84 new bats (230 total, up from 146 on v5.10.2).
test_state_machine.bats(+18) — atomicupdate_state,boot_idguard, step 2 entry die,request_rebootcapture.test_manage_robustness.bats(+24) —_backup_configs_nolockcontract (LAST_BACKUP_PATH,compgen -G, critical vs optional),modify_clientbackup gate,regenerate_clientlock + sed checks, flock-timeout fd release.test_restore_rollback.bats(+27) —_restore_do_rollbackhelper,trap RETURN+ cleanup contract,_destructive_ops_startedgate, pre-flightvalidate_awg_config, trap/rollback regression guards.test_arm_matrix.bats(+15) — matrix-to-installer cross-reference, RU/EN mapping parity, absence of the dropped 22.04 branch.
- Bonus: 9 tests whose names contained Unicode em-dash/arrow characters (silently skipped by the bats parser) are now ASCII and actually execute.
Breaking changes
- None.
restore_backupexternally behaves as before (success → service up; failure → previously partial state, now rollback); themanageCLI is unchanged; theawgsetup_cfg.initformat stays compatible; SHA256 pins for helpers were updated — a downgrade from v5.11.0 back to v5.10.2 is possible by restoring the previous files.
5.10.2 — 2026-04-20
Urgent hotfix. In v5.10.1 every fresh AmneziaWG 2.0 install died at step 1 with apt_update_tolerant: command not found — on all mirrors, not only Hetzner. If you tried v5.10.1 on a new server, or you're about to deploy from scratch, move to v5.10.2. This release also closes an edge case where apt_update_tolerant could silently ignore a crash (SIGKILL, OOM).
Fixed
- Critical regression in v5.10.1:
apt_update_tolerant: command not foundbroke installation. The function was defined inawg_common.sh, but that file is only downloaded at step 5. The firstapt updateat step 1 (before the system upgrade) and the second at step 2 (after adding the PPA) receivedcommand not found, and installation aborted withdie "apt update error". In v5.10.2 the definition moved inline intoinstall_amneziawg.sh— next tolog/die, following the existing pattern used forgenerate_awg_params. It has been removed fromawg_common.sh. - Edge case in
apt_update_tolerant: silent crash / OOM / SIGKILL are no longer masked. Ifapt-get updatereturned non-zero WITHOUT classifiableE:/Err:/W:lines in stderr (SIGKILL from OOM-killer, silent crash, unknown output format), the function erroneously returned 0 with a "source packages unavailable" message. Now, before falling back to that branch, the output is checked for explicit source-markers; if none are present, the error is propagated. - Regex future-proofing. The pattern
Sources([[:space:]]|$)is replaced withSources([^[:alpha:]]|$)— catches future variants likeSources.xz, while preventing false-match on strings likeSourcesMirror. - Synced header date in
install_amneziawg_en.sh(was2026-04-16, now2026-04-20to match the release).
Tests
- +9 new bats tests (146 total, was 137).
test_apt_tolerant.bats: +3 tests — silent crash (rc!=0, empty stderr), DNS failure withoutE:prefix, regex does not matchSourcesMirror. Function loading migrated fromsource awg_common.shtosedrange extraction frominstall_amneziawg.sh.test_install_defines_apt_tolerant.bats(new, 6 tests) — regression guard: asserts the invariant "definition is inline in both install scripts, absent from awg_common" + all calls follow the definition line.
5.10.1 — 2026-04-19
Compatibility with mirrors that don't publish source packages (Hetzner, AWS, and others) — Discussion #47.
Fixed
apt updateno longer dies on 404 for source packages. Some mirrors (Hetzner Ubuntu, AWS Ubuntu) don't publish source packages, but the default/etc/apt/sources.list.d/ubuntu.sourcescontainsTypes: deb deb-src. The previousapt update -y || diefailed in that case. The newapt_update_tolerantfunction (inawg_common.sh; moved inline intoinstall_amneziawg.shin v5.10.2) ignores 404s only onsource/Sources/deb-src, but propagates every other error (GPG, network, unreachable PPA).- Removed modification of
/etc/apt/sources.list.d/ubuntu.sources. The installer no longer enablesdeb-src— we never used source packages (kernel module installs via DKMS + binary headers), so the modification was unnecessary and caused the issue.
Tests
- +6 new bats tests (137 total, was 131).
test_apt_tolerant.bats: clean update, source-only 404, deb-src 404, GPG error, binary 404, mixed errors.
5.10.0 — 2026-04-16
Mobile network optimization: --preset=mobile and --jc/--jmin/--jmax CLI flags, comprehensive security and reliability audit across the entire codebase (Discussion #38, Issue #42).
Added
--preset=mobileCLI flag for mobile carriers. Locks Jc=3 with narrow Jmax (Jmin+20..80) — confirmed working settings for Tele2, Yota, Megafon, Tattelecom and other carriers that block AWG connections with Jc>3 or Jmax>300.--preset=defaultis also available for explicit selection of the standard profile (Jc=3-6, Jmin=40-89, Jmax=Jmin+50..250).--jc=N,--jmin=N,--jmax=NCLI flags. Fine-grained override of obfuscation parameters on top of any preset. Jc: 1-128, Jmin/Jmax: 0-1280, Jmax must be ≥ Jmin. Example:--preset=mobile --jc=4uses the mobile profile but with Jc=4 instead of 3.- Protocol boundary validation in
validate_awg_config. Checks AWG parameter ranges after backup restore: Jc (1-128), Jmin/Jmax (0-1280, Jmax ≥ Jmin), S3 (0-64), S4 (0-32), H1-H4 range ordering (lower < upper). AWG_PRESETsaved to configuration. The selected preset is recorded inawgsetup_cfg.initfor diagnostics and reproducibility.
Security
- Config parser BOM and CRLF hardening.
safe_load_configandsafe_read_config_keynow strip BOM (UTF-8\xEF\xBB\xBF) and CR (\r) before parsing. Prevents issues when configs are edited in Windows text editors. - Special character escaping in
regenerate_client.sedreplacements properly escape&,\,/in values, preventing injection through client keys. - GitHub Actions pinned to SHA. All 7 actions across 4 workflows are pinned to specific commit SHAs instead of mutable tags (supply chain protection).
- Endpoint masking in diagnostic report.
generate_diagnostic_reportreplaces the server IP address with***MASKED***for safe sharing of diagnostic output. - File permissions for vpn:// URIs.
secure_filesandrestore_backupsetchmod 600for.vpnuriand.png(QR code) files. - Client name validation in
set_client_expiry. Prevents path traversal through client names. - Quoted paths in cron file.
install_expiry_cronproperly quotes paths with spaces.
Reliability
- TOCTOU fix in
modify_client. Parameter validation moved before lock acquisition, client state checks moved inside the lock. File descriptor is properly closed on all error paths. - Correct service restart. Step 7 now detects an already-running service and uses
enable + restartinstead of a duplicateawg-quick up, preventing the "interface already exists" error. - I1 stale value fix.
load_awg_paramsclearsAWG_I1before parsing the server config, preventing CPS parameter contamination from the initial configuration. - Forced regeneration with CLI flags. Re-running with
--presetor--jc/--jmin/--jmaxforces AWG parameter regeneration even when the config already exists. - ARM prebuilt step completion. The prebuilt
.debinstallation path now correctly updates state and requests a reboot, preventing an infinite step-2 loop. - Correct regex in
release.yml. Dots are now escaped in the version pattern (5\.10\.0instead of5.10.0). - Extended preflight in
build-arm-deb.sh. Addedmodinfo,sha256sum,awk,xzchecks, kernel detection via/lib/modules/*/build, emptyMODULE_VERguard.
CI/CD
- Expanded ShellCheck scope. Workflow now lints
scripts/*.shandtests/*.bashin addition to root.shfiles. - Test workflow hygiene. Added
permissions: contents: readandconcurrencygroup to prevent parallel runs.
Tests
- +33 new bats tests (131 total, up from 98).
test_preset.bats(18): preset selection, CLI overrides, validation.test_validate.bats(+8): protocol boundary checks.test_safe_load_config.bats(+4): CRLF, BOM, BOM+CRLF, values with=.test_validate_endpoint.bats(+3): full IPv6, single-label hostname, empty brackets.
📣 Main features of the 5.x branch — see the v5.8.0 release notes. ARM support — see v5.9.0. v5.10.0 adds mobile network optimization and a comprehensive audit with no breaking changes.
5.9.0 — 2026-04-15
Raspberry Pi (arm64 and armhf) and ARM64 server support (AWS Graviton, Oracle Ampere, Hetzner arm64). Full implementation by @pyr0ball (PR #43, Issue #37).
Added
- Prebuilt kernel modules for ARM. A new GitHub Actions workflow (
.github/workflows/arm-build.yml) buildsamneziawg.kofor 6 ARM targets via QEMU on everyv*tag push. Targets:rpi-bookworm-arm64(Raspberry Pi 3/4),rpi5-bookworm-arm64(Pi 5 / Cortex-A76),rpi-bookworm-armhf(Pi 3/4 32-bit),ubuntu-2404-arm64,ubuntu-2204-arm64,debian-bookworm-arm64. Built.debplus.sha256are published to a dedicatedarm-packagesrelease. Build script (scripts/build-arm-deb.sh) can also be run manually on ARM hardware outside CI. - Automatic install path selection on ARM. On
aarch64/armv7l, step 2 first tries the prebuilt.debfrom thearm-packagesrelease (kernel vermagic must match exactly) and falls back to DKMS silently if it does not. Curl uses--max-time 60to avoid hangs; SHA256 is verified beforedpkg -i. Saves time and RAM on minimal systems without build tools. - Correct kernel headers detection for Raspberry Pi. RPi Foundation kernels (
+rpt/-rpisuffix) now picklinux-headers-rpi-v8orlinux-headers-rpi-2712instead of the non-existentlinux-headers-arm64.amneziawg-tools(userspace) on ARM is already shipped by the PPA for arm64/armhf — no separate build needed. - Bats tests for header selection.
tests/test_rpi_headers.bats— 6 cases:+rpt-rpi-v8→rpi-v8,+rpt-rpi-2712→rpi-2712, legacy-rpi-v8, mainline arm64 Debian, amd64, generic Ubuntu kernel.
Tests
- x86_64 regression on a clean Ubuntu 24.04 LTS, kernel 6.8.0-110-generic: DKMS build, module load,
awg show,manage add/list/backup, uninstall — all unchanged. The ARM path is skipped correctly on x86_64,_try_install_prebuilt_armis not invoked. - ARM end-to-end on a Raspberry Pi 4 / Debian 12 / kernel
6.12.75+rpt-rpi-v8(DKMS path, prebuilts not published at PR time): full install lifecycle,awg-quick@awg0active, vermagic matches.
Out of scope for this release
- OpenWrt — separate package ecosystem, needs the OpenWrt SDK
- Auto-tracking kernel updates / broken-package detection
- Armbian and other SBC vendor kernels (follow-up)
📣 Main release notes for the 5.x branch — see the v5.8.0 release notes. v5.9.0 is a minor bump adding ARM support with no breaking changes for existing x86_64 installs.
5.8.4 — 2026-04-13
Reliability and security hardening following a review of the installer and management script.
Security
- Extended file type check in
restore_backup. The verbose archive listing (tar -tvzf) now checks the type of each entry by its first character. Archives containing block devices (b), character devices (c), FIFOs (p), hardlinks (h), or symlinks (l) are rejected before extraction. The--no-same-permissionsflag is also added to the extract step so file permissions are always derived from the process umask, never from archive metadata. Protects against crafted archives that bypassed the path checks introduced in v5.8.3. - IPv4 octet range validation in
validate_endpoint. Previously the regex accepted999.0.0.1as a "valid" IPv4 address because[0-9]{1,3}did not check the numeric value. A second pass viaBASH_REMATCHnow verifies each octet is in the 0-255 range.validate_endpoint "256.0.0.1"andvalidate_endpoint "999.999.999.999"now correctly return 1. restore_backup— abort on first copy error. All five criticalcp -aoperations (server/, clients/, keys/, server_private.key, server_public.key) are now explicitly checked. On failure both locks are released and the function returns 1 immediately with a message identifying which file failed. Prevents a half-restored configuration from being left in place.
Reliability
- File locks in
backup_configsandrestore_backup.backup_configs()now acquires.awg_backup.lock(30 s timeout) before creating the archive.restore_backup()acquires.awg_backup.lock(outer) and.awg_config.lock(inner, 30 s) before extraction. Lock ordering is fixed (backup → config), deadlock is impossible. Ifmanage backupandmanage restorerun concurrently the second process waits or exits with a clear diagnostic. - Self-deadlock prevention in
restore_backup. Before this fixrestore_backup()calledbackup_configs()for its safety snapshot — both tried to acquire.awg_backup.lock→ deadlock. An internal_backup_configs_nolock()helper was extracted;restore_backup()calls it inside its own locked scope.backup_configs()(the public entry point) keeps its own lock acquisition. - UFW exit code checks in
setup_improved_firewall. Everyufwcommand (default deny/allow, limit SSH, allow VPN port, route rule) on both branches (inactive and active) now checks the exit code. Accumulated errors causereturn 1. Previously a single UFW rule failure did not abort firewall setup. - SHA256 bypass logged at WARN level. When starting with a custom
AWG_BRANCH(used during branch testing) the SHA256 check is skipped. This was previously logged atlog_debug, invisible in normal output. Now it logs atlog_warnso developers can see that integrity was not verified.
Tests
- +7 new bats tests.
test_validate_endpoint.bats+4: reject999.999.999.999,256.1.1.1; accept255.255.255.255,0.0.0.0.test_restore_backup.bats+1: real archive + mock tar injecting a block device entry → type-check rejects (proper negative test with real archive creation).test_apply_config.bats+2: flock timeout returns 1; systemctl restart failure returns non-zero. Total: 92 bats tests, all PASS.
📣 The main release notes bundle for the 5.8.x branch lives in v5.8.0 release notes. v5.8.4 is a hardening patch on top of 5.8.3 with no breaking changes.
5.8.3 — 2026-04-11
A batch of hardening fixes and targeted improvements following Issue #42 and an internal audit.
Security
- Downloaded script integrity check (SHA256).
install_amneziawg.shin step 5 now computessha256sumforawg_common.shandmanage_amneziawg.shright aftercurland compares the result to hardcoded values updated at each release. On mismatch the installer aborts. Protects against tampering on an intermediate hop or a compromise of raw.githubusercontent.com. Verification is automatically skipped whenAWG_BRANCHis overridden by the user for testing a custom branch. - Tar archive validation before extraction in
restore_backup. Before extraction the script reads the file list viatar -tzfand rejects the archive if it contains absolute paths (/etc/...) or path traversal (..). After extraction it scans the unpacked tree for symlinks and rejects the archive if any are found. Plustar -xzf --no-same-ownerto guarantee extracted files are owned by root rather than by metadata inside the archive. Protects against crafted or tampered backups.
Fixed
- Mobile internet — Yota/Tele2 blocked VPN (Issue #42). Reported by @markmokrenko: after a standard install the VPN fails to connect on Yota and Tele2, while Beeline works. Root cause:
Jmin/Jmaxvalues. This continues the Discussion #38 story — mobile carriers are sensitive to junk packet size. Lowered theJmaxoffset fromJmin+100..500toJmin+50..250, the maximum junk packet size drops from ~590 to ~340 bytes. Obfuscation strength is preserved, mobile compatibility improves.
Tests
- 4 new bats tests for
restore_backuptar validation: happy path (good backup), absolute path rejection, path traversal rejection, server keychmod 600. Total: 85 bats tests, all PASS.
Live VPS tests
The release was validated on a clean Ubuntu 24.04 LTS: 13/13 checks passed. Tar validation was tested against three attack types — path traversal, absolute paths, symlinks. The SHA256 verify_sha256 function was tested with both correct and incorrect hash inputs. UFW routing cleanup during --uninstall was confirmed.
📣 The main release notes bundle for the 5.8.x branch lives in v5.8.0 release notes. v5.8.3 is a hotfix on top of 5.8.2 with security hardening and a narrower Jmax range for mobile networks.
5.8.2 — 2026-04-10
Fixed
- Hoster VNC console breaks, network drops on Hetzner (Discussion #41):
rp_filterlowered from1(strict) to2(loose). Strict mode broke routing on cloud hosters (Hetzner and similar) where the gateway is in a different subnet. Addedkernel.printk = 3 4 1 3to suppress kernel warning messages in the VNC console. Thanks @z036. --uninstallnow correctly removes UFW routing rules: addedout on <nic>to the delete command — UFW requires an exact match with the rule that was created during install.- Default
Jclowered from 4-8 to 3-6 (Discussion #38): mobile networks (LTE/5G) do not tolerate large amounts of junk packets well. @elvaleto confirmed thatJc=3works reliably on Tattelecom (Letai).
Documentation
- ADVANCED.md/en FAQ: added 2 new entries — Jc/I1 recommendation for mobile networks and workaround for the VNC/Hetzner rp_filter issue. Parameter table updated:
Jcrange4-8 → 3-6.
5.8.1 — 2026-04-09
Targeted hotfix on top of v5.8.0 following Discussion #40 from @z036: the randomized H1-H4 values from v5.8.0 could fall into the [2^31, 2^32-1] range, which the amneziawg-windows-client config editor underlines as invalid and refuses to save. The server (amneziawg-go) accepts the full uint32; the issue is purely in the client-side UI validator.
Fixed
- H1-H4 Windows client compatibility (Discussion #40):
generate_awg_h_rangesnow caps the upper bound at2^31-1 = 2147483647instead of the fulluint32. This matchesisValidHField()in amnezia-vpn/amneziawg-windows-client#85 (upstream bug, open since February 2026, not yet fixed). Implementation: a0x7FFFFFFFbit mask is applied to theod -N32 -tu4 /dev/urandomoutput, and the fallback path now usesrand_range 0 2147483647. No bias is introduced — each lower bit stays independent. Obfuscation strength is not weakened: four non-overlapping pairs in[0, 2^31)with a minimum width of 1000 each still give an astronomically large key space, DPI cannot fingerprint by default values. Thanks @z036 for the precise screenshot with the underlined fields.
Compatibility
- Existing v5.8.0 installs continue to work on the server side.
amneziawg-goaccepts the fulluint32, handshake with clients is not affected. The only inconvenience is thatamneziawg-windows-client's config editor underlines H2-H4 in red if they happen to land in the upper half of the range (~99.6% of fresh v5.8.0 installs). The cross-platformamnezia-client(Qt, Android/iOS/Desktop) does not have this limit. - Upgrading from v5.8.0 is recommended if you use
amneziawg-windows-client: runsudo bash /root/awg/install_amneziawg.sh --uninstall --yes, then install v5.8.1 fresh. New H1-H4 values will land in the safe half of the range. - Algorithm and config format are unchanged, only the generation space is narrower. No breaking changes for the server or existing client
.conffiles.
Tests
tests/test_h_ranges.batsupdated: upper-bound check changed from2^32-1to2^31-1, plus a new regression test running the generator 20 times × 8 values (160 samples) and asserting every value is ≤ 2147483647. Total: 81 bats tests (+1 from 5.8.0).
Documentation
- ADVANCED.md/en FAQ: added an entry about the upstream
amneziawg-windows-clientbug with a root-cause explanation, links to upstream issue #85 and Discussion #40, and three workaround options for v5.8.0 users.
📣 The main release notes bundle for the 5.8.x branch lives in v5.8.0 release notes. That is where the full Discussion #38 (Russian DPI fingerprinting) context and the multi-round code-audit story lives. v5.8.1 is a hotfix on top of 5.8.0, recommended for everyone using the Windows client.
5.8.0 — 2026-04-07
Major security and reliability update after several consecutive code audits. The reason for a minor bump instead of a patch release is the significant volume of breaking-semantics changes in config handling, parameter source of truth, and error propagation.
Security
-
Russian DPI fingerprinting via static H1-H4 (Discussion #38): The H1-H4 ranges in
generate_awg_paramswere hardcoded identically across all installs (100000-800000,1000000-8000000, ...). Russian DPI fingerprinted this static signature — installs stopped working over Russian mobile carriers. H1-H4 are now randomized per install: 8 random uint32 values are sorted and grouped into 4 non-overlapping pairs. Every install gets unique ranges with no static signature. Thanks @Klavishnik (report) and @elvaleto (diagnosis). -
Split-brain prevention in
load_awg_params: When the liveawg0.confexists, it is now the SOLE source of truth for AWG protocol parameters. A partially corrupt live config (for example, a missing H4 field) produces an explicit error with return 1 instead of silently falling back to stale values from the init file. This closes a class of split-brain bugs where the server runs one config whileregenwould issue clients a different set of J*/S*/H*. -
Atomic export in
load_awg_params_from_server_conf: The parser no longer exportsAWG_*variables as it finds each field. It now either reads all 11 required fields successfully and exports them, or the environment is not modified at all. Protects against mixed state whenawg0.confis partially corrupt. -
restore_backupforceschmod 600on restored server keys instead of inheriting the mode from the archive viacp -a. Protects against restoring keys with broken permissions if the backup was created with a bad umask. -
--uninstallno longer disables UFW globally (HIGH severity, audit). Previouslyufw --force disablewiped the entire firewall on a VPS where UFW was used for SSH/web hardening before our script was installed. The installer now writes a marker.ufw_enabled_by_installeronly if UFW was inactive before installation, and uninstall disables UFW only when that marker is present. Backwards compat: older installs without the marker get safer-by-default — UFW stays active. -
Process-wide install lock (audit). Two concurrent
install_amneziawg.sh --yesruns could read the samesetup_state, race each other onapt-getand corrupt package state.flock -non$AWG_DIR/.install.lockis now taken at the start of main() for the entire process lifetime — a second instance getsdie "Another installer is already running". -
--endpointvalidation (audit). Previously the value was accepted verbatim and written to init and client.conf without any sanity check. Newlines or quotes in the endpoint could smuggle extra directives into configs. A newvalidate_endpoint()function rejects newlines, CR, quotes, backslashes, and requires FQDN / IPv4 /[IPv6]format.
Fixed
-
regendid not update AWG parameters in client configs (#38):load_awg_paramsonly read AWG parameters from the cached/root/awg/awgsetup_cfg.init, not from the live/etc/amnezia/amneziawg/awg0.conf. If a user manually editedawg0.conf(for example, to change obfuscation parameters),regenproduced client configs with stale values.load_awg_paramsnow reads the live server config first, with the init file used only as a bootstrap fallback on first install. Added new functionload_awg_params_from_server_conf. -
manage add/removeignoredapply_configexit code (audit). On apply_config failure the commands still logged "Configuration applied" and returned success — the user saw "OK" while the peer was applied only to the config file, not to the live interface. The caller now checks the return code, logs an actionable error pointing atsystemctl status, and sets_cmd_rc=1. -
check_expired_clientsleft peers on the live interface on apply failure (audit). If apply_config failed after expired peers were removed from state files, the peer vanished fromexpiry/but remained active on the interface until a manual restart. Permanent stuck state. The function now checks the return code and returns 1 with an actionable message. -
--uninstallremoved/etc/fail2ban/jail.localby heuristic (audit). Previously the entire file was deleted if it containedbanaction = ufw— too broad a filter, could wipe an unrelatedjail.localwith custom jails. The removal block has been dropped entirely, leaving onlyrm -f /etc/fail2ban/jail.d/amneziawg.conf(our own artefact). -
check_serverdid not checkawg showexit code (audit). Could report "State OK" even whenawgitself crashed. The command is now captured and its exit code verified. -
backup_configs/restore_backupleaked temp directories on SIGINT (audit).mktemp -dwas used directly, while the_awg_cleanuptrap only removed files. A newmanage_mktempdirhelper registers the dir in an array and chains cleanup properly. -
add_peer_to_servernow takes an inner flock to protect against direct calls outsidegenerate_client(defense-in-depth, self-audit). The "caller must hold the lock" contract was fragile. -
check_expired_clientsvalidates the client name before using it in paths (defense-in-depth, self-audit). Previouslyname=$(basename "$efile")was used without validation. -
Backup file names no longer contain colons:
%F_%T→%F_%H-%M-%S. Colons are incompatible with FAT/NTFS when copying backups to another medium. -
apply_confighas an explicitreturn 0on the success path — removes exit-code ambiguity fromexec {fd}>&-.
Optimizations
generate_awg_h_rangesdoes a single/dev/urandomread instead of 8rand_rangesubprocess calls.od -An -N32 -tu4 /dev/urandomreads 32 bytes = 8 uint32 values in one operation. Falls back torand_rangeif/dev/urandomis unavailable.
Tests
- 80 bats tests (+34 from the 5.7.12 baseline of 46 tests):
test_h_ranges.bats— 9 H1-H4 generation checkstest_load_awg_params.bats— 14 awg0.conf parser, init-file priority, split-brain prevention, atomic export, bootstrap path checkstest_validate_endpoint.bats— 14 validate_endpoint checks (valid FQDN/IPv4/IPv6, reject newline/CR/quotes/space/backslash/empty)
- All 46 existing tests (apply_config, IP allocation, parse_duration, peer management, safe_load_config, validate) still pass without regressions.
Documentation
- ADVANCED.md/en FAQ: added workflow "Rotating obfuscation parameters when DPI detects them" — how to edit
awg0.conf+ restart + regen, noting that as of 5.8.0 regen reads the live config.
5.7.12 — 2026-04-06
Fixed
- Fail2Ban on Debian (Discussion #39): On Debian 12/13 rsyslog is not installed — fail2ban crashed without
/var/log/auth.log. Addedbackend = systemdandpython3-systemdpackage for Debian. Ubuntu continues usingbackend = auto.
5.7.11 — 2026-03-31
Fixed
- regen corrupts Address on Debian/mawk (#31):
\sin awk (PCRE extension) not supported by mawk. Replaced with[ \t]. Also replacedgrep -oPwith POSIX-compatiblesedfor private key extraction. - regen loses values after modify (#31): User settings (DNS, PersistentKeepalive, AllowedIPs) changed via
modifyare now preserved during config regeneration. - modify leaves .bak files (#31): Backup file is now deleted after successful parameter change.
- check fails to detect port on Debian (#31):
grep -qPreplaced with POSIX-compatiblegrepin all 6 port-checking locations.
5.7.10 — 2026-03-31
Added
- Batch remove clients (#30):
manage remove client1 client2 client3— remove multiple clients in one command with a single apply_config at the end. - AWG_SKIP_APPLY=1 (#30): Environment variable to skip apply_config entirely. Allows accumulating changes and applying once — for automation and API integrations. Correct "Apply deferred" message instead of "Configuration applied".
- flock in apply_config (#30): Inter-process lock (
${AWG_DIR}/.awg_apply.lock) prevents concurrent restart/syncconf calls. - Unit tests (bats-core): 43 tests for awg_common.sh — parse_duration, safe_load_config, IP allocation, peer management, apply_config modes, validate. CI workflow
.github/workflows/test.yml.
5.7.9 — 2026-03-25
Added
- Config apply mode (#30): New
--apply-mode=restartoption formanage_amneziawg.sh. Switches to full service restart instead ofawg syncconf— bypasses upstream deadlock in amneziawg kernel module (amneziawg-linux-kernel-module#146). Persists viaAWG_APPLY_MODE=restartinawgsetup_cfg.init.
5.7.8 — 2026-03-24
Added
- Batch add clients (#29):
manage add client1 client2 client3 ...— create multiple clients in one command.awg syncconfis called once at the end instead of N times. Prevents kernel panic during mass client creation (upstream bug amneziawg-linux-kernel-module#146).
5.7.7 — 2026-03-24
Fixed
- Peer loss on reinstall:
render_server_configoverwroteawg0.conffrom scratch. Existing[Peer]blocks are now automatically restored from backup when step 6 re-runs. - Race condition when adding clients (TOCTOU):
get_next_client_ipandadd_peer_to_servernow execute in a single critical section (flockingenerate_client). Two paralleladdoperations can no longer pick the same IP. - Silent restore success on failure:
restore_backupnow returns non-zero exit code when file copy errors occur, instead of silently reporting success. - Config parser double quote support:
safe_load_confignow correctly handles double-quoted values ("value") in addition to single quotes.
5.7.6 — 2026-03-24
Fixed
- UFW blocks VPN traffic (Discussion #28): Added
ufw route allow in on awg0 out on <nic>rule during firewall setup. Previously, the defaultdeny (routed)policy blocked forwarded packets from awg0 to the main interface, despite PostUp iptables rules. The rule is automatically removed on uninstall. - PostUp FORWARD ordering: Changed
iptables -A FORWARDtoiptables -I FORWARDto insert the rule at the top of the chain. Ensures correct routing when UFW is absent (--no-tweaks).
5.7.5 — 2026-03-20
Fixed
- Trailing newlines in awg0.conf (#27): Multiple blank lines accumulated in the server config after peer removals. Added normalization via
cat -son each remove. - Timeout for awg syncconf (#27):
awg-quick stripandawg syncconfare now called withtimeout 10. On hang (upstream deadlock amneziawg-linux-kernel-module#146), the script falls back to a full service restart instead of waiting indefinitely.
5.7.4 — 2026-03-20
Fixed
- MTU 1280 by default (Closes #26): Server and client configs now include
MTU = 1280. Fixes smartphone connectivity over cellular networks and on iPhone. - Jmax cap: Maximum junk packet size capped at
Jmin+500(wasJmin+999). Prevents fragmentation with MTU 1280. - validate_subnet: Last subnet octet must be 1 (server address). Previously allowed arbitrary values, causing conflicts with
get_next_client_ip. - awg show dump parsing: Interface line skipped via
tail -n +2instead of unreliable empty psk field check. - manage help without AWG:
helpand empty command show usage beforecheck_dependencies, allowing--helpwithout AWG installed. - help text: Installer help now lists all 4 supported OS (Ubuntu 24.04/25.10, Debian 12/13).
- manage --expires help: Added
4wformat to--expireshelp text (already supported by parser, but missing from help).
Improved
- IP caching:
get_server_public_ip()caches the result — repeated calls (add/regen) skip external service requests. - O(N) IP lookup:
get_next_client_ip()uses an associative array for free IP lookup instead of O(N²) nested loops.
Documentation
- Fixed client compatibility table:
amneziawg-windows-client >= 2.0.0supports AWG 2.0 (previously incorrectly listed as AWG 1.x only). - Fixed APT format for Ubuntu 24.04: DEB822
.sources(was.list). - Fixed
restoreexample in migration FAQ: correct path/root/awg/backups/. - Fixed uninstall reference in EN README FAQ:
install_amneziawg_en.sh. - Added Ubuntu 25.10 to the "Which hosting?" FAQ answer.
- Updated config examples: added
MTU = 1280. - Updated Jmax range in parameters table:
+500instead of+999. - Rewrote MTU section: automatic for v5.7.4+, manual workaround for older versions.
- Removed "MTU not set" from Known Limitations.
- Updated "How to change MTU?" FAQ for automatic MTU.
5.7.3 — 2026-03-18
Fixed
- Uninstall SSH lockout: UFW is now disabled BEFORE fail2ban unban — prevents SSH lockout if the connection drops during uninstall.
- CIDR validation (strict): Invalid CIDR in
--route-customnow callsdie()in CLI mode. In interactive mode — retry prompt. Previously, installation continued with invalid AllowedIPs. - validate_subnet .0/.255: Subnets with last octet 0 (network address) or 255 (broadcast) are now rejected.
- ALLOWED_IPS resume: Custom CIDR values (mode=3) are now validated when resuming installation from saved config.
- modify sed mismatch: Synchronized sed pattern with grep in
modify_client()— handles .conf files with any whitespace formatting around=. Added post-replacement verification. - --no-color ANSI leak: Fixed ESC code
\033[0mleaking intolist --no-coloroutput. - Uninstall wildcard cleanup: Removed meaningless wildcard patterns from uninstall —
*amneziawg*files in/etc/cron.d/and/usr/local/bin/were never created.
Documentation
- Added AmneziaWG for Windows 2.0.0 as a supported client.
- Removed misleading note about curl requirement on Debian.
5.7.2 — 2026-03-16
Security
- safe_load_config(): Replaced
sourcewith a whitelist config parser inawg_common.sh— only permitted keys (AWG_, OS_, DISABLE_IPV6, etc.) are loaded from the file. Eliminates potential code injection viaawgsetup_cfg.init. - Supply chain pinning: Script download URLs are pinned to the version tag (
AWG_BRANCH=v${SCRIPT_VERSION}) instead ofmain. TheAWG_BRANCHvariable can be overridden for development. - HTTPS for IP detection:
get_server_public_ip()uses HTTPS instead of HTTP for external IP detection.
Fixed
- modify allowlist: Removed Address and MTU from allowed
modifyparameters — these are managed by the installer and should not be changed manually. - flock for add/remove peer: Peer addition and removal operations are protected with
flock -xto prevent race conditions during parallel invocations. - cron expiry env: Expiry cron job explicitly sets PATH and uses
--conf-dirfor correct operation in minimal cron environments. - log_warn for malformed expiry: Malformed expiry files are handled via
log_warninstead of being silently skipped. - Dead code: Removed unused functions and variables from
awg_common.sh.
Changed
- list_clients O(N): Optimized
list_clients— single-pass algorithm instead of O(N*M). - backup/restore: Backups now include client expiry data (
expiry/) and cron job. - Version: 5.7.1 → 5.7.2 across all scripts.
5.7.1 — 2026-03-13
Fixed
- vpn:// URI AllowedIPs:
generate_vpn_uri()was hardcoding0.0.0.0/0instead of using actual AllowedIPs from client config — split-tunnel configurations are now correctly passed to the URI. - Fail2Ban jail.d: Installation now writes to
/etc/fail2ban/jail.d/amneziawg.confinstead of overwritingjail.local— user Fail2Ban customizations are preserved. - Fail2Ban uninstall: Uninstall now removes only its own artifacts instead of
rm -rf /etc/fail2ban/. - validate_client_name: Client name validation added to
removeandmodifycommands — previously only worked foraddandregen. - exit code: Management script now returns proper error codes instead of unconditional
exit 0. - expiry cron path: Expiry cron job uses
$AWG_DIRinstead of hardcoded/root/awg/.
Removed
- rand_range(): Removed unused function from
awg_common.sh(installer defines its own copy).
5.7.0 — 2026-03-13
Added
- syncconf:
addandremovecommands now auto-apply changes viaawg syncconf— zero-downtime, no active connection drops (#19). - apply_config(): New function in
awg_common.sh— applies config viaawg syncconfwith fallback to full restart. - --no-tweaks: Installer flag — skips hardening (UFW, Fail2Ban, sysctl tweaks, cleanup) for advanced users with pre-configured servers (#21).
- setup_minimal_sysctl(): Minimal sysctl configuration for
--no-tweaks— onlyip_forwardand IPv6 settings.
Fixed
- trap conflict: Fixed EXIT handler being overwritten when sourcing
awg_common.sh. Each script now owns its trap and chains the library cleanup explicitly.
Changed
- Expiry cleanup: Auto-removal of expired clients now uses
syncconfinstead of full restart. - Manage help: Removed manual restart warning after
add/remove(no longer required). - Version: 5.6.0 → 5.7.0 across all scripts.
5.6.0 — 2026-03-13
Added
- stats:
statscommand — per-client traffic statistics (format_bytes via awk). - stats --json: Machine-readable JSON output for integration and monitoring.
- --expires:
--expires=DURATIONflag foradd— time-limited clients (1h, 12h, 1d, 7d, 30d, 4w). - Expiry system: Auto-removal of expired clients via cron (
/etc/cron.d/awg-expiry, checks every 5 min). - vpn:// URI: Generation of
.vpnurifiles for one-tap import into Amnezia Client (zlib compression via Perl). - Debian 12 (bookworm): Full support — PPA via codename mapping to focal.
- Debian 13 (trixie): Full support — PPA via codename mapping to noble, DEB822 format.
- linux-headers fallback: Auto-fallback to
linux-headers-$(dpkg --print-architecture)on Debian.
Fixed
- JSON sanitization: Safe serialization in JSON output.
- Numeric quoting: AWG numeric parameters properly quoted.
- O(n) stats: Single-pass stats collection instead of multiple calls.
- backup filename:
%F_%T→%F_%H%M%S(removed colons from filename). - cron auto-remove: Cron cleanup when the last expiry client is removed.
- backups perms:
chmod 700aftermkdirfor the backups directory. - apt sources location: Apt sources backup moved to
$AWG_DIRinstead ofsources.list.d. - Multiple minor fixes from code review (19 fixes).
Changed
- Debian-aware installer: OS_ID detection, adaptive behavior (cleanup, PPA, headers).
- Version: 5.5.1 → 5.6.0 across all scripts.
5.5.1 — 2026-03-05
Fixed
- read -r: Added
-rflag to allread -pcalls (15 places) — prevents\from being interpreted as an escape character in user input. - curl timeout: Added
--max-time 60 --retry 2to script downloads during installation — prevents indefinite hanging on network issues. - subnet validation: Subnet validation now checks each octet ≤ 255 — previously accepted addresses like
999.999.999.999/24. - chmod checks: Added error checking for
chmod 600when setting permissions on key files. - pipe subshell: Fixed variable loss in config regeneration loop due to pipe subshell — replaced with here-string.
- port grep: Improved port matching precision in
ss -lunp— replacedgrep ":PORT "withgrep -P ":PORT\s"to avoid false matches. - sed → bash: Replaced
sed 's/%/%%/g'with${msg//%/%%}— removed 2 unnecessary subprocesses per log call. - cleanup trap: Added
trap EXITfor automatic cleanup of installer temp files.
5.5 — 2026-03-02
Fixed
- uninstall: Uninstall proceeded without confirmation when
/dev/ttywas unavailable (pipe, cron, non-TTY SSH) due to defaultconfirm="yes". - uninstall: Kernel module
amneziawgremained loaded after uninstall — addedmodprobe -r. - uninstall: Working directory
/root/awg/was recreated by logging after deletion — moved cleanup to the end. - uninstall: Empty
/etc/fail2ban/and PPA backup.bak-*files remained after uninstall. - --no-color: Reset escape code
\033[0mwas not suppressed with--no-color— fixedcolor_endinitialization. - step99: Duplicate "Cleaning apt…" message — removed extra
logcall beforecleanup_apt(). - step99: Lock file
setup_state.lockwas not removed after installation completed. - manage: Inconsistent spelling "удален"/"удалён" — standardized (RU only).
5.4 — 2026-03-02
Fixed
- step5:
manage_amneziawg.shdownload failure is now fatal (die), consistent withawg_common.sh. - update_state():
die()inside flock subshell did not terminate the main process — moved outside. - step6: Server config backup now created before
render_server_config, not after overwrite. - cloud-init: Conservative detection — cloud-init markers checked first to avoid removing it on cloud hosts.
- restore_backup(): Added non-interactive guard (explicit file path required in automation).
- Subnet: Validation now only allows
/24mask (matches actual IP allocation logic). - Version: Removed stale
v5.1references in logs/diagnostics; introducedSCRIPT_VERSIONconstant.
5.3 — 2026-03-02
Added
- English scripts: Full English versions of all three scripts (
install_amneziawg_en.sh,manage_amneziawg_en.sh,awg_common_en.sh) with translated messages, help text, and comments. - CI: ShellCheck and
bash -nchecks for English scripts. - PR template: Checklist item for EN/RU version synchronization.
- CONTRIBUTING.md: Requirement to synchronize EN/RU when modifying scripts.
5.2 — 2026-03-02
Fixed
- check_server(): Fixed inverted exit code (return 1 on success → return 0).
- Diagnostics restart/restore:
systemctl statusoutput is now correctly captured in the log. - restore_backup(): Server config restoration path now uses
$SERVER_CONF_FILE.
Changed
- awg_mktemp(): Activated automatic temp file cleanup via trap EXIT.
- modify: Added an allowlist of permitted parameters (DNS, Endpoint, AllowedIPs, Address, PersistentKeepalive, MTU). (Address and MTU removed in v5.7.2)
- Documentation: Removed incorrect mention of /16 subnet support.
- Removed dead trap code from install_amneziawg.sh.
5.1 — 2026-03-01
Fixed
- CRITICAL: Command injection via special characters
#,&,/,\inmodify_client()— addedescape_sed()function for escaping. - CRITICAL: Race condition in
update_state()— added locking viaflock -x. - MEDIUM:
curlinget_server_public_ip()could receive HTML instead of IP — added-fflag (fail on error) and whitespace cleanup. - MEDIUM:
$RANDOMfallback inrand_range()gave max 32767 instead of uint32 — replaced with(RANDOM<<15|RANDOM)for 30-bit range. - MEDIUM: Pipe subshell in
check_server()— replaced with process substitution< <(...). - MEDIUM: Awk script in
remove_peer_from_server()didn't handle non-standard sections — added handling for any[...]blocks.
Added
- CI: GitHub Actions workflow — ShellCheck +
bash -non push/PR to main. - GitHub: Issue templates (bug report, feature request) in YAML form format.
- GitHub: PR template with checklist (bash -n, shellcheck, VPS test, changelog).
- SECURITY.md: Security policy, responsible vulnerability disclosure.
- CONTRIBUTING.md: Contributor guide with code and testing requirements.
- .editorconfig: Unified formatting settings (UTF-8, LF, indentation).
- Trap cleanup: Automatic temp file cleanup via
trap EXIT+awg_mktemp(). - Bash version check:
Bash >= 4.0check at the start of install and manage scripts. - Documentation: Config examples, Mermaid architecture diagram, extended FAQ, troubleshooting.
Changed
- Version: 5.0 → 5.1 across all scripts and documentation.
- README.md: Command table expanded to 10 (+ modify, backup, restore), FAQ expanded to 8 questions.
- ADVANCED.md: Added config examples, manage command examples, diagnostics description, update instructions.
5.0 — 2026-03-01
⚠️ Breaking Changes
- AWG 2.0 protocol is not compatible with AWG 1.x. All clients must update their configuration.
- Requires Amnezia VPN >= 4.8.12.7 client with AWG 2.0 support.
- Previous version is available in the
legacy/v4branch.
Added
- AWG 2.0: Full protocol support — parameters H1-H4 (ranges), S1-S4, CPS (I1).
- Native generation: All keys and configs generated using Bash +
awgwith no external dependencies. - awg_common.sh: Shared function library for install and manage scripts.
- Server cleanup: Automatic removal of unnecessary packages (snapd, modemmanager, networkd-dispatcher, unattended-upgrades, etc.).
- Hardware-aware optimization: Automatic swap, network buffer, and sysctl tuning based on server characteristics (RAM, CPU, NIC).
- NIC optimization: GRO/GSO/TSO offload disabling for stable VPN tunnel operation.
- Extended sysctl hardening: Adaptive network buffers, conntrack, additional protection.
- Individual client regeneration:
regen <name>command for regenerating a single client's configs. - AWG 2.0 validation: Verification of all protocol parameters in the server config.
- AWG 2.0 diagnostics:
checkcommand shows AWG 2.0 parameter status.
Removed
- Python/venv/awgcfg.py: Python dependency and external config generator completely removed.
- awgcfg.py bug workaround: Moving
awgsetup_cfg.initduring generation is no longer necessary. - Parameters j1-j3, itime: Legacy AWG 1.x parameters are no longer supported.
Changed
- Architecture: 2 files → 3 files (install + manage + awg_common.sh).
- Install step 1: Added system cleanup and optimization.
- Install step 2: Installs
qrencodeinstead of Python. - Install step 5: Downloads
awg_common.sh+manage(no Python/venv). - Install step 6: Fully native config generation.
- Key generation: Native via
awg genkey/awg pubkey. - QR codes: Generated via
qrencodedirectly (no Python). - Documentation: README.md and ADVANCED.md updated for AWG 2.0.
4.0 — 2025-07-15
Added
- AWG 1.x support (Jc, Jmin, Jmax, S1, S2, H1-H4 fixed values).
- DKMS installation.
- Config generation via Python + awgcfg.py.
- Client management: add, remove, list, regen, modify, backup, restore.
- UFW firewall, Fail2Ban, sysctl hardening.
- Resume-after-reboot support.
- Diagnostic report (
--diagnostic). - Full uninstall (
--uninstall).