Internet Speed Online

Language

Articles

Practical guide

How to Set Up a WireGuard VPN Server on Ubuntu with a Script

Start with a fresh Ubuntu server and finish with a personal VPN connection. This guide explains the server setup, device profiles and checks that show whether your internet traffic is using the tunnel.

Tested: server setup, Linux container connectivity and a Windows speed test. Native macOS, Ubuntu Desktop, iPhone and Android checks are still pending.

When should you use this setup?

Use this setup when you want a personal VPN with an internet exit through a server of your choice, and your network allows WireGuard connections. You choose the provider, server location and devices that can connect.

If your network blocks VPNs, ordinary WireGuard may not be suitable. It does not disguise its connection as ordinary web traffic. Even a correctly configured server may be unreachable through your internet provider. Consider this before paying for a VPS.

For networks with VPN blocking, consider AmneziaWG or Xray with VLESS and REALITY. AmneziaVPN supports setting them up on your own server. They are designed to resist detection and blocking, but neither guarantees a connection from every network.

WireGuard

AmneziaVPN

1. Choose a server and prepare access

This guide describes setting up WireGuard from scratch on an Ubuntu 26.04 LTS VPS. You will need its public IPv4 address and a root password or SSH key. Choose any provider and region that suit your needs.

For this guide, we use a VPS with 1 vCPU and 1 GB of RAM.

Choose a server with IPv4 so you can connect from networks that do not support IPv6. An IPv6-only server needs additional arrangements to reach IPv4-only websites and is not covered here.

Server security: this guide covers VPN installation, not complete VPS security and maintenance. The script configures the firewall for SSH and WireGuard. You remain responsible for security updates and access protection. Use an SSH key, enable two-factor authentication on your hosting account and protect VPN profiles like passwords. Only disable SSH password login after checking that key login works.

2. Check that you can log in over SSH

Windows: open Start, type PowerShell and open it. Mac: press Command+Space, type Terminal and press Enter. Ubuntu Desktop: press Ctrl+Alt+T.

In every command below, replace SERVER_IP with the public IPv4 address from your server control panel. For example, ssh root@SERVER_IP means connecting to your server as root.

Use the password command, or the key command if you already use an SSH key. Replace the example key path with your own.

On your first connection, SSH may ask whether to trust this server. Check that the address is the VPS you just created, type yes and press Enter. Enter the root password when asked; nothing appears on screen while you type it.

Once connected, run the server command below to check Ubuntu, then exit to return to your computer.

Local PowerShell, macOS Terminal or Ubuntu Terminal — password login
ssh root@SERVER_IP
Local PowerShell, macOS Terminal or Ubuntu Terminal — existing SSH key
ssh -i ~/.ssh/id_ed25519 root@SERVER_IP
On the server
cat /etc/os-release
exit
If the ssh command is not found

On Windows, open a new PowerShell window using Run as administrator and run the command below. When installation finishes, close it and reopen ordinary PowerShell. On Ubuntu, use the Ubuntu command below. macOS includes an SSH client.

Windows — install the SSH client, in administrator PowerShell
Add-WindowsCapability -Online -Name OpenSSH.Client~~~~0.0.1.0

Copy the command exactly. OpenSSH.Client~~~~0.0.1.0 is the Windows component identifier; keep the tildes and numbers unchanged.

Ubuntu Desktop — install the SSH client
sudo apt update
sudo apt install openssh-client

3. Download and inspect the setup bundle

Download the ZIP and extract it. Keep the scripts together in the wireguard-guide folder. Choose the Windows, Mac or Ubuntu instructions below; you only need one of these paths.

The script installs WireGuard on your VPS and saves a VPN profile on your computer. It uses one SSH connection for the entire setup. With password authentication, the password is requested once per successful run and is not saved by the script.

Profile names can contain 1-15 English letters (uppercase or lowercase), digits and hyphens, starting with a letter. Spaces are not allowed. Examples: my-wg-vpn, my-laptop, my-phone. If you omit the name, the script asks for it; press Enter to use my-wg-vpn. Invalid names prompt another attempt. Use a different name for each additional device.

