wg-easy WireGuard VPN on AWS User Guide
Overview
This image runs wg-easy, the easiest way to run your own WireGuard VPN server and manage it entirely from your web browser. WireGuard is a modern, fast and secure VPN protocol; wg-easy wraps it in a clean admin console where you add and remove peers, download ready-to-use client configuration files and QR codes, and see each client's connection status at a glance.
wg-easy runs as a Docker container with the network capabilities (NET_ADMIN, SYS_MODULE) and IP-forwarding settings a VPN gateway needs. The encrypted WireGuard tunnel is published on UDP port 51820, and the web admin UI binds to 127.0.0.1:51821 on the loopback interface and is fronted by nginx as a reverse proxy on port 80 (and 443 once you add TLS), with the WebSocket upgrade the live interface uses already configured. wg-easy's database of the admin user, the WireGuard interface keys, peers and settings lives on a dedicated EBS data volume mounted at /var/lib/wg-easy, independently resizable and separate from the operating system disk.
On the first boot of every deployed instance, a one-shot service creates the wg-easy admin account with a per-instance password, completes the first-run setup with the instance's own public address (so generated client configurations point at the right endpoint), and records the password in /root/wg-easy-credentials.txt with mode 0600. No shared or default credentials ship in the image. The current release available is wg-easy 15.3.0.
Prerequisites
Before you deploy this image you need:
- An Amazon Web Services account where you can launch EC2 instances
- IAM permissions to launch instances, create security groups, and subscribe to AWS Marketplace products
- An EC2 key pair in the target Region for SSH access to the instance
- A VPC and subnet in the target Region, with a security group allowing inbound TCP port 22 from your management network, inbound TCP port 80 from the networks your operators will reach the admin UI on, and inbound UDP port 51820 from anywhere your VPN clients will connect from
- The AWS CLI (version 2) installed locally if you plan to deploy from the command line
Step 1: Launch the Instance from the AWS Marketplace
Sign in to the AWS Management Console, open the EC2 service, and select Launch instance. Under Application and OS Images choose AWS Marketplace AMIs and search for wg-easy. Select the cloudimg listing and choose Select, then Continue on the subscription summary.
Pick an instance type of t3.small or larger. Choose your EC2 key pair under Key pair (login). Under Network settings select your VPC and subnet, and either create or select a security group that allows inbound TCP port 22 from your management network, inbound TCP port 80 from the networks your operators use, and inbound UDP port 51820 from the networks your VPN clients connect from. Leave the root volume at the default size or larger; the image adds a separate data volume for the wg-easy database automatically.
Select Launch instance. First boot initialisation takes under a minute after the instance state becomes Running and the status checks pass.
Step 2: Launch the Instance from the AWS CLI
The following block launches an instance from the cloudimg wg-easy Marketplace AMI into an existing subnet and security group. Replace <ami-id> with the AMI ID shown on the Marketplace listing, <key-name> with your EC2 key pair name, <subnet-id> with your subnet ID, and <security-group-id> with a security group that opens TCP 22, TCP 80, and UDP 51820 as described above.
aws ec2 run-instances \
--image-id <ami-id> \
--instance-type t3.small \
--key-name <key-name> \
--subnet-id <subnet-id> \
--security-group-ids <security-group-id> \
--block-device-mappings '[{"DeviceName":"/dev/sda1","Ebs":{"VolumeSize":20,"VolumeType":"gp3"}}]' \
--tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=wg-easy-01}]'
The command prints a JSON document on success. Note the instance ID, then retrieve its public address once it is running with aws ec2 describe-instances --instance-ids <instance-id> --query "Reservations[].Instances[].PublicIpAddress" --output text.
Step 3: Connect and Retrieve the Admin Password
Connect over SSH with the key pair you selected and the public IP address from step 2. The SSH login user depends on the operating system of the AMI variant you launched:
| AMI variant | SSH login user |
|---|---|
| wg-easy 15 on Ubuntu 24.04 | ubuntu |
The first boot service runs before the SSH daemon becomes ready, so the credentials file is always in place when you log in for the first time.
ssh <login-user>@<public-ip>
sudo cat /root/wg-easy-credentials.txt
You will see a plain text file containing the web UI URL, the admin username, the per-instance admin password, and the WireGuard tunnel endpoint. From the same SSH session you can confirm the deployment is healthy. All three services are active, the container is healthy, and the WireGuard interface wg0 is listening on UDP 51820:
systemctl is-active docker.service nginx.service wg-easy-firstboot.service
sudo docker ps --format 'table {{.Names}}\t{{.Image}}\t{{.Status}}\t{{.Ports}}'
sudo docker exec wg-easy wg show
active
active
active
NAMES IMAGE STATUS PORTS
wg-easy ghcr.io/wg-easy/wg-easy:15.3.0 Up 3 minutes (healthy) 0.0.0.0:51820->51820/udp, [::]:51820->51820/udp, 127.0.0.1:51821->51821/tcp
interface: wg0
public key: W7QaZaccMZ00Retasuxzc55prnBa6tscp0E6AcSPzk0=
private key: (hidden)
listening port: 51820
An unauthenticated health endpoint is served by nginx for load-balancer and uptime checks:
curl http://<public-ip>/healthz
ok
Step 4: Sign In to the Web UI
Open http://<public-ip>/ in your browser. You are presented with the wg-easy sign-in page. Enter the username admin and the password from /root/wg-easy-credentials.txt.

