Host Your Own VPN Server

Created : September 28, 2025

In this short guide, I will walk you through the process of setting up a personal WireGuard (WG) VPN Server on a $5/month AWS Lightsail instance. Setting up a WireGuard server, generating client configuration file and connecting client to the WG server via a secure tunnel should not take more than 5 minutes. I'm going to use AWS Lightsail for purpose of this demonstration. But you can go ahead and choose your favourite cloud service provider. Or you can setup a WireGuard server on your Raspberry Pi, running inside your home network. You need a static IPv4 address for the following process to work. I'm going to use Ubuntu 24.04 LTS, but the script should work on older and hopefully future versions of Ubuntu too. In case you are on a *very* old release of Ubuntu, I request you to upgrade and enjoy both better features and security.

First, let's go to AWS Lightsail console and create a $5/month instance, running Ubuntu 24.04 LTS. AWS Lightsail console is accessible at https://lightsail.aws.amazon.com. When creating the instance, AWS will ask you to specify geographic location, where this instance will be hosted. I'm browsing from India, so I prefer to choose Singapore or Frankfurt. My personal reason for using a VPN is establishing an encrypted tunnel from my device (be that laptop or mobile) to a remote box, sitting in a data center in Singapore or Frankfurt. And then passing all the traffic, including DNS lookups, over that encrypted tunnel. So even when I'm on public wifi, I can access the Web with a peace of mind. Based on your geographic location and reason for using a VPN, you might want to choose a different location for hosting your Virtual Private Server (VPS).

On AWS Lightsail, I prefer to stick to default dual stack networking (IPv4 + IPv6). I also attach a static IPv4 address to the instance. If you don't do that, your instance IPv4 address will change, after you restart the instance. You can attach a static IPv4 address to the instance, from the networking tab, once the instance is running. On this date of writing, the $5/month VPS on AWS Lightsail comes with following offerings. In my experience this is enough to support 3-5 moderate load WireGuard clients.

  • 2 vCPUs Compute
  • 512MB RAM Memory
  • 20GB SSD Storage
  • 1TB Transfer

Let's log into the VPS over SSH. Check for updates and install, if any are due. Restart the machine if new Kernel is waiting to be installed. It's *generally* better to be on the latest version of any software you use. *Generally*, because, software supply chain attack is really concerning. And they are getting sophisticated. That's why the advice might seem like a double-edged sword. But I don't want to digress.

ssh __LIGHTSAIL__ sudo apt-get update sudo apt-get upgrade -y sudo apt-get autoremove -y sudo systemctl reboot # Optional

In case you reboot the VPS instance, let's SSH into it, again. Clone the repository https://github.com/itzmeanjan/setup-wireguard-vpn where I'm maintaining a BASH script, which will setup WireGuard server on our VPS. Run the only script in that repository, named setup_wireguard_server.sh, with sudo.

ssh __LIGHTSAIL__ git clone https://github.com/itzmeanjan/setup-wireguard-vpn pushd setup-wireguard-vpn sudo ./setup_wireguard_server.sh

A successful execution of WireGuard server setup BASH script should output a console log like below. In following log, we can clearly see our WireGuard server is up and running. It is identified by the public key weYbu1QZrajysq4FSJCEw0PzZEm6T0MhbV38/2hsCg4=. We have configured the network stack of the VPS to forward any IPv4 and IPv6 traffic. And the WireGuard server is expecting new tunnel requests on port 51820. We have to go to AWS Lightsail console, find networking tab of the instance, add firewall rule, so that it can accept any protocol traffic on any port - the most generic configuration. But you may not want that. You need to open only port 51820, for both IPv4 and IPv6 network stacks, and VPN tunneling should work.