To download an existing profile, run the launcher, choose 2 (Manage existing server), connect, then choose 9 (Download profile). Enter a name from the list; Enter without a name cancels. Downloads use the same SSH connection without another server password prompt. A successful download replaces the local file with the same name.

Download setup scripts (.zip)

4a. Set up the server from Windows

Open the extracted wireguard-guide folder in File Explorer. Click its address bar, type powershell and press Enter. This opens PowerShell in the right folder.

Run one of the commands below. Replace SERVER_IP with your VPS address. If using an SSH key, also replace its path.

Choose 1 (Set up server), enter the server IP and a profile name, then an SSH key path or press Enter. Enter keeps the suggested profile name. Check the summary and type yes/y to continue; Type no to cancel. After 3 unrecognized answers, the launcher closes. Progress appears during installation. Pressing Enter also continues.

The profile is saved under your home folder at WireGuard/SERVER_IP/my-wg-vpn.conf. The script prints the full path.

Start with prompts for the server address and profile name
.\Connect-WireGuardServer.ps1
PowerShell — password authentication
.\Connect-WireGuardServer.ps1 -Server SERVER_IP -ProfileName my-wg-vpn
PowerShell — SSH key authentication
.\Connect-WireGuardServer.ps1 -Server SERVER_IP -ProfileName my-wg-vpn -IdentityFile "$HOME\.ssh\id_ed25519"
If PowerShell blocks the script

If the error says the downloaded file is not digitally signed, run this command in the same folder, then retry the setup command.

PowerShell — unblock the downloaded file
Unblock-File -LiteralPath .\Connect-WireGuardServer.ps1, .\ManagementClient.ps1

If the error says running scripts is disabled, run these commands and confirm the prompt, then retry setup. This change lasts only until you close this PowerShell window.

PowerShell — allow scripts for this window only
Set-ExecutionPolicy -Scope Process -ExecutionPolicy RemoteSigned
Unblock-File -LiteralPath .\Connect-WireGuardServer.ps1, .\ManagementClient.ps1

If a policy error still prevents execution, stop and keep the error message for troubleshooting.

4b. Set up the server from a Mac

Open Terminal. Type cd followed by a space, drag the extracted wireguard-guide folder from Finder into Terminal, and press Enter.

Run one of the commands below, including bash at the beginning. Replace SERVER_IP with your VPS address and, if using a key, replace its path. The word my-wg-vpn names this device profile; use a different name, such as macbook, for another Mac.

The profile is saved under your home folder at WireGuard/SERVER_IP/my-wg-vpn.conf. The script prints the full path.

Choose 1 (Set up server), enter the server IP and a profile name, then an SSH key path or press Enter. Enter keeps the suggested profile name. Check the summary and type yes/y to continue; Type no to cancel. After 3 unrecognized answers, the launcher closes. Progress appears during installation. Pressing Enter also continues.

Start with prompts for the server address and profile name
bash ./connect-wireguard-server.sh
macOS Terminal — password authentication
bash ./connect-wireguard-server.sh SERVER_IP my-wg-vpn
macOS Terminal — SSH key authentication
bash ./connect-wireguard-server.sh SERVER_IP my-wg-vpn 22 ~/.ssh/id_ed25519

4c. Set up the server from Ubuntu Desktop

Press Ctrl+Alt+T to open Terminal. Type cd followed by a space, drag the extracted wireguard-guide folder into the terminal and press Enter.

Run one of the commands below, replacing SERVER_IP with your VPS address. The word my-wg-vpn names this device profile. You do not need sudo for this launcher or for SSH login.

The profile is saved under your home folder at WireGuard/SERVER_IP/my-wg-vpn.conf. The script prints the full path.

Choose 1 (Set up server), enter the server IP and a profile name, then an SSH key path or press Enter. Enter keeps the suggested profile name. Check the summary and type yes/y to continue; Type no to cancel. After 3 unrecognized answers, the launcher closes. Progress appears during installation. Pressing Enter also continues.

