Here's how I set up an AmneziaWG 3.1 server on a plain Ubuntu or Debian VPS: one bash script, the kernel module, no Docker and no web panel. It takes 15 to 25 minutes, mostly apt and building the kernel module.
AmneziaWG is the WireGuard fork built to get past DPI, and 3.1 is its newest generation. The official way to get a 3.1 server is the Amnezia VPN app, which logs into your server over SSH and runs AmneziaWG there in Docker. I wrote and maintain amneziawg-installer, the script I use below. Since v6.0.0 a fresh install sets up 3.1 by default.
What 3.1 changes
The big one is header encryption. Every install gets its own HeaderProtectionKey, so the header no longer tells an observer what kind of packet it's looking at. Data packets also get extra padding (ContentPaddingAddition). The obfuscation you may know from 2.0 is still there: junk packets (Jc), random padding on protocol messages (S1-S4) and the I1 packet sent before the handshake.
The Amnezia team now tells people to move even if 2.0 still works for them, because "AmneziaWG 2.0, like AmneziaWG 1.5, has become vulnerable to blocking" (Amnezia docs).
One thing before you start. If your carrier blocks the server's IP, or the whole hosting provider, a new protocol generation won't help. 3.1 changes how the packets look, but they still go to the same address.
What you need
- A full virtual machine (KVM or similar) on x86_64. Containers (OpenVZ, LXC, Docker) can't load a kernel module, and the installer stops there.
- Ubuntu 24.04 LTS, Ubuntu 26.04 LTS or Debian 13. 3.1 needs kernel 6.7 or newer, and all three have it.
- At least 512 MB of RAM and 2 GB of disk. 1 GB of RAM is comfortable, and one vCPU is plenty for a personal VPN.
- Root over SSH, ideally on a clean minimal install. The script assumes the server does nothing else: it tunes the kernel and network for a VPN and offers to remove packages like snapd.
- An emergency console in your provider's panel. Make sure it works before you start. If SSH ever stops answering, that's how you get back in.
On ARM (Raspberry Pi, Hetzner CAX, Oracle Ampere) the installer still works, but it sets up AmneziaWG 2.0, because 3.1 is x86_64 only for now. Same on a stock Debian 12: its kernel is 6.1, older than 6.7. Either way, the final report tells you why.
If you plan to route traffic from Russian mobile networks, avoid Hetzner. Russian carriers block its subnets widely.
Install
Log in as root and run:
wget -O install_amneziawg_en.sh https://github.com/bivlked/amneziawg-installer/releases/latest/download/install_amneziawg_en.sh
chmod +x install_amneziawg_en.sh
sudo bash ./install_amneziawg_en.sh
If SSH listens on a non-standard port, add --ssh-port=YOUR_PORT so the firewall doesn't lock you out.
The first run asks for the VPN port, the tunnel subnet, IPv6, the routing mode, client isolation and the server name shown in the Amnezia app. Enter takes the value in brackets, and the defaults are fine for most people. It also lists the packages it wants to remove and asks before touching them. Answer n if you want to keep them.
Two prompts trip people up:
-
"Reboot now? [y/N]". Answer
y. Enter means no, and then you have to reboot by hand. Your SSH session drops. Wait a minute or two, log in again and run the same command with the same flags. The script remembers where it stopped. -
"Enable UFW? [y/N]" on the third run. Answer
yhere too. Enter leaves the server without a firewall.
So a normal install has two reboots: one after system prep, one after the kernel module is built. After the second one the script sets up the firewall, starts the service and creates two clients, my_phone and my_laptop.
If you don't want to answer anything, add --yes. It takes the defaults, removes the packages, enables the firewall and reboots on its own. You still have to log in after each reboot and run the same command again.
Connect your devices
Each client gets four files in /root/awg/:
-
name.conf, the text config for AmneziaWG apps, Linuxawg-quickand routers -
name.png, a QR code of that same config -
name.vpnuriandname.vpnuri.png, avpn://link for the Amnezia VPN app
The two QR codes look the same, and it's easy to scan the wrong one. The Amnezia VPN app wants name.vpnuri.png. The AmneziaWG apps want name.png.
Copy them to your computer. Run this on your own machine, not in the SSH session:
scp root@SERVER_IP:/root/awg/my_phone.png .
scp root@SERVER_IP:/root/awg/my_laptop.conf .
If SSH is on another port, scp wants it as -P (capital P): scp -P YOUR_PORT root@SERVER_IP:/root/awg/my_phone.png .
Which app to use:
- Android: WG Tunnel or AmneziaWG, scan
my_phone.pngoff your screen - iPhone, iPad and Mac: AmneziaWG
- Windows: AmneziaWG, import the
.conf - Linux:
awg-quickwith the.conf, or the nm-amneziawg plugin for NetworkManager - Any platform: Amnezia VPN, scan
name.vpnuri.png
Whatever you pick, it has to be a version that understands 3.1. An older app may fail to connect, sometimes without showing any error. I keep a table of clients with the versions that work and recheck it when something changes.
On 13 October I connected to a fresh 3.1 server from Android (AmneziaWG and WG Tunnel) and from Windows. When the phone switched from Wi-Fi to mobile data, both Android apps reconnected in under a second. I didn't test iPhone or Mac that day.
To add a client later:
sudo bash /root/awg/manage_amneziawg.sh add my_tablet
Check that it works
Connect a device, then run this on the server:
sudo awg show awg0
You want a latest handshake from the last two or three minutes. On the device, any "what is my IP" site should show the server's address (with the default routing mode, which sends all traffic through the tunnel).
To see the server's health and which generation it runs:
sudo bash /root/awg/manage_amneziawg.sh check
Look for the line "Installation protocol generation".
When to stay on 2.0
A client without 3.1 support can't connect to a 3.1 server. If any of your devices is a router on stock firmware (stable KeeneticOS, GL.iNet, OpenWrt with an older amneziawg package), uses Hiddify or runs an app that hasn't been updated, install the server on 2.0 from the start:
sudo bash ./install_amneziawg_en.sh --protocol=2.0
Better to decide before you install: switching generations later means a reinstall and a new profile for every client.
Optional: your own I1 packet
I1 is a packet the client sends before the handshake, so the start of the connection looks like some other protocol. By default my installer puts a packet shaped like a DNS response there. Since v6.1.0 you can set your own at install time:
sudo bash ./install_amneziawg_en.sh --i1='<your I1 string>'
A popular choice is a QUIC-shaped packet from Mini QUIC Generator: enter an SNI and copy the "AmneziaWG 1.5+ (I1 = )" field. I tried it with several SNIs, and the strings it gave me (53 to 99 bytes) passed the installer's check as is.
That check runs before anything gets installed. It only allows the tags that both the kernel module and amneziawg-go understand: <b 0xHEX>, <r N>, <rc N>, <rd N> and <t>, written back to back, with the whole packet at most 1024 bytes. It refuses <c>, because amneziawg-go, which the Android, iPhone, Mac and Windows apps run on, won't load a profile with it.
The installer remembers your value, so a later reinstall keeps it. --no-cps, --preset, --mobile, --jc, --jmin and --jmax drop it, with a warning.
On a server that's already running, use --force --i1='...'. That's a full reinstall pass with the same two reboots, so expect a few minutes of downtime. Keys, clients and the other parameters stay as they were, only I1 changes. When it's done, reissue the client profiles with sudo bash /root/awg/manage_amneziawg.sh regen and import them on your devices again. The client is the one sending I1, so the new value only kicks in once it's in their profiles.
Questions I get often
Can I upgrade my 2.0 server to 3.1 in place? No. Updating the scripts keeps the generation. To move over, you run --uninstall and then a fresh install, and every client needs a new profile. Before that, run sudo bash /root/awg/manage_amneziawg.sh backup and copy the archive to your own machine, because --uninstall deletes /root/awg/ along with the backups folder inside it. That backup is also your way back to 2.0 if you need it.
Why does the profile leave out RandomTrailers and DisableCookies? RandomTrailers has to be on at both ends, so a server with it cuts off every client that doesn't have it. In my tests it also cut throughput 85 to 133 times when combined with the rest of the obfuscation. DisableCookies removes the protection against handshake floods. 3.1 works fine without either, so the installer doesn't write these lines at all.
Will it get through my ISP? I can't promise that. It depends on the network and on the parameters. If the handshake shows up but traffic dies after a few kilobytes, read the section on AS-level blocking before you reinstall anything.
The full guide, with every flag, updates and uninstall, is INSTALL_VPS. If something here doesn't match what you see on your server, open an issue in the repository.