[+] This BASH script helps you setup WireGuard VPN server and clients. [?] Have you read this script and understand what it does to your system? (y/n): y [+] Going ahead with setting up WireGuard server. [+] Updating system and installing WireGuard. Hit:1 http://ap-south-1.ec2.archive.ubuntu.com/ubuntu noble InRelease Hit:2 http://ap-south-1.ec2.archive.ubuntu.com/ubuntu noble-updates InRelease Hit:3 http://ap-south-1.ec2.archive.ubuntu.com/ubuntu noble-backports InRelease Hit:4 http://security.ubuntu.com/ubuntu noble-security InRelease Reading package lists... Done Building dependency tree... Done Reading state information... Done All packages are up to date. Reading package lists... Done Building dependency tree... Done Reading state information... Done The following additional packages will be installed: wireguard-tools The following NEW packages will be installed: wireguard wireguard-tools 0 upgraded, 2 newly installed, 0 to remove and 0 not upgraded. Need to get 92.2 kB of archives. After this operation, 345 kB of additional disk space will be used. Get:1 http://ap-south-1.ec2.archive.ubuntu.com/ubuntu noble/main amd64 wireguard-tools amd64 1.0.20210914-1ubuntu4 [89.1 kB] Get:2 http://ap-south-1.ec2.archive.ubuntu.com/ubuntu noble/universe amd64 wireguard all 1.0.20210914-1ubuntu4 [3086 B] Fetched 92.2 kB in 0s (2975 kB/s) Selecting previously unselected package wireguard-tools. (Reading database ... 103351 files and directories currently installed.) Preparing to unpack .../wireguard-tools_1.0.20210914-1ubuntu4_amd64.deb ... Unpacking wireguard-tools (1.0.20210914-1ubuntu4) ... Selecting previously unselected package wireguard. Preparing to unpack .../wireguard_1.0.20210914-1ubuntu4_all.deb ... Unpacking wireguard (1.0.20210914-1ubuntu4) ... Setting up wireguard-tools (1.0.20210914-1ubuntu4) ... wg-quick.target is a disabled or a static unit, not starting it. Setting up wireguard (1.0.20210914-1ubuntu4) ... Processing triggers for man-db (2.12.0-4build2) ... Scanning processes... Scanning linux images... Running kernel seems to be up-to-date. No services need to be restarted. No containers need to be restarted. No user sessions are running outdated binaries. No VM guests are running outdated hypervisor (qemu) binaries on this host. [+] Generating WireGuard server private + public keypair. [+] Writing WireGuard server private + public keypair to respective files. mBs2nlLJZocQff3iS7aR/7zwaxZjC+zim/hHL66/u0w= weYbu1QZrajysq4FSJCEw0PzZEm6T0MhbV38/2hsCg4= [+] Computing pseudo-random IPv6 address prefix. [+] Figuring out publicly visible IPv4 address of WireGuard server. [+] Writing WireGuard server's initial configuration file. [+] Updating WireGuard server's network configuration to forward both IPv4 and IPv6 traffic. net.ipv4.ip_forward=1 net.ipv6.conf.all.forwarding=1 net.ipv4.ip_forward = 1 net.ipv6.conf.all.forwarding = 1 [+] Updating WireGuard server configuration file to add firewall rules. Rules updated Rules updated (v6) Rules updated Rules updated (v6) Firewall stopped and disabled on system startup Command may disrupt existing ssh connections. Proceed with operation (y|n)? y Firewall is active and enabled on system startup Status: active To Action From -- ------ ---- 51820/udp ALLOW Anywhere OpenSSH ALLOW Anywhere 51820/udp (v6) ALLOW Anywhere (v6) OpenSSH (v6) ALLOW Anywhere (v6) [+] Enabling and starting the WireGuard server with systemd. Created symlink /etc/systemd/system/multi-user.target.wants/wg-quick@wg0.service → /usr/lib/systemd/system/wg-quick@.service. ● wg-quick@wg0.service - WireGuard via wg-quick(8) for wg0 Loaded: loaded (/usr/lib/systemd/system/wg-quick@.service; enabled; preset: enabled) Active: active (exited) since Sun 2025-09-28 10:05:07 UTC; 36ms ago Docs: man:wg-quick(8) man:wg(8) https://www.wireguard.com/ https://www.wireguard.com/quickstart/ https://git.zx2c4.com/wireguard-tools/about/src/man/wg-quick.8 https://git.zx2c4.com/wireguard-tools/about/src/man/wg.8 Process: 1978 ExecStart=/usr/bin/wg-quick up wg0 (code=exited, status=0/SUCCESS) Main PID: 1978 (code=exited, status=0/SUCCESS) CPU: 159ms Sep 28 10:05:07 ip-172-26-1-219 wg-quick[1978]: [#] wg setconf wg0 /dev/fd/63 Sep 28 10:05:07 ip-172-26-1-219 wg-quick[1978]: [#] ip -4 address add 10.8.0.1/24 dev wg0 Sep 28 10:05:07 ip-172-26-1-219 wg-quick[1978]: [#] ip -6 address add fd58:c8d6:d02e::1/64 dev wg0 Sep 28 10:05:07 ip-172-26-1-219 wg-quick[1978]: [#] ip link set mtu 1420 up dev wg0 Sep 28 10:05:07 ip-172-26-1-219 wg-quick[1978]: [#] ufw route allow in on wg0 out on ens5 Sep 28 10:05:07 ip-172-26-1-219 wg-quick[2007]: Rule added Sep 28 10:05:07 ip-172-26-1-219 wg-quick[2007]: Rule added (v6) Sep 28 10:05:07 ip-172-26-1-219 wg-quick[1978]: [#] iptables -t nat -I POSTROUTING -o ens5 -j MASQUERADE Sep 28 10:05:07 ip-172-26-1-219 wg-quick[1978]: [#] ip6tables -t nat -I POSTROUTING -o ens5 -j MASQUERADE Sep 28 10:05:07 ip-172-26-1-219 systemd[1]: Finished wg-quick@wg0.service - WireGuard via wg-quick(8) for wg0. [+] Wireguard server should be running. interface: wg0 public key: weYbu1QZrajysq4FSJCEw0PzZEm6T0MhbV38/2hsCg4= private key: (hidden) listening port: 51820 [+] Generating WireGuard client setup BASH script. [+] WireGuard client setup script 'setup_wireguard_client.sh' should be ready to use. [+] Go ahead and give it a read, before you run it.

