Post

Setting up Wireguard server on EC2

Setting up Wireguard server on EC2

Let’s explore what network access patterns can be established with Wireguard VPN setup. We will deep dive into the installation process, configuration, generation of client keys and troubleshooting the connection.

What is VPN, why WireGuard?

VPN technology creates an encrypted tunnel between devices or networks, protecting traffic from interception while providing secure access to private resources over untrusted networks.

WireGuard is a modern VPN protocol designed around simplicity, strong cryptography, and high performance, with a much smaller codebase than traditional VPN solutions.

Its fast connection setup, low overhead, and straightforward configuration make it well suited for cloud, mobile, and remote-access VPN deployments.

Compared to OpenVPN, wireguard consumes less server resources and can run on low memory, cpu limited machine. In this setup we will utilize 1 single core ARM machine with 512MB of RAM.

With such installation, it performs well does not drop traffic (verified on 700MB/sec speed).

Network Access patterns that can be established with wireguard VPN

  1. Access to isolated network - such endpoint is entry point to your VPC.
  2. VPC server-mode with forwarding all traffic over encrypted WireGuard VPN tunnel.
  3. VPN split-tunneling, when all internat and intranet traffic is used via direct interfaces, but only some subnets are accessed through wireguard interface.
  4. Muli-sites and multi-clinet connections - same way you can connect different servers, routers, devices to single Wireguard VPN, each of them will get the CIDR from the same network allowing them communicate with each other. Companies are using such topologie to connect together remote offices, datacenters, and cloud services.
  5. Remote access to private assets - home server infrastructure, office servers, and other private resources can be accessed securely and privately through a WireGuard VPN.
  6. Establishing encrypted connection from insecure public networks (public wifi, coffee shops, etc.).

Infrastructure:

infra.png

Preparing EC2 instance for installation

Wireguard server consumes very low resources, I have setup it on instance with ARM cpu and 500MB of RAM. It runs perfectly - there are no freezes, with speed test under load of UDP stream and file transfer CPU load has not increased more then 20%, so probably if there will be smaller instance type it will be enough to setup and run.

1
2
chmod 400 "remote-key.pem"
ssh -i "remote-key.pem" ubuntu@ec2-xx-xx-xx-xx.xx-xxx-1.compute.amazonaws.com

Adding Swap volume

But since I have choosen only 500MB of RAM instance, just to assure I’m adding a 2G swap. Thus if with some spike memory will increase beyond of physical RAM - instance will not be terminated cause SWAP will be used.

1
2
3
4
5
sudo fallocate -l 2G /swapfile
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile
echo "/swapfile swap swap defaults 0 0" | sudo tee -a /etc/fstab

Update OS:

1
apt update && apt upgrade -y

wireguard installation:

1
apt install -y wireguard

generate server keys

1
wg genkey | sudo tee /etc/wireguard/privatekey | wg pubkey | sudo tee /etc/wireguard/publickey

Set proper privatekey permissions

1
chmod 600 /etc/wireguard/privatekey

Check available network interfaces

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host noprefixroute
       valid_lft forever preferred_lft forever
2: ens5: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 9001 qdisc mq state UP group default qlen 1000
    link/ether 0a:xx:xx:a6:xx:9b brd ff:ff:ff:ff:ff:ff
    altname enp0s5
    altname enx0affe1a6ff9b
    inet 172.31.5.70/20 metric 100 brd 172.31.15.255 scope global dynamic ens5
       valid_lft 3258sec preferred_lft 3258sec
    inet6 fe80::8ff:xxxx:fea6:ff9b/64 scope link proto kernel_ll
       valid_lft forever preferred_lft forever

In case interface name can be different eth0, can be other ens3 etc. This interface alias we will use in /etc/wireguard/wg0.conf:

1
sudo nano /etc/wireguard/wg0.conf

You can modify the port number, network CIDR:

1
2
3
4
5
6
[Interface]
PrivateKey = <privatekey>
Address = 10.0.0.1/24
ListenPort = 51830
PostUp = iptables -A FORWARD -i %i -j ACCEPT; iptables -t nat -A POSTROUTING -o ens5 -j MASQUERADE
PostDown = iptables -D FORWARD -i %i -j ACCEPT; iptables -t nat -D POSTROUTING -o ens5 -j MASQUERADE
1
<privatekey> from /etc/wireguard/privatekey

