Regarding Privacy and Anonymity #
A self-hosted VPN is secure against local network threats, like the classic public wifi in a coffee shop scenario, or ISP snooping, but it does not mean it makes you anonymous. Also it does not mean it is entirely private. Your server hosting provider, e.g. AWS, Hetzner, DigitalOcean, etc. has the same level of visibility into your traffic as an ISP would once it leaves the tunnel (dest IPs, hostnames, packet timing, sizes), but not page contents (Assuming HTTPS traffic). If your goal is privacy from your ISP and public wifi, it’s solid. If your goal is hiding activity from political entities, or intelligence agencies, it’s not entirely what you need.
A self-hosted VPN shifts trust: from your ISP to your server provider. Your cloud host controls the physical machine and hypervisor. The provider can still:
-Capture packets on the host/virtual switch
-Snapshot RAM/disk to obtain keys
-Comply with lawful orders to monitor your traffic
Why not just use a commercial VPN #
One difference is that with a commercial VPN, you shift trust to the vendor. With your own VPN, you shift trust to the infrastructure provider. 4
With self-hosting, you can configure minimal logging. With commercial services, you rely on their policies (claims of “no logs” are unverifiable).
Commercial providers can be sometimes widely blocked (streaming, firewalls, censorship). However, a self-hosted VPN on a simple VPS looks like any usual personal server and can bypass those blocks with more success.
Setting up #
In the past I used to use OpenVPN but now I will host a wireguard server (on debian).
apt update
apt install wireguard
wireguard
provides kernel module + wg
tools.
Key generation #
For a basic start: https://www.wireguard.com/quickstart/
Their guide suggests using umask
command. It is used to restrict file permissions for anything you create after executing it in this case, the WireGuard keys, though a manual chmod 600
would work the same too:
umask 077
Then create the key pair (will be created with permissions 600 rw-------
):
wg genkey | tee wg_private_key | wg pubkey > wg_public_key
The clients should create their own private and public keys.
Config #
You generally need sudo
to access /etc/wireguard
and manage WireGuard.
WireGuard config files live in /etc/wireguard/
(for example, wg0.conf
).
sudo nano /etc/wireguard/wg0.conf
More info about wg config file: https://wiresock.net/documentation/wireguard/config.html
[Interface]
# VPN subnet for clients
# Example, this value: 10.10.10.1/24, defines a
# subnet of 10.10.10.0 - 10.10.10.255 (256 total addresses), with
# 10.10.10.1 as the server’s VPN IP
Address = 10.10.10.1/24
# Default is 51820, any port should work fine
# Your choice of port depends on what your local network or firewall allows
# You should choose a port that is unlikely to be blocked
# by your network or firewall, with common alternatives including
# UDP:443 or UDP:80,
ListenPort = 51234
# This should be the key itself, not the file path
PrivateKey = <server_private_key>
# Optional
# SaveConfig = true
#======Client 1==========
[Peer]
# This should contain the key itself, not the file path
PublicKey = <client_public_key>
# Which IPs are allowed for this client, must be in server IP addr range
# /32 means one single ip is available: 10.10.10.2
AllowedIPs = 10.10.10.2/32 #, ipv6 addr optional
# Keepalive to traverse NAT/firewalls
PersistentKeepalive = 25
# Optional (if client has fixed IP)
#Endpoint = 203.0.113.10:51820
Forwarding #
net.ipv4.ip_forward=1
enables the Linux kernel to forward IPv4 packets between interfaces. Without this, the server can’t route traffic from the VPN interface (wg0
) to the public network (eth0
for example).
echo "net.ipv4.ip_forward=1" | sudo tee -a /etc/sysctl.conf
Similarly, for IPv6 if used:
echo "net.ipv6.conf.all.forwarding=1" | sudo tee -a /etc/sysctl.conf
Apply changes (raeds /etc/sysctl.conf
and applies the settings to the running kernel):
sudo sysctl -p
NAT #
Replace eth0 with your server interface (use ifconfig to find out):
sudo iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
sudo sh -c "iptables-save > /etc/iptables.rules"
Without NAT, only traffic to the VPN subnet itself can reach the server or other VPN clients. Internet traffic from clients will fail because private VPN IPs (like, for instance, class A private IPs 10.0.0.0
to 10.255.255.255
) are not routable on the public internet.
sudo apt install iptables-persistent -y
https://upcloud.com/resources/tutorials/configure-iptables-debian/
Start the service #
$ sudo systemctl enable wg-quick@wg0
$ sudo systemctl start wg-quick@wg0
$ sudo wg
interface: wg0
public key: <PUBLIC_KEY_SNIP>
private key: (hidden)
listening port: 51234
peer: <PUBLIC_KEY_SNIP>
allowed ips: 10.10.10.2/32
persistent keepalive: every 25 seconds
Client Side #
From the client side, setting up WireGuard is simpler because you don’t touch NAT or forwarding. https://www.wireguard.com/install/ for your platform.
On the client side with wg installed:
wg genkey | tee client_private_key | wg pubkey > client_public_key
For personal VPN, generating the client keys on the server side should usually be acceptable because you trust yourself as the server operator.
Config #
First of all add a new entry in the server config in the [Peer] section, use the template from before and modify the client settings. ( For more clients, you can add another client by creating a new [Peer]
block in your server config.)
Then, on the client machine, create /etc/wireguard/client.conf
[Interface]
PrivateKey = <client_private_key>
Address = 10.10.10.2/32
DNS = 1.1.1.1
[Peer]
PublicKey = <server_public_key>
Endpoint = <server_public_ip>:51234
AllowedIPs = 0.0.0.0/0, ::/0 # full tunnel
PersistentKeepalive = 25
$ sudo wg-quick up client
[#] ip link add client type wireguard
[#] wg setconf client /dev/fd/63
[#] ip -4 address add 10.10.10.2/32 dev client
[#] ip link set mtu 1420 up dev client
[#] resolvconf -a client -m 0 -x
[#] wg set client fwmark 51820
[#] ip -6 rule add not fwmark 51820 table 51820
[#] ip -6 rule add table main suppress_prefixlength 0
[#] ip -6 route add ::/0 dev client table 51820
[#] nft -f /dev/fd/63
[#] ip -4 rule add not fwmark 51820 table 51820
[#] ip -4 rule add table main suppress_prefixlength 0
[#] ip -4 route add 0.0.0.0/0 dev client table 51820
[#] sysctl -q net.ipv4.conf.all.src_valid_mark=1
[#] nft -f /dev/fd/63
$ sudo wg
interface: client
public key: <PUB_KEY_SNIP>
private key: (hidden)
listening port: 39168
fwmark: 0xca6c
peer: <PUB_KEY_SNIP>
endpoint: <IP_ADDR_SNIP>:51234
allowed ips: 0.0.0.0/0, ::/0
latest handshake: 2 seconds ago
transfer: 2.95 KiB received, 7.21 KiB sent
persistent keepalive: every 25 seconds
Check your ip:
cation@local:~/wg$ curl 2ip.me
ip : <IP_ADDR_SNIP>
hostname : rlcthd.com
provider ...
And ifconfig to confirm your private ip:
client: flags=209<UP,POINTOPOINT,RUNNING,NOARP> mtu 1420
inet 10.10.10.2 netmask 255.255.255.255 destination 10.10.10.2
unspec 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00 txqueuelen 1000 (UNSPEC)
RX packets 762 bytes 318900 (318.9 KB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 924 bytes 256648 (256.6 KB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
End note #
WireGuard is encrypted by default. You don’t have to enable anything extra for encryption.
HTTPS or other end-to-end encryption is still recommended for content security on the Internet.
And after using your own VPN anyone sniffing your connection (ISP, public wifi) will only see fully encrypted packets.
WireGuard’s default logging is minimal and built into the kernel module. There’s no separate log file unless you explicitly use systemd or dmesg.
Get Involved #
I think knowledge should be shared and discussions encouraged. So, don’t hesitate to ask questions, or suggest topics you’d like
me to cover in future posts.
Stay Connected #
You can contact me at ion.miron@tutanota.com