WireGuard server is setup. It is ready to accept connections from WireGuard peers. To make it easy for you to setup many peers, the script has generated another BASH script, named setup_wireguard_client.sh, which should produce WireGuard peer configuration file, when executed. Let's go ahead and generate a WireGuard client configuration.

$ sudo ./setup_wireguard_client.sh [+] This BASH script helps you setup a WireGuard VPN client. [?] Have you read this script and understand what it does? (y/n): y [+] Going ahead with setting up a WireGuard client. [+] Setting up WireGuard peer with ID: 2. [+] Generating WireGuard peer private + public keypair. [+] Writing WireGuard peer configuration to 'peer2.conf'. [+] Adding peer to the WireGuard server configuration. [+] WireGuard peer configuration file 'peer2.conf' is ready. [+] Use it with your WireGuard client application.

Executing the WireGuard client setup script produced a client configuration file, named peer2.conf. The generated WireGuard peer configuration file is as below. Notice the public key of the peer, in following snippet. It is same as the public key identifier of the WireGuard server, we noted earlier. In WireGuard terminology, there is a secure tunnel between two peers, each identified by their corresponding public keys. These public keys are used for establishing the secure tunnel. Public Key Encryption helps each peer derive a shared secret. Now this shared secret can be used in some symmetric key construction for fast authenticated encryption or longer key derivation or time-to-time ratcheting.

[Interface] PrivateKey = kE4xQ0NQsKfqGhGlbKTenLqYM/D+7C3oqGWE6N07rG8= Address = 10.8.0.2/32 Address = fd58:c8d6:d02e::2/128 DNS = 1.1.1.1, 1.0.0.1, 2606:4700:4700::1111, 2606:4700:4700::1001 MTU = 1420 [Peer] PublicKey = weYbu1QZrajysq4FSJCEw0PzZEm6T0MhbV38/2hsCg4= AllowedIPs = 0.0.0.0/0, ::/0 Endpoint = 43.205.124.63:51820 PersistentKeepalive = 25