After signing in you land on the Clients dashboard. On a fresh instance there are no clients yet; every WireGuard peer you add appears here with its tunnel addresses and controls to enable, disable, edit or remove it.

Step 5: Add a VPN Client
Select New Client (or the New button), give the client a name such as my-laptop, and optionally set an expiry date. Select Create Client.

The new client appears in the list immediately, assigned its own tunnel addresses (for example 10.8.0.2). wg-easy generates the client's key pair and a complete WireGuard configuration that points at this instance's public address automatically, so there is nothing to edit by hand.
Step 6: Connect a Device
Each client row offers two ways to onboard a device. Select the QR code icon to display a QR code you can scan straight into the WireGuard mobile app on iOS or Android, and the tunnel is up in seconds.

For a desktop, select the download icon on the client row to download that client's .conf file, then import it into the WireGuard client for Windows, macOS or Linux. Once a device connects you can confirm the peer's handshake and transfer from the same SSH session:
sudo docker exec wg-easy wg show
WireGuard is connectionless, so a client only appears in the peer list once it has sent its first packet through the tunnel. Make sure inbound UDP 51820 is open in the instance security group from wherever your clients connect.
Step 7: Configure HTTPS (Recommended)
The admin UI is served over plain HTTP on port 80 out of the box, which is fine behind a load balancer that terminates TLS or over a trusted management network. For direct internet exposure, put the admin UI behind HTTPS. Point a DNS name at the instance, open port 443 in the security group, install certbot, and obtain a certificate:
sudo snap install --classic certbot
sudo ln -sf /snap/bin/certbot /usr/local/bin/certbot
sudo certbot --nginx -d your-wg-easy-host.example.com
certbot edits the nginx site in place to add the TLS listener and the redirect from port 80. Note that WireGuard itself is always encrypted end to end regardless of the admin UI's TLS; HTTPS here protects the admin console, not the VPN tunnel.
Step 8: Backup and Maintenance
wg-easy stores everything (the admin user, the WireGuard server keys, every peer and all settings) in its SQLite database on the data volume mounted at /var/lib/wg-easy. Back up that directory to preserve your VPN configuration:
sudo tar czf <backup-dir>/wg-easy-$(date +%F).tgz -C /var/lib/wg-easy .
The container runs with --restart=always, so it comes back automatically after a reboot. To update wg-easy, pull a newer pinned image tag and recreate the container against the same data volume; because the database persists on /var/lib/wg-easy, your peers and keys survive the upgrade.
Support
cloudimg provides 24/7 technical support for this image, covering deployment, DNS and public-endpoint configuration, HTTPS and reverse-proxy setup, client onboarding, split-tunnel and allowed-IP configuration, storage and upgrade planning. All product and company names are trademarks or registered trademarks of their respective holders. Use of them does not imply any affiliation with or endorsement by them.