Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add headless support #120

Open
wants to merge 12 commits into
base: master
Choose a base branch
from
61 changes: 61 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,67 @@ It will install WireGuard (kernel module and tools) on the server, configure it,

Run the script again to add or remove clients!

## Headless install

It's also possible to run the script headless, e.g. without waiting for user input, in an automated manner.

Example usage:

```bash
AUTO_INSTALL=y ./wireguard-install.sh

# or

export AUTO_INSTALL=y
./wireguard-install.sh
```

A default set of variables will then be set, by passing the need for user input.

If you want to customise your installation, you can export them or specify them on the same line, as shown above.

- `APPROVE_INSTALL=y`
- `APPROVE_IP=y`
- `APPROVE_NIC=y`
- `SERVER_WG_NIC=wg0`
- `SERVER_WG_IPV4=10.66.66.1`
- `SERVER_WG_IPV6=fd42:42:42::1`
- `SERVER_PORT=51820`
- `CLIENT_DNS_1=176.103.130.130`
- `CLIENT_DNS_2=176.103.130.131`
- `CLIENT_NAME=client`
- `CLIENT_DOT=2`

If the server is behind NAT, you can specify its endpoint with the `SERVER_PUB_IP` variable. If the endpoint is the public IP address which it is behind, you can use `SERVER_PUB_IP=$(curl https://ifconfig.co)` (the script will default to this). The endpoint can be an IP or a domain.

Other variables can be set depending on your choice (`SERVER_NIC`). You can search for them in the `installQuestions()` function of the script.

## Headless User Addition

It's also possible to automate the addition of a new user. Here, the key is to provide the (string) value of the `MENU_OPTION` variable along with the remaining mandatory variables before invoking the script.

The following Bash script adds a new user `foo` to an existing WireGuard configuration. The wireguard-install script will automatically assign a free IP to the client. You can assign a specific one by setting its Host ID to the variable `CLIENT_DOT`.

```bash
#!/bin/bash
export MENU_OPTION="1"
export CLIENT_NAME="foo"
./wireguard-install.sh
```

## Headless User Revokation

It's also possible to automate the revokation of an existing user. Here, the key is to provide the (string) value of the `MENU_OPTION` variable along with the remaining mandatory variables before invoking the script.

The following Bash script revokes an user `foo` from an existing WireGuard configuration

```bash
#!/bin/bash
export MENU_OPTION="2"
export CLIENT_NAME="foo"
./wireguard-install.sh
```

## Providers