IP forwarding configuration:

1
2
3
4
5
6
7
echo "net.ipv4.ip_forward = 1" | sudo tee -a /etc/sysctl.conf
sudo sysctl -p

$ echo "net.ipv4.ip_forward = 1" | sudo tee -a /etc/sysctl.conf
net.ipv4.ip_forward = 1
ubuntu@ip-xx-xx-xx-xx:~$ sudo sysctl -p
net.ipv4.ip_forward = 1

Enable systemd daemon with wireguard:

1
2
3
sudo systemctl enable wg-quick@wg0
sudo systemctl start wg-quick@wg0
sudo systemctl status wg-quick@wg0

Add clients, register client keys on the server:

Prepare keys for clients connections:

1
wg genkey | sudo tee /etc/wireguard/client1_privatekey | wg pubkey | sudo tee /etc/wireguard/client1_publickey

Update server config with newly generated clients:

1
sudo nano vim /etc/wireguard/wg0.conf

Add following blocks to end of config

1
2
3
4
5
6
7
8
9
10
11
[Peer]
PublicKey = <client1_public_key>
AllowedIPs = 10.0.0.2/32

[Peer]
PublicKey = <client2_public_key>
AllowedIPs = 10.0.0.3/32

[Peer]
PublicKey = <client3_public_key>
AllowedIPs = 10.0.0.4/32

Change with value from ``/etc/wireguard/client1_publickey``

Restart systemd service with wireguard:

1
2
sudo systemctl restart wg-quick@wg0
sudo systemctl status wg-quick@wg0

Client connection setup:

On local machine (laptop, phone) create .conf file for client:

1
nano client_wb.conf
1
2
3
4
5
6
7
8
9
10
[Interface]
PrivateKey = <client_private_key>
Address = 10.0.0.2/32
DNS = 8.8.8.8

[Peer]
PublicKey = server_public_key
Endpoint = <server_ip>:<server_port>
AllowedIPs = 0.0.0.0/0
PersistentKeepalive = 20
1
2
PublicKey is from `/etc/wireguard/publickey``
PrivateKey is from ``/etc/wireguard/client1_privatekey``

Import this configuration file to Wireguard client and click connecting.

Activate security group

At this moment you will see on client side that connection is ongoing and there are sent bytes, however there are zero received bytes. To make server work we need enable Security Group for wireguard port:

port: 51280 protocol: UDP

Check connection after SG has been applied:

1
2
3
4
5
6
7
8
9
10
11
sudo wg show
interface: wg0
  public key: xxxxxxxxxx=
  private key: (hidden)
  listening port: 51820

peer: xxxx=
  endpoint: 178.xx.42.xx:47868
  allowed ips: 10.0.0.2/32
  latest handshake: 11 seconds ago
  transfer: 175.35 MiB received, 718.21 MiB sent

We got a handshake and traffic is going.

Routing specific traffic

When setting up VPN tunnel, you can route specific traffic through the VPN. It support 2 modes:

  • full tunnel
  • split tunnel

This is useful when you want to encrypt and secure only certain applications or services, while leaving others unaffected.

For example, you can route all traffic from a specific application through the VPN, ensuring that only that application’s traffic is encrypted and protected.

Full Tunnel: Set AllowedIPs = 0.0.0.0/0 on the client configuration to route all traffic (including all encapsulated UDP packets) through the VPN.

Split Tunnel: Set AllowedIPs to a specific subnet (e.g., 10.0.0.0/24) so only traffic destined for that remote network uses the WireGuard interface.

Routing DNS traffic

Also, when configuring WireGuard, you can route DNS traffic through the VPN. This is useful when you want to ensure that all DNS queries are encrypted and protected. To do this, you can set the DNS server address in the client configuration to the IP address of the DNS server on the VPN network.

DNS = WIREGUARD_SERVER_IP

or keep to downstrem DNS, like:

DNS = 8.8.8.8

For more complex traffic routing other VPN and proxy solutions should be used, that allow distinguish protocols, ports, geo-zones, traffic snippets, that I will share soon.

This post is licensed under CC BY 4.0 by the author.