Deploy WireGuard VPN Server on Debian 12
Posted: Wed May 13, 2026 7:58 pm
Steps
Setup Server
Install WireGuard
Create Server Keys
Now we need to create the public and private key-pairs used for establishing a secure connection.
We can do this by running the following command:
This will result in there being two files locally called privatekey
and publickey which contain the private and public keys accordingly.
Configure Tunnel Interface
The interface does not need to be called
, but whatever you call it, the file
must be at that path and have the same name with the
extension.
Now either fill it in manually by substituting the variables in the content below:
... or you can use the following BASH script to fill in the variables and have it create the file for you:
Enable Packet Forwarding
Finally, we need to ensure that the server will allow packet forwarding. This can be enabled by running:
Then we also need to enable it in the sysctl kernel configuration file:
Setup Client
Now we need to setup and configure wireguard on the client, for it to connect to the server.
Install Wireguard
Install wireguard as you did before:
Create a public/private key-pair as you did before on your client computer:
Configure Tunnel Interface
Now create a wireguard configuration file by running:
The file doesn't have to be called
and can be labelled anything with the
extension. However, it does need to be in the
folder and the name of the
file will reflect the name of the interface. The name of the interface doesn't need to match
the name of the interface on the server either.
Now either fill it with the following, taking care to manually swap out the values as appropriate
to your setup:
... or run the following BASH script with setting the variables at the top:
Add Client To Server
We now need to tell the server to allow the client to be able to connect. This is similar to how we
add a public SSH key to the $HOME/.ssh/authorized_keys file to tell the server we allow a
client to connect with their SSH Key.
Run the following BASH script to append the peer connection details to your WireGuard interface's configuration file:
... or you can do it manually, with the following template:
Alternative Method
The alternative would be to just run the following command to add the client to wireguard interface:
However, that relies on having set
to
for it to be remembered, and relies on Wireguard overwriting your
config file for
the client to be kept, and you not having to keep entering the line. The
downside to this is that it will also write in the endpoint for
the client, which is not ideal in which your client's may likely change
IP such as a laptop you travel with. Thus I go with just adding
the peers manually to the config file, and having
set to false.
Using The Wireguard Tunnel
Now in order to get the tunnel running and make use of it, you first need to run the connect/up command
shown below on the server first, before then running it on the client.
Connect
Finally, after all of that configuration, you should be able to use the following command on your client
in order to create the WireGuard tunnel connection to the server and start making use of it:
Using Filepath Instead
If you don't like sticking the configuration files in the
folder, and placed them somewhere
else, then you can just specify the full path to the configuration file instead:
Disconnect
To disconnect, you an then run the down command like so:
Show WireGuard Status
If you wish to see your current wireguard connections and how much
traffic is being sent over them, you can run the following command:
Auto Connect On Boot
If you wish for the wireguard connection to automatically start on boot, you cn enable this through
systemd like so:
Then you can start it immediately with:
Setup Server
Install WireGuard
Code: Select all
sudo apt update
sudo apt-get install wireguard -yNow we need to create the public and private key-pairs used for establishing a secure connection.
We can do this by running the following command:
Code: Select all
wg genkey | tee privatekey | wg pubkey > publickeyand publickey which contain the private and public keys accordingly.
Configure Tunnel Interface
Code: Select all
WIREGUARD_INTERFACE_NAME="wg0"
sudo touch /etc/wireguard/${WIREGUARD_INTERFACE_NAME}.confCode: Select all
wg0must be at that path and have the same name with the
Code: Select all
.confNow either fill it in manually by substituting the variables in the content below:
Code: Select all
[Interface]
PrivateKey=${PRIVATE_KEY}
# Specify the subnet that should be used for assigning IP addresses to the clients on this
# tunnel interface. This needs to not overlap with your server's private IP subnet!
Address=${WIREGUARD_SUBNET}
SaveConfig=false
# Add rules to iptables networking when the interface come up in order to have the server do the
# following:
# 1. Accept every forwarding packet on the tunnel interface (wg0)
# 2. have packets that we forward out on the eth0 interface be manipulated to look like they came
# from this server instead of having their original source IP.
PostUp=iptables -A FORWARD -i ${WIREGUARD_INTERFACE_NAME} -j ACCEPT; iptables -t nat -A POSTROUTING -o ${NORMAL_INTERFACE_NAME} -j MASQUERADE;
# Remove the rules we added, when the wireguard tunnel interface comes down
PostDown=iptables -D FORWARD -i ${WIREGUARD_INTERFACE_NAME} -j ACCEPT; iptables -t nat -D POSTROUTING -o ${NORMAL_INTERFACE_NAME} -j MASQUERADE;
# Specify which port you wish for the wireguard to listen on for this interface. This can be anything
# you want, but 51820 is the default for wireguard.
ListenPort=${PORT}Code: Select all
# Settings - fill these in as appropriate to you.
PRIVATE_KEY=""
WIREGUARD_INTERFACE_NAME="wg0"
WIREGUARD_SUBNET="10.172.0.1/24"
NORMAL_INTERFACE_NAME="eth0"
PORT=51820
sudo echo "
[Interface]
PrivateKey=${PRIVATE_KEY}
# Specify the subnet that should be used for assigning IP addresses to the clients on this
# tunnel interface. This needs to not overlap with your server's private IP subnet!
Address=${WIREGUARD_SUBNET}
# Specify if you want wireguard to overwrite the config on shutdown.
SaveConfig=false
# Add rules to iptables networking when the interface come up in order to have the server do the
# following:
# 1. Accept every forwarding packet on the tunnel interface (wg0)
# 2. have packets that we forward out on the eth0 interface be manipulated to look like they came from this
# server instead of having their original source IP.
PostUp=iptables -A FORWARD -i ${WIREGUARD_INTERFACE_NAME} -j ACCEPT; iptables -t nat -A POSTROUTING -o ${NORMAL_INTERFACE_NAME} -j MASQUERADE;
# Remove the rules we added, when the wireguard tunnel interface comes down
PostDown=iptables -D FORWARD -i ${WIREGUARD_INTERFACE_NAME} -j ACCEPT; iptables -t nat -D POSTROUTING -o ${NORMAL_INTERFACE_NAME} -j MASQUERADE;
# Specify which port you wish for the wireguard to listen on for this interface. This can be anything
# you want, but 51820 is the default for wireguard.
ListenPort=${PORT}
" | sudo tee /etc/wireguard/${WIREGUARD_INTERFACE_NAME}.confFinally, we need to ensure that the server will allow packet forwarding. This can be enabled by running:
Code: Select all
sudo echo 1 | sudo tee /proc/sys/net/ipv4/ip_forwardCode: Select all
SEARCH="#net.ipv4.ip_forward.*"
REPLACE="net.ipv4.ip_forward=1"
FILEPATH="/etc/sysctl.conf"
sudo sed -i "s;$SEARCH;$REPLACE;" $FILEPATH
# Have the change take immediate effect
sudo sysctl -pNow we need to setup and configure wireguard on the client, for it to connect to the server.
Install Wireguard
Install wireguard as you did before:
Code: Select all
sudo apt update
sudo apt-get install wireguard -yCode: Select all
wg genkey | tee privatekey | wg pubkey > publickeyNow create a wireguard configuration file by running:
Code: Select all
touch /etc/wireguard/wg0.confCode: Select all
wg0.confCode: Select all
.confCode: Select all
/etc/wireguardfile will reflect the name of the interface. The name of the interface doesn't need to match
the name of the interface on the server either.
Now either fill it with the following, taking care to manually swap out the values as appropriate
to your setup:
Code: Select all
[Interface]
PrivateKey=${PRIVATE_KEY}
# Specify the subnet that should be used for assigning IP addresses to the clients on this
# tunnel interface. This needs to not overlap with your private IP subnet, and needs to be
# unique on the subnet you created. E.g. we used 10.172.0.1 for the server, so we
# are using 10.172.0.2 here. If you were to create another client it would need to be
# 10.172.0.3 etc.
Address=10.172.0.2/24
# Specify if you wish for WireGuard to overwrite the config on shutdown.
SaveConfig=false
[Peer]
# Specify the public key of the server you wish to connect to.
PublicKey=${SERVER_PUBLIC_KEY}
# Specify the IP address of the server to connect to. If you are using something like DigitalOcean,
# then this would be that instance's public/internet IP address. If you are using a computer on
# your private network, then you could specify its private IP address.
Endpoint=${SERVER_PUBLIC_IP_ADDRESS}
# Specify which subnets that wireguard should send through the tunnel. We wish to send all traffic
# through the server, so we will use 0.0.0.0/0, but if you only wanted to forward traffic for
# another private subnet that your server is on, you could specify it's subnet instead.
AllowedIPs=0.0.0.0/0
# Optionally have the following to have wireguard send a keepalive packet every x seconds so
# that the connection remains open, otherwise routers/gateways between the server and the client
# may close the connection because wireguard uses UDP and is stateless.
PersistentKeepalive=30Code: Select all
CLIENT_PRIVATE_KEY=""
SERVER_PUBLIC_KEY=""
WIREGUARD_INTERFACE_NAME="wg0"
WIREGUARD_SUBNET_CLIENT_IP="10.172.0.2/24"
SERVER_PUBLIC_IP_ADDRESS=""
AllowedIPs="0.0.0.0/0"
PORT=51820
sudo echo "
[Interface]
PrivateKey=${CLIENT_PRIVATE_KEY}
# Specify the subnet that should be used for assigning IP addresses to the clients on this
# tunnel interface. This needs to not overlap with your private IP subnet, and needs to be
# unique on the subnet you created. E.g. we used 10.172.0.1 for the server, so we
# are using 10.172.0.2 here. If you were to create another client it would need to be
# 10.172.0.3 etc.
Address=${WIREGUARD_SUBNET_CLIENT_IP}
# Specify if you wish for WireGuard to overwrite the config on shutdown.
SaveConfig=false
[Peer]
# Specify the public key of the server you wish to connect to.
PublicKey=${SERVER_PUBLIC_KEY}
# Specify the IP address of the server to connect to. If you are using something like DigitalOcean,
# then this would be that instance's public/internet IP address. If you are using a computer on
# your private network, then you could specify its private IP address.
Endpoint=${SERVER_PUBLIC_IP_ADDRESS}:${PORT}
# Specify which subnets that wireguard should send through the tunnel. We wish to send all traffic
# through the server, so we will use 0.0.0.0/0, but if you only wanted to forward traffic for
# another private subnet that your server is on, you could specify it's subnet instead.
AllowedIPs=${AllowedIPs}
# Optionally have the following to have wireguard send a keepalive packet every x seconds so that
# the connection remains open, otherwise routers/gateways between the server and the client may
# close the connection because wireguard uses UDP and is stateless.
PersistentKeepalive=30" | sudo tee /etc/wireguard/${WIREGUARD_INTERFACE_NAME}.confWe now need to tell the server to allow the client to be able to connect. This is similar to how we
add a public SSH key to the $HOME/.ssh/authorized_keys file to tell the server we allow a
client to connect with their SSH Key.
Run the following BASH script to append the peer connection details to your WireGuard interface's configuration file:
Code: Select all
WIREGUARD_INTERFACE_NAME="wg0"
# Specify the *public* key of the client
CLIENT_PUBLIC_KEY="xxxxxxxxxxxxxxxxxxxx"
# Specify the IP address you gave the client in their `Address` setting but use /32 for the CIDR
# so that the client can only use that single IP.
CLIENT_TUNNEL_IP="10.172.0.2/32"
echo "
[Peer]
PublicKey = ${CLIENT_PUBLIC_KEY}
AllowedIPs = ${CLIENT_TUNNEL_IP}
" >> /etc/wireguard/${WIREGUARD_INTERFACE_NAME}.confCode: Select all
[Peer]
PublicKey = ${CLIENT_PUBLIC_KEY}
AllowedIPs = ${CLIENT_TUNNEL_IP}The alternative would be to just run the following command to add the client to wireguard interface:
Code: Select all
WIREGUARD_INTERFACE="wg0"
CLIENT_PUBLIC_KEY="xxxxxxxxxxxxxxxxxxxx"
# Specify the IP address you gave the client in their `Address` setting but use /32 for the CIDR
# so that the client can only use that single IP.
CLIENT_TUNNEL_IP="10.172.0.2/32"
sudo wg set $WIREGUARD_INTERFACE peer ${CLIENT_PUBLIC_KEY} allowed-ips ${CLIENT_TUNNEL_IP}Code: Select all
SaveConfigCode: Select all
trueconfig file for
the client to be kept, and you not having to keep entering the line. The
downside to this is that it will also write in the endpoint for
the client, which is not ideal in which your client's may likely change
IP such as a laptop you travel with. Thus I go with just adding
the peers manually to the config file, and having
Code: Select all
SaveConfigUsing The Wireguard Tunnel
Now in order to get the tunnel running and make use of it, you first need to run the connect/up command
shown below on the server first, before then running it on the client.
Connect
Finally, after all of that configuration, you should be able to use the following command on your client
in order to create the WireGuard tunnel connection to the server and start making use of it:
Code: Select all
WIREGUARD_INTERFACE_NAME="wg0"
sudo wg-quick up $WIREGUARD_INTERFACE_NAMEIf you don't like sticking the configuration files in the
Code: Select all
/etc/wireguardelse, then you can just specify the full path to the configuration file instead:
Code: Select all
CONFIG_FILEPATH="/path/to/my/wireguard/config.conf"
sudo wg-quick up $CONFIG_FILEPATHTo disconnect, you an then run the down command like so:
Code: Select all
WIREGUARD_INTERFACE_NAME="wg0"
sudo wg-quick down $WIREGUARD_INTERFACE_NAMEIf you wish to see your current wireguard connections and how much
traffic is being sent over them, you can run the following command:
Code: Select all
sudo wg showIf you wish for the wireguard connection to automatically start on boot, you cn enable this through
systemd like so:
Code: Select all
WG_INTERFACE="wg0"
sudo systemctl enable wg-quick@${WG_INTERFACE}.service
sudo systemctl daemon-reloadCode: Select all
WG_INTERFACE="wg0"
sudo systemctl start wg-quick@${WG_INTERFACE}