On-demand personal VPN using:
- AmneziaWG (WireGuard fork with DPI obfuscation) via wg-easy (Docker)
- AWS as cloud provider (spot instance for cost savings)
- Terraform for infrastructure
- AWS SSM Session Manager for secure panel access (no SSH, no open port 22)
Standard WireGuard has a recognizable handshake signature that Deep Packet Inspection (DPI) systems can detect and block without decrypting traffic. This setup uses AmneziaWG — a WireGuard fork that injects junk packets and scrambles headers to make the tunnel unrecognizable to censors.
wg-easy runs AmneziaWG's userspace implementation (
amneziawg-go, bundled in the image) and auto-configures obfuscation parameters (Jc, Jmin, Jmax, S1, S2, H1-H4) at first startup — no kernel module install required.
Clients must use AmneziaWG-compatible apps (standard WireGuard apps will not connect):
| Platform | App |
|---|---|
| iOS / macOS | AmneziaWG or Amnezia VPN |
| Android | AmneziaWG, WG Tunnel, or Amnezia VPN |
| Windows / Linux | AmneziaWG client |
- Terraform
- AWS CLI configured
- AWS Session Manager plugin
git clone https://github.com/felipelaptrin/wireguard.git
cd wireguardcd terraform
terraform init
terraform applyWait ~2 minutes for the instance to boot and Docker to start.
Use SSM port forwarding to access the web UI securely:
bash scripts/tunnel.sh <INSTANCE_ID>The instance ID is printed by terraform output instance_id. Then open http://localhost:51821 in your browser — on first visit, wg-easy shows a setup wizard asking for a username and password. Pick both there; wg-easy v15 has no PASSWORD_HASH env var (that was v14-only), so the admin account is always created this way, not via Terraform.
From the wg-easy panel:
- Click + Add Client
- Mobile (Android/iOS): scan the QR code with the AmneziaWG app (not the standard WireGuard app)
- Desktop: download the
.conffile and import it into the AmneziaWG client
Dual-stack tunnels are only safe if IPv6 is actually routed through them — otherwise it silently goes around the VPN in the clear. With the VPN connected, confirm your IPv6 traffic exits through the server too:
curl -6 ifconfig.meThis should return the VPN server's IPv6 address, not your ISP's. If it fails or times out instead, that means you have no native IPv6 at all on your current network — which is also safe (nothing to leak), just double-check on a network you know is dual-stack (e.g. mobile data) before trusting it.
cd terraform
terraform destroy