Start with prompts for the server address and profile name
bash ./connect-wireguard-server.sh
On Ubuntu Desktop — password authentication
bash ./connect-wireguard-server.sh SERVER_IP my-wg-vpn
On Ubuntu Desktop — SSH key authentication
bash ./connect-wireguard-server.sh SERVER_IP my-wg-vpn 22 ~/.ssh/id_ed25519

Before connecting: what happens if the VPN stops working?

Full tunnel routes ordinary internet traffic through the VPN while the profile is active.

A kill switch blocks internet connections outside the VPN. Its behavior depends on the app and settings: an unreachable server, manually disabling the profile and restarting the device can have different effects. This guide creates a full-tunnel profile, but does not configure the same permanent block on connections without a VPN across all devices. Without additional protection, disabling the profile can restore your ordinary internet connection.

Windows: the official WireGuard client automatically enables its kill switch for the profile our script creates. This protection applies while the tunnel is active. Manually deactivating the profile allows ordinary internet access again.

Android: in the phone's system settings, find VPN and the WireGuard settings. Enable Always-on VPN and Block connections without VPN to block connections outside the VPN. Always-on alone is not enough. Names and locations can vary by phone. While blocking is enabled, an unavailable VPN also means no internet access.

Mac and iPhone: On-Demand automatically connects the VPN according to configured rules. Do not treat it as a permanent kill switch.

Ubuntu Desktop: the NetworkManager import described below does not create a separate kill switch. That requires additional firewall rules on your computer.

An unreachable server and a disabled VPN profile are different situations. If the server stops responding while the profile remains active, internet traffic may simply stop; this does not necessarily mean the device switched to a connection outside the VPN.

WireGuard — Windows

Android — VPN

5a. Connect Windows or macOS

Install the official WireGuard application for your operating system. Import the .conf file created by the launcher, approve the operating system's VPN permission and activate the tunnel. The exact import wording can vary between app versions.

The profile sends IPv4 traffic into the tunnel and includes an IPv6 default route so that IPv6 should not bypass this IPv4-only setup. The server does not provide IPv6 internet access. Verify the actual behavior on your device using the checks below.

An imported profile contains a private key. Anyone with a copy can attempt to use that device's VPN identity. Do not paste it into support tickets, upload it to online QR generators or share it between devices.

Official WireGuard downloads

5b. Connect Ubuntu Desktop with NetworkManager

Use NetworkManager to import the profile and manage DNS and routing together. This avoids depending on a particular version of the graphical VPN import dialog. Run the commands below on your desktop, not over SSH on the VPS. Confirm that nmcli is available and NetworkManager is running before importing.

Use a profile named my-wg-vpn.conf so the imported connection is named my-wg-vpn. If that connection name already exists, choose a different device name and adjust the commands. Import only once; for later connections use the up and down commands. Disable automatic connection so this guide does not silently reconnect the VPN every time the desktop starts.

The DNS settings below prefer this connection for all DNS names while it is active. Browsers using their own secure DNS can behave differently. Complete the public-IP, DNS and IPv6 checks in step 7. This NetworkManager route has not yet passed a native Ubuntu Desktop test; the earlier Linux container result does not validate desktop DNS or IPv6 behavior.

Do not also activate the same profile with wg-quick: two managers configuring the same tunnel can create conflicting routes. You can inspect and disconnect the imported connection with nmcli even if the desktop interface presents it differently.

On Ubuntu Desktop — check NetworkManager
nmcli --version
systemctl is-active NetworkManager
On Ubuntu Desktop — import once and configure DNS
sudo nmcli connection import type wireguard file "$HOME/WireGuard/SERVER_IP/my-wg-vpn.conf"
sudo nmcli connection modify my-wg-vpn connection.autoconnect no ipv4.dns-priority -50 ipv4.dns-search "~."
On Ubuntu Desktop — connect
sudo nmcli connection up my-wg-vpn
nmcli connection show --active
On Ubuntu Desktop — disconnect
sudo nmcli connection down my-wg-vpn

