Created
February 26, 2022 10:27
-
-
Save snehesht/e8e73519ce8212f5311c51ace9fdcb92 to your computer and use it in GitHub Desktop.
Install Wireguard
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
# Secure WireGuard server installer | |
# https://github.com/angristan/wireguard-install | |
RED='\033[0;31m' | |
ORANGE='\033[0;33m' | |
NC='\033[0m' | |
function isRoot() { | |
if [ "${EUID}" -ne 0 ]; then | |
echo "You need to run this script as root" | |
exit 1 | |
fi | |
} | |
function checkVirt() { | |
if [ "$(systemd-detect-virt)" == "openvz" ]; then | |
echo "OpenVZ is not supported" | |
exit 1 | |
fi | |
if [ "$(systemd-detect-virt)" == "lxc" ]; then | |
echo "LXC is not supported (yet)." | |
echo "WireGuard can technically run in an LXC container," | |
echo "but the kernel module has to be installed on the host," | |
echo "the container has to be run with some specific parameters" | |
echo "and only the tools need to be installed in the container." | |
exit 1 | |
fi | |
} | |
function checkOS() { | |
# Check OS version | |
if [[ -e /etc/debian_version ]]; then | |
source /etc/os-release | |
OS="${ID}" # debian or ubuntu | |
if [[ ${ID} == "debian" || ${ID} == "raspbian" ]]; then | |
if [[ ${VERSION_ID} -lt 10 ]]; then | |
echo "Your version of Debian (${VERSION_ID}) is not supported. Please use Debian 10 Buster or later" | |
exit 1 | |
fi | |
OS=debian # overwrite if raspbian | |
fi | |
elif [[ -e /etc/fedora-release ]]; then | |
source /etc/os-release | |
OS="${ID}" | |
elif [[ -e /etc/centos-release ]]; then | |
source /etc/os-release | |
OS=centos | |
elif [[ -e /etc/oracle-release ]]; then | |
source /etc/os-release | |
OS=oracle | |
elif [[ -e /etc/arch-release ]]; then | |
OS=arch | |
else | |
echo "Looks like you aren't running this installer on a Debian, Ubuntu, Fedora, CentOS, Oracle or Arch Linux system" | |
exit 1 | |
fi | |
} | |
function initialCheck() { | |
isRoot | |
checkVirt | |
checkOS | |
} | |
function installQuestions() { | |
echo "Welcome to the WireGuard installer!" | |
echo "The git repository is available at: https://github.com/angristan/wireguard-install" | |
echo "" | |
echo "I need to ask you a few questions before starting the setup." | |
echo "You can leave the default options and just press enter if you are ok with them." | |
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' | awk '{print $1}' | 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 | |
# 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 | |
read -rp "Public interface: " -e -i "${SERVER_NIC}" SERVER_PUB_NIC | |
done | |
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 | |
done | |
until [[ ${SERVER_WG_IPV4} =~ ^([0-9]{1,3}\.){3} ]]; do | |
read -rp "Server's WireGuard IPv4: " -e -i 10.66.66.1 SERVER_WG_IPV4 | |
done | |
until [[ ${SERVER_WG_IPV6} =~ ^([a-f0-9]{1,4}:){3,4}: ]]; do | |
read -rp "Server's WireGuard IPv6: " -e -i fd42:42:42::1 SERVER_WG_IPV6 | |
done | |
# Generate random number within private ports range | |
RANDOM_PORT=$(shuf -i49152-65535 -n1) | |
until [[ ${SERVER_PORT} =~ ^[0-9]+$ ]] && [ "${SERVER_PORT}" -ge 1 ] && [ "${SERVER_PORT}" -le 65535 ]; do | |
read -rp "Server's WireGuard port [1-65535]: " -e -i "${RANDOM_PORT}" SERVER_PORT | |
done | |
# 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 | |
read -rp "First DNS resolver to use for the clients: " -e -i 94.140.14.14 CLIENT_DNS_1 | |
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 | |
read -rp "Second DNS resolver to use for the clients (optional): " -e -i 94.140.15.15 CLIENT_DNS_2 | |
if [[ ${CLIENT_DNS_2} == "" ]]; then | |
CLIENT_DNS_2="${CLIENT_DNS_1}" | |
fi | |
done | |
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..." | |
} | |
function installWireGuard() { | |
# Run setup questions first | |
installQuestions | |
# Install WireGuard tools and module | |
if [[ ${OS} == 'ubuntu' ]] || [[ ${OS} == 'debian' && ${VERSION_ID} -gt 10 ]]; then | |
apt-get update | |
apt-get install -y wireguard iptables resolvconf qrencode | |
elif [[ ${OS} == 'debian' ]]; then | |
if ! grep -rqs "^deb .* buster-backports" /etc/apt/; then | |
echo "deb http://deb.debian.org/debian buster-backports main" >/etc/apt/sources.list.d/backports.list | |
apt-get update | |
fi | |
apt update | |
apt-get install -y iptables resolvconf qrencode | |
apt-get install -y -t buster-backports wireguard | |
elif [[ ${OS} == 'fedora' ]]; then | |
if [[ ${VERSION_ID} -lt 32 ]]; then | |
dnf install -y dnf-plugins-core | |
dnf copr enable -y jdoss/wireguard | |
dnf install -y wireguard-dkms | |
fi | |
dnf install -y wireguard-tools iptables qrencode | |
elif [[ ${OS} == 'centos' ]]; then | |
yum -y install epel-release elrepo-release | |
if [[ ${VERSION_ID} -eq 7 ]]; then | |
yum -y install yum-plugin-elrepo | |
fi | |
yum -y install kmod-wireguard wireguard-tools iptables qrencode | |
elif [[ ${OS} == 'oracle' ]]; then | |
dnf install -y oraclelinux-developer-release-el8 | |
dnf config-manager --disable -y ol8_developer | |
dnf config-manager --enable -y ol8_developer_UEKR6 | |
dnf config-manager --save -y --setopt=ol8_developer_UEKR6.includepkgs='wireguard-tools*' | |
dnf install -y wireguard-tools qrencode iptables | |
elif [[ ${OS} == 'arch' ]]; then | |
pacman -S --needed --noconfirm wireguard-tools qrencode | |
fi | |
# Make sure the directory exists (this does not seem the be the case on fedora) | |
mkdir /etc/wireguard >/dev/null 2>&1 | |
chmod 600 -R /etc/wireguard/ | |
SERVER_PRIV_KEY=$(wg genkey) | |
SERVER_PUB_KEY=$(echo "${SERVER_PRIV_KEY}" | wg pubkey) | |
# Save WireGuard settings | |
echo "SERVER_PUB_IP=${SERVER_PUB_IP} | |
SERVER_PUB_NIC=${SERVER_PUB_NIC} | |
SERVER_WG_NIC=${SERVER_WG_NIC} | |
SERVER_WG_IPV4=${SERVER_WG_IPV4} | |
SERVER_WG_IPV6=${SERVER_WG_IPV6} | |
SERVER_PORT=${SERVER_PORT} | |
SERVER_PRIV_KEY=${SERVER_PRIV_KEY} | |
SERVER_PUB_KEY=${SERVER_PUB_KEY} | |
CLIENT_DNS_1=${CLIENT_DNS_1} | |
CLIENT_DNS_2=${CLIENT_DNS_2}" >/etc/wireguard/params | |
# Add server interface | |
echo "[Interface] | |
Address = ${SERVER_WG_IPV4}/24,${SERVER_WG_IPV6}/64 | |
ListenPort = ${SERVER_PORT} | |
PrivateKey = ${SERVER_PRIV_KEY}" >"/etc/wireguard/${SERVER_WG_NIC}.conf" | |
if pgrep firewalld; then | |
FIREWALLD_IPV4_ADDRESS=$(echo "${SERVER_WG_IPV4}" | cut -d"." -f1-3)".0" | |
FIREWALLD_IPV6_ADDRESS=$(echo "${SERVER_WG_IPV6}" | sed 's/:[^:]*$/:0/') | |
echo "PostUp = firewall-cmd --add-port ${SERVER_PORT}/udp && firewall-cmd --add-rich-rule='rule family=ipv4 source address=${FIREWALLD_IPV4_ADDRESS}/24 masquerade' && firewall-cmd --add-rich-rule='rule family=ipv6 source address=${FIREWALLD_IPV6_ADDRESS}/24 masquerade' | |
PostDown = firewall-cmd --remove-port ${SERVER_PORT}/udp && firewall-cmd --remove-rich-rule='rule family=ipv4 source address=${FIREWALLD_IPV4_ADDRESS}/24 masquerade' && firewall-cmd --remove-rich-rule='rule family=ipv6 source address=${FIREWALLD_IPV6_ADDRESS}/24 masquerade'" >>"/etc/wireguard/${SERVER_WG_NIC}.conf" | |
else | |
echo "PostUp = iptables -A FORWARD -i ${SERVER_PUB_NIC} -o ${SERVER_WG_NIC} -j ACCEPT; iptables -A FORWARD -i ${SERVER_WG_NIC} -j ACCEPT; iptables -t nat -A POSTROUTING -o ${SERVER_PUB_NIC} -j MASQUERADE; ip6tables -A FORWARD -i ${SERVER_WG_NIC} -j ACCEPT; ip6tables -t nat -A POSTROUTING -o ${SERVER_PUB_NIC} -j MASQUERADE | |
PostDown = iptables -D FORWARD -i ${SERVER_PUB_NIC} -o ${SERVER_WG_NIC} -j ACCEPT; iptables -D FORWARD -i ${SERVER_WG_NIC} -j ACCEPT; iptables -t nat -D POSTROUTING -o ${SERVER_PUB_NIC} -j MASQUERADE; ip6tables -D FORWARD -i ${SERVER_WG_NIC} -j ACCEPT; ip6tables -t nat -D POSTROUTING -o ${SERVER_PUB_NIC} -j MASQUERADE" >>"/etc/wireguard/${SERVER_WG_NIC}.conf" | |
fi | |
# Enable routing on the server | |
echo "net.ipv4.ip_forward = 1 | |
net.ipv6.conf.all.forwarding = 1" >/etc/sysctl.d/wg.conf | |
sysctl --system | |
systemctl start "wg-quick@${SERVER_WG_NIC}" | |
systemctl enable "wg-quick@${SERVER_WG_NIC}" | |
newClient | |
echo "If you want to add more clients, you simply need to run this script another time!" | |
# Check if WireGuard is running | |
systemctl is-active --quiet "wg-quick@${SERVER_WG_NIC}" | |
WG_RUNNING=$? | |
# WireGuard might not work if we updated the kernel. Tell the user to reboot | |
if [[ ${WG_RUNNING} -ne 0 ]]; then | |
echo -e "\n${RED}WARNING: WireGuard does not seem to be running.${NC}" | |
echo -e "${ORANGE}You can check if WireGuard is running with: systemctl status wg-quick@${SERVER_WG_NIC}${NC}" | |
echo -e "${ORANGE}If you get something like \"Cannot find device ${SERVER_WG_NIC}\", please reboot!${NC}" | |
fi | |
} | |
function newClient() { | |
ENDPOINT="${SERVER_PUB_IP}:${SERVER_PORT}" | |
echo "" | |
echo "Tell me a name for the client." | |
echo "The name must consist of alphanumeric character. It may also include an underscore or a dash and can't exceed 15 chars." | |
until [[ ${CLIENT_NAME} =~ ^[a-zA-Z0-9_-]+$ && ${CLIENT_EXISTS} == '0' && ${#CLIENT_NAME} -lt 16 ]]; do | |
read -rp "Client name: " -e CLIENT_NAME | |
CLIENT_EXISTS=$(grep -c -E "^### Client ${CLIENT_NAME}\$" "/etc/wireguard/${SERVER_WG_NIC}.conf") | |
if [[ ${CLIENT_EXISTS} == '1' ]]; then | |
echo "" | |
echo "A client with the specified name was already created, please choose another name." | |
echo "" | |
fi | |
done | |
for DOT_IP in {2..254}; do | |
DOT_EXISTS=$(grep -c "${SERVER_WG_IPV4::-1}${DOT_IP}" "/etc/wireguard/${SERVER_WG_NIC}.conf") | |
if [[ ${DOT_EXISTS} == '0' ]]; then | |
break | |
fi | |
done | |
if [[ ${DOT_EXISTS} == '1' ]]; then | |
echo "" | |
echo "The subnet configured supports only 253 clients." | |
exit 1 | |
fi | |
BASE_IP=$(echo "$SERVER_WG_IPV4" | awk -F '.' '{ print $1"."$2"."$3 }') | |
until [[ ${IPV4_EXISTS} == '0' ]]; do | |
read -rp "Client's WireGuard IPv4: ${BASE_IP}." -e -i "${DOT_IP}" DOT_IP | |
CLIENT_WG_IPV4="${BASE_IP}.${DOT_IP}" | |
IPV4_EXISTS=$(grep -c "$CLIENT_WG_IPV4/24" "/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 "" | |
fi | |
done | |
BASE_IP=$(echo "$SERVER_WG_IPV6" | awk -F '::' '{ print $1 }') | |
until [[ ${IPV6_EXISTS} == '0' ]]; do | |
read -rp "Client's WireGuard IPv6: ${BASE_IP}::" -e -i "${DOT_IP}" DOT_IP | |
CLIENT_WG_IPV6="${BASE_IP}::${DOT_IP}" | |
IPV6_EXISTS=$(grep -c "${CLIENT_WG_IPV6}/64" "/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 | |
# Generate key pair for the client | |
CLIENT_PRIV_KEY=$(wg genkey) | |
CLIENT_PUB_KEY=$(echo "${CLIENT_PRIV_KEY}" | wg pubkey) | |
CLIENT_PRE_SHARED_KEY=$(wg genpsk) | |
# Home directory of the user, where the client configuration will be written | |
if [ -e "/home/${CLIENT_NAME}" ]; then | |
# if $1 is a user name | |
HOME_DIR="/home/${CLIENT_NAME}" | |
elif [ "${SUDO_USER}" ]; then | |
# if not, use SUDO_USER | |
if [ "${SUDO_USER}" == "root" ]; then | |
# If running sudo as root | |
HOME_DIR="/root" | |
else | |
HOME_DIR="/home/${SUDO_USER}" | |
fi | |
else | |
# if not SUDO_USER, use /root | |
HOME_DIR="/root" | |
fi | |
# Create client file and add the server as a peer | |
echo "[Interface] | |
PrivateKey = ${CLIENT_PRIV_KEY} | |
Address = ${CLIENT_WG_IPV4}/32,${CLIENT_WG_IPV6}/128 | |
DNS = ${CLIENT_DNS_1},${CLIENT_DNS_2} | |
[Peer] | |
PublicKey = ${SERVER_PUB_KEY} | |
PresharedKey = ${CLIENT_PRE_SHARED_KEY} | |
Endpoint = ${ENDPOINT} | |
AllowedIPs = 0.0.0.0/0,::/0" >>"${HOME_DIR}/${SERVER_WG_NIC}-client-${CLIENT_NAME}.conf" | |
# Add the client as a peer to the server | |
echo -e "\n### Client ${CLIENT_NAME} | |
[Peer] | |
PublicKey = ${CLIENT_PUB_KEY} | |
PresharedKey = ${CLIENT_PRE_SHARED_KEY} | |
AllowedIPs = ${CLIENT_WG_IPV4}/32,${CLIENT_WG_IPV6}/128" >>"/etc/wireguard/${SERVER_WG_NIC}.conf" | |
wg syncconf "${SERVER_WG_NIC}" <(wg-quick strip "${SERVER_WG_NIC}") | |
echo -e "\nHere is your client config file as a QR Code:" | |
qrencode -t ansiutf8 -l L <"${HOME_DIR}/${SERVER_WG_NIC}-client-${CLIENT_NAME}.conf" | |
echo "It is also available in ${HOME_DIR}/${SERVER_WG_NIC}-client-${CLIENT_NAME}.conf" | |
} | |
function revokeClient() { | |
NUMBER_OF_CLIENTS=$(grep -c -E "^### Client" "/etc/wireguard/${SERVER_WG_NIC}.conf") | |
if [[ ${NUMBER_OF_CLIENTS} == '0' ]]; then | |
echo "" | |
echo "You have no existing clients!" | |
exit 1 | |
fi | |
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) | |
# remove [Peer] block matching $CLIENT_NAME | |
sed -i "/^### Client ${CLIENT_NAME}\$/,/^$/d" "/etc/wireguard/${SERVER_WG_NIC}.conf" | |
# remove generated client file | |
rm -f "${HOME}/${SERVER_WG_NIC}-client-${CLIENT_NAME}.conf" | |
# restart wireguard to apply changes | |
wg syncconf "${SERVER_WG_NIC}" <(wg-quick strip "${SERVER_WG_NIC}") | |
} | |
function uninstallWg() { | |
echo "" | |
read -rp "Do you really want to remove WireGuard? [y/n]: " -e -i n REMOVE | |
if [[ $REMOVE == 'y' ]]; then | |
checkOS | |
systemctl stop "wg-quick@${SERVER_WG_NIC}" | |
systemctl disable "wg-quick@${SERVER_WG_NIC}" | |
if [[ ${OS} == 'ubuntu' ]]; then | |
apt-get autoremove --purge -y wireguard qrencode | |
elif [[ ${OS} == 'debian' ]]; then | |
apt-get autoremove --purge -y wireguard qrencode | |
elif [[ ${OS} == 'fedora' ]]; then | |
dnf remove -y wireguard-tools qrencode | |
if [[ ${VERSION_ID} -lt 32 ]]; then | |
dnf remove -y wireguard-dkms | |
dnf copr disable -y jdoss/wireguard | |
fi | |
dnf autoremove -y | |
elif [[ ${OS} == 'centos' ]]; then | |
yum -y remove kmod-wireguard wireguard-tools qrencode | |
yum -y autoremove | |
elif [[ ${OS} == 'oracle' ]]; then | |
yum -y remove wireguard-tools qrencode | |
yum -y autoremove | |
elif [[ ${OS} == 'arch' ]]; then | |
pacman -Rs --noconfirm wireguard-tools qrencode | |
fi | |
rm -rf /etc/wireguard | |
rm -f /etc/sysctl.d/wg.conf | |
# Reload sysctl | |
sysctl --system | |
# Check if WireGuard is running | |
systemctl is-active --quiet "wg-quick@${SERVER_WG_NIC}" | |
WG_RUNNING=$? | |
if [[ ${WG_RUNNING} -eq 0 ]]; then | |
echo "WireGuard failed to uninstall properly." | |
exit 1 | |
else | |
echo "WireGuard uninstalled successfully." | |
exit 0 | |
fi | |
else | |
echo "" | |
echo "Removal aborted!" | |
fi | |
} | |
function manageMenu() { | |
echo "Welcome to WireGuard-install!" | |
echo "The git repository is available at: https://github.com/angristan/wireguard-install" | |
echo "" | |
echo "It looks like WireGuard is already installed." | |
echo "" | |
echo "What do you want to do?" | |
echo " 1) Add a new user" | |
echo " 2) Revoke existing user" | |
echo " 3) Uninstall WireGuard" | |
echo " 4) Exit" | |
until [[ ${MENU_OPTION} =~ ^[1-4]$ ]]; do | |
read -rp "Select an option [1-4]: " MENU_OPTION | |
done | |
case "${MENU_OPTION}" in | |
1) | |
newClient | |
;; | |
2) | |
revokeClient | |
;; | |
3) | |
uninstallWg | |
;; | |
4) | |
exit 0 | |
;; | |
esac | |
} | |
# Check for root, virt, OS... | |
initialCheck | |
# Check if WireGuard is already installed and load params | |
if [[ -e /etc/wireguard/params ]]; then | |
source /etc/wireguard/params | |
manageMenu | |
else | |
installWireGuard | |
fi |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment