Deploy WireGuard VPN Server on Debian 12

Post Reply
User avatar
Admin
Site Admin
Posts: 17
Joined: Sun May 10, 2026 10:15 pm

Deploy WireGuard VPN Server on Debian 12

Post by Admin »

Steps

Setup Server

Install WireGuard

Code: Select all

sudo apt update
sudo apt-get install wireguard -y
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:

Code: Select all

wg genkey | tee privatekey | wg pubkey > publickey
This will result in there being two files locally called privatekey
and 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}.conf
The interface does not need to be called

Code: Select all

wg0
, but whatever you call it, the file
must be at that path and have the same name with the

Code: Select all

.conf
extension.

Now 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}
... or you can use the following BASH script to fill in the variables and have it create the file for you:

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}.conf
Enable Packet Forwarding

Finally, 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_forward
Then we also need to enable it in the sysctl kernel configuration file:

Code: 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 -p
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:

Code: Select all

sudo apt update
sudo apt-get install wireguard -y
Create a public/private key-pair as you did before on your client computer:

Code: Select all

wg genkey | tee privatekey | wg pubkey > publickey
Configure Tunnel Interface

Now create a wireguard configuration file by running:

Code: Select all

touch /etc/wireguard/wg0.conf
The file doesn't have to be called

Code: Select all

wg0.conf
and can be labelled anything with the

Code: Select all

.conf
extension. However, it does need to be in the

Code: Select all

/etc/wireguard
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:

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=30
... or run the following BASH script with setting the variables at the top:

Code: 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}.conf
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:

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}.conf
... or you can do it manually, with the following template:

Code: Select all

[Peer]
PublicKey = ${CLIENT_PUBLIC_KEY}
AllowedIPs = ${CLIENT_TUNNEL_IP}
Alternative Method

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}
However, that relies on having set

Code: Select all

SaveConfig
to

Code: Select all

true
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

Code: Select all

SaveConfig
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:

Code: Select all

WIREGUARD_INTERFACE_NAME="wg0"
sudo wg-quick up $WIREGUARD_INTERFACE_NAME
Using Filepath Instead

If you don't like sticking the configuration files in the

Code: Select all

/etc/wireguard
folder, and placed them somewhere
else, 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_FILEPATH
Disconnect

To disconnect, you an then run the down command like so:

Code: Select all

WIREGUARD_INTERFACE_NAME="wg0"
sudo wg-quick down $WIREGUARD_INTERFACE_NAME
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:

Code: Select all

sudo wg show
Auto Connect On Boot

If 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-reload
Then you can start it immediately with:

Code: Select all

WG_INTERFACE="wg0"
sudo systemctl start wg-quick@${WG_INTERFACE}
Post Reply