6. Connect iPhone or Android with a QR code

Install the official WireGuard app using the App Store or Google Play link below.

On your computer, connect to the VPS again using ssh root@SERVER_IP (or your SSH-key command). Run the command below for your phone. It creates a profile and displays its QR code.

In the WireGuard phone app, choose the option to add a tunnel by scanning a QR code. Scan the code on your computer, name the connection and approve the VPN permission. Then switch the connection on.

Use a separate profile for each phone. Do not share the QR code: it gives access to your VPN. If it appears broken across lines, enlarge the terminal window and display it again.

On the server — create an iPhone profile
python3 /root/internetspeed-wireguard/manage-client.py add iphone
qrencode -t ANSIUTF8 < /etc/wireguard/clients/iphone.conf
On the server — create a separate Android profile
python3 /root/internetspeed-wireguard/manage-client.py add android
qrencode -t ANSIUTF8 < /etc/wireguard/clients/android.conf

WireGuard for iPhone — App Store

WireGuard for Android — Google Play

7. Check that internet traffic uses your VPN

Open our My IP page using the link below before switching on the VPN and note your IP address. Turn on WireGuard, refresh My IP and compare the result with the public IPv4 of your VPS.

If the page loads and shows your VPS address, that browser connection is using the VPN. If the old address remains, use the troubleshooting section below.

This confirms the browser connection, not every application or protection during a VPN interruption. The optional checks below cover DNS and IPv6.

Check your public IP

Optional: check IPv6 and DNS

IPv6: open Test IPv6 before connecting and note whether it reports an IPv6 address. Connect the VPN and run the test again. This IPv4-only setup should have no working IPv6 internet connection. If your usual IPv6 address still appears, IPv6 is bypassing the tunnel. If IPv6 was unavailable before connecting, this test cannot show how the VPN will behave on an IPv6-enabled network.

DNS: with the VPN active, open DNS Leak Test and run its Standard test. This profile uses Cloudflare DNS. If results show your home internet provider, check the device DNS setup. Another provider can also come from the browser Secure DNS setting, so it is a reason to investigate rather than automatic proof of a leak. Neither result alone certifies that every application is protected.

Open Test IPv6

Open DNS Leak Test

8. Troubleshoot a connection that does not work

If My IP still shows your normal address: open WireGuard and check that your imported connection is switched on. Switch it off and on once, then refresh My IP.

If websites stop opening when you turn on the VPN: turn it off and try opening the same page. If the page also fails with the VPN off, first restore your ordinary internet connection. If it works with the VPN off, use the checks below.

If you want to check whether your current Wi-Fi connection is the cause, connect the same computer to your phone hotspot and try the VPN again. On a phone, switch off Wi-Fi and try mobile data. This is a temporary comparison, not a suggestion to change internet providers. Mobile data charges may apply. If the VPN works through the hotspot or mobile data but not through Wi-Fi, the problem is specific to that connection; this alone does not identify the cause.

If setup stopped with an error: keep the last error message. After correcting that problem, rerun the same setup command with the same device name. The script preserves the existing profile.

Check whether the VPN server is running

Connect to the VPS over SSH as in step 2, then run the command below. The expected result is active. If it says inactive or failed, run the restart command and check again. If it still does not say active, keep the error message for troubleshooting.

On the server — check WireGuard
systemctl is-active wg-quick@wg0
On the server — restart WireGuard if it is not active
systemctl restart wg-quick@wg0
systemctl is-active wg-quick@wg0

Restarting briefly disconnects any devices using this VPN.

Check whether your device reaches the server

Turn on the VPN on your device and try opening My IP. On the server, run wg show below. Under the device entry, look for latest handshake. A value such as 10 seconds ago means the device and server recently established an encrypted connection. If that line is missing, a successful connection has not yet been recorded for that device.