I recommend these cheap cloud providers for your VPN server:
Expand Down
95 changes: 64 additions & 31 deletions wireguard-install.sh
Original file line number Diff line number Diff line change
Expand Up @@ -67,16 +67,24 @@ function installQuestions() {
echo ""

# Detect public IPv4 or IPv6 address and pre-fill for the user
SERVER_PUB_IP=$(ip -4 addr | sed -ne 's|^.* inet \([^/]*\)/.* scope global.*$|\1|p' | head -1)
SERVER_PUB_IP=${SERVER_PUB_IP:-$(ip -4 addr | sed -ne 's|^.* inet \([^/]*\)/.* scope global.*$|\1|p' | head -1)}
if [[ -z ${SERVER_PUB_IP} ]]; then
# Detect public IPv6 address
SERVER_PUB_IP=$(ip -6 addr | sed -ne 's|^.* inet6 \([^/]*\)/.* scope global.*$|\1|p' | head -1)
fi
read -rp "IPv4 or IPv6 public address: " -e -i "${SERVER_PUB_IP}" SERVER_PUB_IP

APPROVE_IP=${APPROVE_IP:-n}
if [[ ${APPROVE_IP} =~ n ]]; then
read -rp "IPv4 or IPv6 public address: " -e -i "${SERVER_PUB_IP}" SERVER_PUB_IP
fi

# Detect public interface and pre-fill for the user
SERVER_NIC="$(ip -4 route ls | grep default | grep -Po '(?<=dev )(\S+)' | head -1)"
until [[ ${SERVER_PUB_NIC} =~ ^[a-zA-Z0-9_]+$ ]]; do
SERVER_NIC=${SERVER_NIC:-$(ip -4 route ls | grep default | grep -Po '(?<=dev )(\S+)' | head -1)}
if [[ -z $SERVER_NIC ]]; then
SERVER_NIC=$(ip -6 route show default | sed -ne 's/^default .* dev \([^ ]*\) .*$/\1/p')
fi
APPROVE_NIC=${APPROVE_NIC:-n}
until [[ ${SERVER_PUB_NIC} =~ ^[a-zA-Z0-9_]+$ || ${APPROVE_NIC} =~ n ]]; do
read -rp "Public interface: " -e -i "${SERVER_NIC}" SERVER_PUB_NIC
done

Expand Down Expand Up @@ -112,12 +120,33 @@ function installQuestions() {
echo ""
echo "Okay, that was all I needed. We are ready to setup your WireGuard server now."
echo "You will be able to generate a client at the end of the installation."
read -n1 -r -p "Press any key to continue..."
APPROVE_INSTALL=${APPROVE_INSTALL:-n}
if [[ $APPROVE_INSTALL =~ n ]]; then
read -n1 -r -p "Press any key to continue..."
fi
}

function installWireGuard() {
# Run setup questions first
installQuestions
if [[ ${AUTO_INSTALL} == "y" ]]; then
# Set default choices so that no questions will be asked.
APPROVE_INSTALL=${APPROVE_INSTALL:-y}
APPROVE_IP=${APPROVE_IP:-y}
APPROVE_NIC=${APPROVE_NIC:-y}
SERVER_WG_NIC=${SERVER_WG_NIC:-wg0}
SERVER_WG_IPV4=${SERVER_WG_IPV4:-10.66.66.1}
SERVER_WG_IPV6=${SERVER_WG_IPV6:-fd42:42:42::1}
SERVER_PORT=${SERVER_PORT:-$(shuf -i49152-65535 -n1)}
CLIENT_DNS_1=${CLIENT_DNS_1:-176.103.130.130}
CLIENT_DNS_2=${CLIENT_DNS_2:-176.103.130.131}
CLIENT_NAME=${CLIENT_NAME:-client}
CLIENT_DOT=${CLIENT_DOT:-2}

# Behind NAT, we'll default to the publicly reachable IPv4.
SERVER_PUB_IP=${SERVER_PUB_IP:-$(curl https://ifconfig.co)}
else
# Run setup questions first
installQuestions
fi

# Install WireGuard tools and module
if [[ ${OS} == 'ubuntu' ]]; then
Expand Down Expand Up @@ -222,6 +251,7 @@ function newClient() {
echo ""
echo "A client with the specified name was already created, please choose another name."
echo ""
exit 1
fi
done

Expand All @@ -239,28 +269,20 @@ function newClient() {
fi

until [[ ${IPV4_EXISTS} == '0' ]]; do
read -rp "Client's WireGuard IPv4: ${SERVER_WG_IPV4::-1}" -e -i "${DOT_IP}" DOT_IP
CLIENT_WG_IPV4="${SERVER_WG_IPV4::-1}${DOT_IP}"
until [[ ${CLIENT_DOT} =~ ^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$ ]]; do
read -rp "Client's WireGuard Host ID (valid for both IPv4 and IPv6): ${SERVER_WG_IPV4%.*}." -e -i "${DOT_IP}" CLIENT_DOT
done
CLIENT_WG_IPV4="${SERVER_WG_IPV4%.*}.${CLIENT_DOT}"
IPV4_EXISTS=$(grep -c "$CLIENT_WG_IPV4" "/etc/wireguard/${SERVER_WG_NIC}.conf")

if [[ ${IPV4_EXISTS} == '1' ]]; then
echo ""
echo "A client with the specified IPv4 was already created, please choose another IPv4."
echo ""
exit 1
fi
done

until [[ ${IPV6_EXISTS} == '0' ]]; do
read -rp "Client's WireGuard IPv6: ${SERVER_WG_IPV6::-1}" -e -i "${DOT_IP}" DOT_IP
CLIENT_WG_IPV6="${SERVER_WG_IPV6::-1}${DOT_IP}"
IPV6_EXISTS=$(grep -c "${CLIENT_WG_IPV6}" "/etc/wireguard/${SERVER_WG_NIC}.conf")

if [[ ${IPV6_EXISTS} == '1' ]]; then
echo ""
echo "A client with the specified IPv6 was already created, please choose another IPv6."
echo ""
fi
done
CLIENT_WG_IPV6="${SERVER_WG_IPV6%:*}:${CLIENT_DOT}"

# Generate key pair for the client
CLIENT_PRIV_KEY=$(wg genkey)
Expand Down Expand Up @@ -314,18 +336,29 @@ function revokeClient() {

echo ""
echo "Select the existing client you want to revoke"
grep -E "^### Client" "/etc/wireguard/${SERVER_WG_NIC}.conf" | cut -d ' ' -f 3 | nl -s ') '
until [[ ${CLIENT_NUMBER} -ge 1 && ${CLIENT_NUMBER} -le ${NUMBER_OF_CLIENTS} ]]; do
if [[ ${CLIENT_NUMBER} == '1' ]]; then
read -rp "Select one client [1]: " CLIENT_NUMBER
else
read -rp "Select one client [1-${NUMBER_OF_CLIENTS}]: " CLIENT_NUMBER
fi
done

# match the selected number to a client name
CLIENT_NAME=$(grep -E "^### Client" "/etc/wireguard/${SERVER_WG_NIC}.conf" | cut -d ' ' -f 3 | sed -n "${CLIENT_NUMBER}"p)
if [[ -z ${CLIENT_NAME} ]]; then
grep -E "^### Client" "/etc/wireguard/${SERVER_WG_NIC}.conf" | cut -d ' ' -f 3 | nl -s ') '
until [[ ${CLIENT_NUMBER} -ge 1 && ${CLIENT_NUMBER} -le ${NUMBER_OF_CLIENTS} ]] || [[ -n ${CLIENT_NAME} ]]; do
if [[ ${CLIENT_NUMBER} == '1' ]]; then
read -rp "Select one client [1]: " CLIENT_NUMBER
else
read -rp "Select one client [1-${NUMBER_OF_CLIENTS}]: " CLIENT_NUMBER
fi
done

# match the selected number to a client name
CLIENT_NAME=$(grep -E "^### Client" "/etc/wireguard/${SERVER_WG_NIC}.conf" | cut -d ' ' -f 3 | sed -n "${CLIENT_NUMBER}"p)
else
CLIENT_EXISTS=$(grep -c -E "^### Client ${CLIENT_NAME}\$" "/etc/wireguard/${SERVER_WG_NIC}.conf")

if [[ ${CLIENT_EXISTS} == '1' ]]; then
echo ""
echo "The client with the specified name doesn't exists."
echo ""
exit 1
fi
fi
# remove [Peer] block matching $CLIENT_NAME
sed -i "/^### Client ${CLIENT_NAME}\$/,/^$/d" "/etc/wireguard/${SERVER_WG_NIC}.conf"

Expand Down