feat: Enable headless installation without interaction

This commit is contained in:
Goetz Epperlein 2024-03-16 16:37:20 +01:00
parent 39caf2fcf6
commit 364c93b9fe
2 changed files with 93 additions and 15 deletions

View File

@ -39,6 +39,39 @@ It will install WireGuard (kernel module and tools) on the server, configure it,
Run the script again to add or remove clients! Run the script again to add or remove clients!
## Headless installation
It's also possible to run the script headless, e.g. without waiting for user input, in an automated way.
Example usage:
```bash
APPROVE_INSTALL=y ./wireguard-install.sh
# or
export APPROVE_INSTALL=y
./wireguard-install.sh
```
This will set a default set of variables, bypassing any user input.
If you want to customise your installation, you can use variables, as shown below:
```
export APPROVE_INSTALL=y
export SERVER_PUB_IP="54.14.1.48"
export SERVER_PORT=64567
export CLIENT_NAME=client
```
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 -s https://api.ipify.org)` (the script defaults to this). The endpoint can be an IP or a domain.
The headless installation involves adding a new user. Adding `CLIENT_NAME=foo` will change the name of the new user to `foo` instead of the default.
Other variables can be set as required on your choice (`SERVER_NIC`). You can find them in the `installQuestions()` function of the script.
## Providers ## Providers
I recommend these cheap cloud providers for your VPN server: I recommend these cheap cloud providers for your VPN server:

View File