If no recent connection appears after you try opening a page, open the profile in WireGuard and check that Endpoint contains your VPS address followed by :51820. Then open the VPS control panel and look for Firewall or Security groups. If firewall rules are attached to this VPS, they need to allow incoming UDP on port 51820. The exact screen depends on your provider. The setup script already configures the firewall inside Ubuntu.

If a recent handshake appears but websites still do not open, record that result and the application error or log. This narrows the problem to investigate; changing advanced network settings at random can make diagnosis harder.

On the server — show VPN connection status
wg show

9. What speed can you expect?

In our Windows test, WireGuard delivered approximately 450–500 Mbps download and 450–500 Mbps upload. Testing followed the same method used for the other VPNs in this project. The test path was: user in San Diego → VPN server in the San Francisco Bay Area → measurement server in Seattle.

The VPN ran on a Vultr Shared CPU (vc2-1c-1gb) VPS: 1 vCPU, 1 GB RAM, and 1 TB of monthly traffic, at $5 per month when provisioned.

In a separate test, a Vultr Shared CPU Intel High Frequency instance (vhf-1c-1gb; 1 vCPU, 1 GB RAM), priced at $6 per month, delivered approximately 550–750 Mbps for both download and upload. Both plans were tested on Windows using the same method and route: San Diego → VPN server in the San Francisco Bay Area → measurement server in Seattle.

Results varied between the Intel High Frequency instances we tested: some consistently delivered speeds near the upper end of the range, while others stayed closer to the lower end. Choosing this plan alone did not guarantee 750 Mbps.

These are the speeds observed with this setup. Your results will depend on your internet connection, server and location.

10. Understand costs, privacy and provider limits

A self-hosted VPN gives you control of the server configuration and one chosen exit location. It also makes you responsible for security updates, account billing, device access and recovery. It does not make your activity anonymous to your hosting provider or remove the need for HTTPS.

Our tested servers cost $5 and $6 per month. Prices, hardware and traffic allowances vary by provider and region. When comparing with a VPN subscription, consider more than the price: one VPS gives you one chosen location, and you maintain the server yourself.

Using the VPN consumes your VPS traffic allowance: browsing, watching videos, downloading and uploading files, and running speed tests all use traffic. Check the remaining allowance in your hosting control panel. Exceeding it may lead to extra charges or restrictions, depending on the plan.

Review the provider's current acceptable-use terms and applicable law before using peer-to-peer software. The protocol and the rights to the content are separate questions. Use content you are entitled to download and share; do not assume every host permits every P2P use.

A data-center IP can encounter CAPTCHAs, service restrictions or streaming blocks. Plain WireGuard does not promise access from every filtered network. One VPS also gives you a single failure point rather than a large provider's pool of locations and replacement servers.

11. Add devices, revoke access and maintain the server

Use a separate profile for each device. To revoke access for a VPN profile, connect to the VPS over SSH and run the removal command below, replacing iphone with the profile name. Then delete any saved copies of its file or QR code. Deleting a profile on the device alone does not revoke access on the server.

Keep Ubuntu security updates current and check whether a reboot is required. Reboot at a convenient time and confirm that the VPN returns. Protect the provider account and SSH access; changing SSH authentication should be a separate step with a tested alternative login.

The removal script below stops this guide's VPN and removes its managed configuration and firewall rules. It leaves SSH access, UFW and installed packages in place. The runtime forwarding setting remains enabled until the operating system's policy is applied at reboot. Removing WireGuard does not cancel your VPS bill; delete the instance through your provider when you no longer need it, after preserving anything required.

On the server — revoke the iPhone profile
python3 /root/internetspeed-wireguard/manage-client.py remove iphone
On the server — inspect available updates and reboot requirement
apt update
apt list --upgradable
test ! -f /var/run/reboot-required || cat /var/run/reboot-required

These commands list available updates and check whether a reboot is required; they do not install updates. Configure security updates and broader VPS protection separately from VPN installation.

On the server — remove this VPN configuration (disconnects all clients)
bash /root/internetspeed-wireguard/remove-server.sh --confirm