Now we can transfer the WireGuard peer configuration file peer2.conf to our local machine. I will rename it to mumbai.conf for clarity. It can be imported into Ubuntu desktop for connecting to the tunnel. Simply go to Ubuntu Desktop settings, find network and click on import VPN configuration from a file, select the mumbai.conf. Enable the VPN connection and check your machine IP address by running the following command. Notice the IP address below, it is same as the endpoint address listed in the WireGuard peer configuration file. As our publicly visible IP address has changed, we can say, VPN tunneling is working.

$ curl -s https://ipinfo.io | jq { "ip": "43.205.124.63", "hostname": "ec2-43-205-124-63.ap-south-1.compute.amazonaws.com", "city": "Mumbai", "region": "Maharashtra", "country": "IN", "loc": "19.0728,72.8826", "org": "AS16509 Amazon.com, Inc.", "postal": "400017", "timezone": "Asia/Kolkata", "readme": "https://ipinfo.io/missingauth" }

In case you want to setup a WireGuard client on your mobile, get target OS specific WireGuard client app installed first. Then transfer the peer configuration file to the mobile device. And import it in the client app. Connect to the secure VPN tunnel. All your traffic should now be flowing through the WireGuard VPN server.

Now that we have setup a WireGuard server and connected a client to it, we can see how easily we can setup more peers. The script allows you to have a maximum of 253 peers, connected to a single WireGuard server. Let's log back into the VPS, where the WireGuard server is running. We have to open the setup_wireguard_client.sh file, find a BASH variable PEER_ID, increment its value by 1, and save the script. Execute the script, just like we did before, with sudo. It should produce a WireGuard peer configuration file, named peer3.conf. Now you can go ahead and use this configuration file in another WireGuard client. In short, after the first peer, for every new peer you want to setup for this WireGuard server, you must increment the PEER_ID, otherwise things won't work as expected. PEER_ID can take a maximum value of 254.

Everytime you add a new peer, the setup_wireguard_client.sh script, adds public key identity of the peer to the WireGuard server. If not done, the WireGuard server won't accept connection from that peer. It means, even though we are running a WireGuard server on public Internet, with relatively loose firewall rules, our WireGuard server will only accept connection from known peers. Following snippet shows status of the WireGuard server, running on the VPS.

$ sudo wg # Notice, the WG server has two peers, which we setup earlier. It will accept connection, only from them. interface: wg0 public key: weYbu1QZrajysq4FSJCEw0PzZEm6T0MhbV38/2hsCg4= private key: (hidden) listening port: 51820 peer: 02fAMrHtu2LzM7EXyeW5FzUXNYC68ql/68KCav1KRVA= endpoint: 152.59.158.244:45928 allowed ips: 10.8.0.2/32, fd58:c8d6:d02e::2/128 latest handshake: 25 minutes, 6 seconds ago transfer: 643.76 KiB received, 4.19 MiB sent peer: 4PbebAIQZJu8cF0fqwkvZOXqXOCP/bpJRYsMh+bj5Cg= allowed ips: 10.8.0.3/32, fd58:c8d6:d02e::3/128

I'd like to end this walk-through with one important reminder. From time to time, you should go ahead and check for OS updates in the VPS, running WireGuard server. And if, any are pending, you should install them. You might have to restart the system. If you do, ensure that you run following command to reload, IPv4 and IPv6 packet forwarding configuration from /etc/sysctl.conf, post reboot. This configuration was added by the server setup script.

sudo sysctl -p # Is there any way to automatically trigger reloading of /etc/sysctl.conf, post system reboot?

I hope this guide inspires you to run your own VPN server, on a $5/month VPS or your Raspberry Pi. I found a blog post by DigitalOcean, titled "How To Set Up WireGuard on Ubuntu 20.04", helpful when setting up my first WireGuard VPN server. The BASH script, we just used for setting up the WG server, is an attempt to ease the process of setting up WireGuard. The inspiration blog from DigitalOcean is accessible at https://www.digitalocean.com/community/tutorials/how-to-set-up-wireguard-on-ubuntu-20-04. Let me know if you stumbled upon any problems, while setting up WireGuard. Cheers.