@ -110,29 +110,38 @@ function installQuestions() {
echo "" echo ""
# Detect public IPv4 or IPv6 address and pre-fill for the user # 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' | awk '{print $1}' | head -1) SERVER_PUB_IP=${SERVER_PUB_IP:-$(ip -4 addr | sed -ne 's|^.* inet \([^/]*\)/.* scope global.*$|\1|p' | awk '{print $1}' | head -1)}
if [[ -z ${SERVER_PUB_IP} ]]; then if [[ -z ${SERVER_PUB_IP} ]]; then
# Detect public IPv6 address # Detect public IPv6 address
SERVER_PUB_IP=$(ip -6 addr | sed -ne 's|^.* inet6 \([^/]*\)/.* scope global.*$|\1|p' | head -1) SERVER_PUB_IP=$(ip -6 addr | sed -ne 's|^.* inet6 \([^/]*\)/.* scope global.*$|\1|p' | head -1)
fi fi
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 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 # Detect public interface and pre-fill for the user
SERVER_NIC="$(ip -4 route ls | grep default | grep -Po '(?<=dev )(\S+)' | head -1)" SERVER_NIC="${SERVER_NIC:-$(ip -4 route ls | grep default | grep -Po '(?<=dev )(\S+)' | head -1)}"
until [[ ${SERVER_PUB_NIC} =~ ^[a-zA-Z0-9_]+$ ]]; do APPROVE_NIC=${APPROVE_NIC:-n}
if [[ ${APPROVE_IP} =~ n ]]; then
until [[ ${SERVER_PUB_NIC} =~ ^[a-zA-Z0-9_]+$ || ${APPROVE_NIC} =~ n ]]; do
read -rp "Public interface: " -e -i "${SERVER_NIC}" SERVER_PUB_NIC read -rp "Public interface: " -e -i "${SERVER_NIC}" SERVER_PUB_NIC
done done
else
SERVER_PUB_NIC="${SERVER_NIC}"
fi
until [[ ${SERVER_WG_NIC} =~ ^[a-zA-Z0-9_]+$ && ${#SERVER_WG_NIC} -lt 16 ]]; do until [[ ${SERVER_WG_NIC} =~ ^[a-zA-Z0-9_]+$ && ${#SERVER_WG_NIC} -lt 16 ]]; do
read -rp "WireGuard interface name: " -e -i wg0 SERVER_WG_NIC read -rp "WireGuard interface name: " -e -i "${SERVER_WG_NIC_DEFAULT}" SERVER_WG_NIC
done done
until [[ ${SERVER_WG_IPV4} =~ ^([0-9]{1,3}\.){3} ]]; do until [[ ${SERVER_WG_IPV4} =~ ^([0-9]{1,3}\.){3} ]]; do
read -rp "Server WireGuard IPv4: " -e -i 10.66.66.1 SERVER_WG_IPV4 read -rp "Server WireGuard IPv4: " -e -i "${SERVER_WG_IPV4_DEFAULT}" SERVER_WG_IPV4
done done
until [[ ${SERVER_WG_IPV6} =~ ^([a-f0-9]{1,4}:){3,4}: ]]; do until [[ ${SERVER_WG_IPV6} =~ ^([a-f0-9]{1,4}:){3,4}: ]]; do
read -rp "Server WireGuard IPv6: " -e -i fd42:42:42::1 SERVER_WG_IPV6 read -rp "Server WireGuard IPv6: " -e -i "${SERVER_WG_IPV6_DEFAULT}" SERVER_WG_IPV6
done done
# Generate random number within private ports range # Generate random number within private ports range
@ -143,10 +152,10 @@ function installQuestions() {
# Adguard DNS by default # Adguard DNS by default
until [[ ${CLIENT_DNS_1} =~ ^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$ ]]; do until [[ ${CLIENT_DNS_1} =~ ^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$ ]]; do
read -rp "First DNS resolver to use for the clients: " -e -i 1.1.1.1 CLIENT_DNS_1 read -rp "First DNS resolver to use for the clients: " -e -i "${CLIENT_DNS_1_DEFAULT}" CLIENT_DNS_1
done done
until [[ ${CLIENT_DNS_2} =~ ^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$ ]]; do until [[ ${CLIENT_DNS_2} =~ ^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$ ]]; do
read -rp "Second DNS resolver to use for the clients (optional): " -e -i 1.0.0.1 CLIENT_DNS_2 read -rp "Second DNS resolver to use for the clients (optional): " -e -i "${CLIENT_DNS_2_DEFAULT}" CLIENT_DNS_2
if [[ ${CLIENT_DNS_2} == "" ]]; then if [[ ${CLIENT_DNS_2} == "" ]]; then
CLIENT_DNS_2="${CLIENT_DNS_1}" CLIENT_DNS_2="${CLIENT_DNS_1}"
fi fi
@ -156,17 +165,44 @@ function installQuestions() {
echo -e "\nWireGuard uses a parameter called AllowedIPs to determine what is routed over the VPN." echo -e "\nWireGuard uses a parameter called AllowedIPs to determine what is routed over the VPN."
read -rp "Allowed IPs list for generated clients (leave default to route everything): " -e -i '0.0.0.0/0,::/0' ALLOWED_IPS read -rp "Allowed IPs list for generated clients (leave default to route everything): " -e -i '0.0.0.0/0,::/0' ALLOWED_IPS
if [[ ${ALLOWED_IPS} == "" ]]; then if [[ ${ALLOWED_IPS} == "" ]]; then
ALLOWED_IPS="0.0.0.0/0,::/0" ALLOWED_IPS="${ALLOWED_IPS_DEFAULTS}"
fi fi
done done
echo "" echo ""
echo "Okay, that was all I needed. We are ready to setup your WireGuard server now." 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." echo "You will be able to generate a client at the end of the installation."
APPROVE_INSTALL=${APPROVE_INSTALL:-n}
if [[ $APPROVE_INSTALL =~ n ]]; then
read -n1 -r -p "Press any key to continue..." read -n1 -r -p "Press any key to continue..."
fi
} }
function installWireGuard() { function installWireGuard() {
SERVER_WG_NIC_DEFAULT="wg0"
SERVER_WG_IPV4_DEFAULT="10.66.66.1"
SERVER_WG_IPV6_DEFAULT="fd42:42:42::1"
CLIENT_DNS_1_DEFAULT="1.1.1.1"
CLIENT_DNS_2_DEFAULT="1.0.0.1"
ALLOWED_IPS_DEFAULTS="0.0.0.0/0,::/0"
if [[ ${APPROVE_INSTALL} == "y" ]]; then
# Set default choices so that no questions will be asked.
APPROVE_IP=${APPROVE_IP:-y}
APPROVE_NIC=${APPROVE_NIC:-y}
SERVER_WG_NIC=${SERVER_WG_NIC:-$SERVER_WG_NIC_DEFAULT}
SERVER_WG_IPV4=${SERVER_WG_IPV4:-$SERVER_WG_IPV4_DEFAULT}
SERVER_WG_IPV6=${SERVER_WG_IPV6:-$SERVER_WG_IPV6_DEFAULT}
SERVER_PORT=${SERVER_PORT:-$(shuf -i49152-65535 -n1)}
CLIENT_DNS_1=${CLIENT_DNS_1:-$CLIENT_DNS_1_DEFAULT}
CLIENT_DNS_2=${CLIENT_DNS_2:-$CLIENT_DNS_2_DEFAULT}
CLIENT_NAME=${CLIENT_NAME:-client}
ALLOWED_IPS=${ALLOWED_IPS:-$ALLOWED_IPS_DEFAULTS}
# Behind NAT, we'll default to the publicly reachable IPv4.
SERVER_PUB_IP=${SERVER_PUB_IP:-$(curl -s https://api.ipify.org)}
fi
# Run setup questions first # Run setup questions first
installQuestions installQuestions
@ -295,6 +331,7 @@ function newClient() {
echo "" echo ""
echo "The client name must consist of alphanumeric character(s). It may also include underscores or dashes and can't exceed 15 chars." echo "The client name must consist of alphanumeric character(s). It may also include underscores or dashes and can't exceed 15 chars."
CLIENT_EXISTS=$(grep -c -E "^### Client ${CLIENT_NAME}\$" "/etc/wireguard/${SERVER_WG_NIC}.conf")
until [[ ${CLIENT_NAME} =~ ^[a-zA-Z0-9_-]+$ && ${CLIENT_EXISTS} == '0' && ${#CLIENT_NAME} -lt 16 ]]; do until [[ ${CLIENT_NAME} =~ ^[a-zA-Z0-9_-]+$ && ${CLIENT_EXISTS} == '0' && ${#CLIENT_NAME} -lt 16 ]]; do
read -rp "Client name: " -e CLIENT_NAME read -rp "Client name: " -e CLIENT_NAME
CLIENT_EXISTS=$(grep -c -E "^### Client ${CLIENT_NAME}\$" "/etc/wireguard/${SERVER_WG_NIC}.conf") CLIENT_EXISTS=$(grep -c -E "^### Client ${CLIENT_NAME}\$" "/etc/wireguard/${SERVER_WG_NIC}.conf")
@ -321,7 +358,11 @@ function newClient() {
BASE_IP=$(echo "$SERVER_WG_IPV4" | awk -F '.' '{ print $1"."$2"."$3 }') BASE_IP=$(echo "$SERVER_WG_IPV4" | awk -F '.' '{ print $1"."$2"."$3 }')
until [[ ${IPV4_EXISTS} == '0' ]]; do until [[ ${IPV4_EXISTS} == '0' ]]; do
if [[ $APPROVE_INSTALL =~ n ]]; then
read -rp "Client WireGuard IPv4: ${BASE_IP}." -e -i "${DOT_IP}" DOT_IP read -rp "Client WireGuard IPv4: ${BASE_IP}." -e -i "${DOT_IP}" DOT_IP
fi
CLIENT_WG_IPV4="${BASE_IP}.${DOT_IP}" CLIENT_WG_IPV4="${BASE_IP}.${DOT_IP}"
IPV4_EXISTS=$(grep -c "$CLIENT_WG_IPV4/32" "/etc/wireguard/${SERVER_WG_NIC}.conf") IPV4_EXISTS=$(grep -c "$CLIENT_WG_IPV4/32" "/etc/wireguard/${SERVER_WG_NIC}.conf")
@ -334,7 +375,11 @@ function newClient() {
BASE_IP=$(echo "$SERVER_WG_IPV6" | awk -F '::' '{ print $1 }') BASE_IP=$(echo "$SERVER_WG_IPV6" | awk -F '::' '{ print $1 }')
until [[ ${IPV6_EXISTS} == '0' ]]; do until [[ ${IPV6_EXISTS} == '0' ]]; do
if [[ $APPROVE_INSTALL =~ n ]]; then
read -rp "Client WireGuard IPv6: ${BASE_IP}::" -e -i "${DOT_IP}" DOT_IP read -rp "Client WireGuard IPv6: ${BASE_IP}::" -e -i "${DOT_IP}" DOT_IP
fi
CLIENT_WG_IPV6="${BASE_IP}::${DOT_IP}" CLIENT_WG_IPV6="${BASE_IP}::${DOT_IP}"
IPV6_EXISTS=$(grep -c "${CLIENT_WG_IPV6}/128" "/etc/wireguard/${SERVER_WG_NIC}.conf") IPV6_EXISTS=$(grep -c "${CLIENT_WG_IPV6}/128" "/etc/wireguard/${SERVER_WG_NIC}.conf")