#!/bin/bash # AmneziaWG server installer # https://github.com/varckin/amneziawg-install RED='\033[0;31m' ORANGE='\033[0;33m' GREEN='\033[0;32m' NC='\033[0m' AMNEZIAWG_DIR="/etc/amnezia/amneziawg" if [ -n "$AWG_INSTANCE" ]; then PARAMS_FILE="/etc/amnezia/amneziawg/$AWG_INSTANCE.params" else PARAMS_FILE="/etc/amnezia/amneziawg/awg0.params" fi 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() { source /etc/os-release OS="${ID}" if [[ ${OS} == "debian" || ${OS} == "raspbian" ]]; then if [[ ${VERSION_ID} -lt 11 ]]; then echo "Your version of Debian (${VERSION_ID}) is not supported. Please use Debian 11 Bullseye or later" exit 1 fi OS=debian # overwrite if raspbian elif [[ ${OS} == "ubuntu" ]]; then RELEASE_YEAR=$(echo "${VERSION_ID}" | cut -d'.' -f1) if [[ ${RELEASE_YEAR} -lt 20 ]]; then echo "Your version of Ubuntu (${VERSION_ID}) is not supported. Please use Ubuntu 20.04 or later" exit 1 fi elif [[ ${OS} == "fedora" ]]; then if [[ ${VERSION_ID} -lt 39 ]]; then echo "Your version of Fedora (${VERSION_ID}) is not supported. Please use Fedora 39 or later" exit 1 fi elif [[ ${OS} == 'centos' ]] || [[ ${OS} == 'almalinux' ]] || [[ ${OS} == 'rocky' ]]; then if [[ ${VERSION_ID} == 7* ]] || [[ ${VERSION_ID} == 8* ]]; then echo "Your version of CentOS (${VERSION_ID}) is not supported. Please use CentOS 9 or later" exit 1 fi else echo "Looks like you aren't running this installer on a Debian, Ubuntu, Fedora, CentOS, AlmaLinux or Rocky Linux system" exit 1 fi } function getHomeDirForClient() { local CLIENT_NAME=$1 if [ -z "${CLIENT_NAME}" ]; then echo "Error: getHomeDirForClient() requires a client name as argument" exit 1 fi # 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 echo "$HOME_DIR" } function initialCheck() { isRoot checkVirt checkOS } function readJminAndJmax() { SERVER_AWG_JMIN=0 SERVER_AWG_JMAX=0 until [[ ${SERVER_AWG_JMIN} =~ ^[0-9]+$ ]] && (( ${SERVER_AWG_JMIN} >= 1 )) && (( ${SERVER_AWG_JMIN} <= 1280 )); do read -rp "Server AmneziaWG Jmin [1-1280]: " -e -i 50 SERVER_AWG_JMIN done until [[ ${SERVER_AWG_JMAX} =~ ^[0-9]+$ ]] && (( ${SERVER_AWG_JMAX} >= 1 )) && (( ${SERVER_AWG_JMAX} <= 1280 )); do read -rp "Server AmneziaWG Jmax [1-1280]: " -e -i 1000 SERVER_AWG_JMAX done } function generateS1AndS2() { RANDOM_AWG_S1=$(shuf -i15-150 -n1) RANDOM_AWG_S2=$(shuf -i15-150 -n1) } function readS1AndS2() { SERVER_AWG_S1=0 SERVER_AWG_S2=0 until [[ ${SERVER_AWG_S1} =~ ^[0-9]+$ ]] && (( ${SERVER_AWG_S1} >= 15 )) && (( ${SERVER_AWG_S1} <= 150 )); do read -rp "Server AmneziaWG S1 [15-150]: " -e -i ${RANDOM_AWG_S1} SERVER_AWG_S1 done until [[ ${SERVER_AWG_S2} =~ ^[0-9]+$ ]] && (( ${SERVER_AWG_S2} >= 15 )) && (( ${SERVER_AWG_S2} <= 150 )); do read -rp "Server AmneziaWG S2 [15-150]: " -e -i ${RANDOM_AWG_S2} SERVER_AWG_S2 done } function generateH1AndH2AndH3AndH4() { RANDOM_AWG_H1=$(shuf -i5-2147483647 -n1) RANDOM_AWG_H2=$(shuf -i5-2147483647 -n1) RANDOM_AWG_H3=$(shuf -i5-2147483647 -n1) RANDOM_AWG_H4=$(shuf -i5-2147483647 -n1) } function readH1AndH2AndH3AndH4() { SERVER_AWG_H1=0 SERVER_AWG_H2=0 SERVER_AWG_H3=0 SERVER_AWG_H4=0 until [[ ${SERVER_AWG_H1} =~ ^[0-9]+$ ]] && (( ${SERVER_AWG_H1} >= 5 )) && (( ${SERVER_AWG_H1} <= 2147483647 )); do read -rp "Server AmneziaWG H1 [5-2147483647]: " -e -i ${RANDOM_AWG_H1} SERVER_AWG_H1 done until [[ ${SERVER_AWG_H2} =~ ^[0-9]+$ ]] && (( ${SERVER_AWG_H2} >= 5 )) && (( ${SERVER_AWG_H2} <= 2147483647 )); do read -rp "Server AmneziaWG H2 [5-2147483647]: " -e -i ${RANDOM_AWG_H2} SERVER_AWG_H2 done until [[ ${SERVER_AWG_H3} =~ ^[0-9]+$ ]] && (( ${SERVER_AWG_H3} >= 5 )) && (( ${SERVER_AWG_H3} <= 2147483647 )); do read -rp "Server AmneziaWG H3 [5-2147483647]: " -e -i ${RANDOM_AWG_H3} SERVER_AWG_H3 done until [[ ${SERVER_AWG_H4} =~ ^[0-9]+$ ]] && (( ${SERVER_AWG_H4} >= 5 )) && (( ${SERVER_AWG_H4} <= 2147483647 )); do read -rp "Server AmneziaWG H4 [5-2147483647]: " -e -i ${RANDOM_AWG_H4} SERVER_AWG_H4 done } function installQuestions() { local instance_label= local default_ifname=awg0 if [ -n "$AWG_INSTANCE" ]; then instance_label="($AWG_INSTANCE instance) " default_ifname="awg_${AWG_INSTANCE/-/_}" SERVER_AWG_NIC="$AWG_INSTANCE" fi echo "AmneziaWG server ${instance_label}installer (https://github.com/varckin/amneziawg-install)" echo "" echo "I need to ask you a few questions before starting the setup." echo "You can keep 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 "Public IPv4 or IPv6 address or domain: " -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_AWG_NIC} =~ ^[a-zA-Z0-9_]+$ && ${#SERVER_AWG_NIC} -lt 16 ]]; do read -rp "AmneziaWG interface name: " -e -i $default_ifname SERVER_AWG_NIC done until [[ ${SERVER_AWG_IPV4} =~ ^([0-9]{1,3}\.){3} ]]; do read -rp "Server AmneziaWG IPv4: " -e -i 10.66.66.1 SERVER_AWG_IPV4 done until [[ ${SERVER_AWG_IPV6} =~ ^([a-f0-9]{1,4}:){3,4}: ]]; do read -rp "Server AmneziaWG IPv6: " -e -i fd42:42:42::1 SERVER_AWG_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 AmneziaWG 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 1.1.1.1 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 1.0.0.1 CLIENT_DNS_2 if [[ ${CLIENT_DNS_2} == "" ]]; then CLIENT_DNS_2="${CLIENT_DNS_1}" fi done until [[ ${ALLOWED_IPS} =~ ^.+$ ]]; do echo -e "\nAmneziaWG 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 if [[ ${ALLOWED_IPS} == "" ]]; then ALLOWED_IPS="0.0.0.0/0,::/0" fi done # Jc RANDOM_AWG_JC=$(shuf -i3-10 -n1) until [[ ${SERVER_AWG_JC} =~ ^[0-9]+$ ]] && (( ${SERVER_AWG_JC} >= 1 )) && (( ${SERVER_AWG_JC} <= 128 )); do read -rp "Server AmneziaWG Jc [1-128]: " -e -i ${RANDOM_AWG_JC} SERVER_AWG_JC done # Jmin && Jmax readJminAndJmax until [ "${SERVER_AWG_JMIN}" -le "${SERVER_AWG_JMAX}" ]; do echo "AmneziaWG require Jmin < Jmax" readJminAndJmax done # S1 && S2 generateS1AndS2 while (( ${RANDOM_AWG_S1} + 56 == ${RANDOM_AWG_S2} )); do generateS1AndS2 done readS1AndS2 while (( ${SERVER_AWG_S1} + 56 == ${SERVER_AWG_S2} )); do echo "AmneziaWG require S1 + 56 <> S2" readS1AndS2 done # H1 && H2 && H3 && H4 generateH1AndH2AndH3AndH4 while (( ${RANDOM_AWG_H1} == ${RANDOM_AWG_H2} )) || (( ${RANDOM_AWG_H1} == ${RANDOM_AWG_H3} )) || (( ${RANDOM_AWG_H1} == ${RANDOM_AWG_H4} )) || (( ${RANDOM_AWG_H2} == ${RANDOM_AWG_H3} )) || (( ${RANDOM_AWG_H2} == ${RANDOM_AWG_H4} )) || (( ${RANDOM_AWG_H3} == ${RANDOM_AWG_H4} )); do generateH1AndH2AndH3AndH4 done readH1AndH2AndH3AndH4 while (( ${SERVER_AWG_H1} == ${SERVER_AWG_H2} )) || (( ${SERVER_AWG_H1} == ${SERVER_AWG_H3} )) || (( ${SERVER_AWG_H1} == ${SERVER_AWG_H4} )) || (( ${SERVER_AWG_H2} == ${SERVER_AWG_H3} )) || (( ${SERVER_AWG_H2} == ${SERVER_AWG_H4} )) || (( ${SERVER_AWG_H3} == ${SERVER_AWG_H4} )); do echo "AmneziaWG require H1 and H2 and H3 and H4 be different" readH1AndH2AndH3AndH4 done echo "" echo "Okay, that was all I needed. We are ready to setup your AmneziaWG 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 installAmneziaWG() { # Run setup questions first installQuestions # Install AmneziaWG tools and module if [[ ${OS} == 'ubuntu' ]]; then if [[ -e /etc/apt/sources.list.d/ubuntu.sources ]]; then if ! grep -q "deb-src" /etc/apt/sources.list.d/ubuntu.sources; then cp /etc/apt/sources.list.d/ubuntu.sources /etc/apt/sources.list.d/amneziawg.sources sed -i 's/deb/deb-src/' /etc/apt/sources.list.d/amneziawg.sources fi else if ! grep -q "^deb-src" /etc/apt/sources.list; then cp /etc/apt/sources.list /etc/apt/sources.list.d/amneziawg.sources.list sed -i 's/^deb/deb-src/' /etc/apt/sources.list.d/amneziawg.sources.list fi fi apt install -y software-properties-common add-apt-repository -y ppa:amnezia/ppa apt install -y amneziawg amneziawg-tools qrencode elif [[ ${OS} == 'debian' ]]; then if ! grep -q "^deb-src" /etc/apt/sources.list; then cp /etc/apt/sources.list /etc/apt/sources.list.d/amneziawg.sources.list sed -i 's/^deb/deb-src/' /etc/apt/sources.list.d/amneziawg.sources.list fi apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 57290828 echo "deb https://ppa.launchpadcontent.net/amnezia/ppa/ubuntu focal main" >>/etc/apt/sources.list.d/amneziawg.sources.list echo "deb-src https://ppa.launchpadcontent.net/amnezia/ppa/ubuntu focal main" >>/etc/apt/sources.list.d/amneziawg.sources.list apt update apt install -y amneziawg amneziawg-tools qrencode iptables elif [[ ${OS} == 'fedora' ]]; then dnf config-manager --set-enabled crb dnf install -y epel-release dnf copr enable -y amneziavpn/amneziawg dnf install -y amneziawg-dkms amneziawg-tools qrencode iptables elif [[ ${OS} == 'centos' ]] || [[ ${OS} == 'almalinux' ]] || [[ ${OS} == 'rocky' ]]; then dnf config-manager --set-enabled crb dnf install -y epel-release dnf copr enable -y amneziavpn/amneziawg dnf install -y amneziawg-dkms amneziawg-tools qrencode iptables fi SERVER_AWG_CONF="${AMNEZIAWG_DIR}/${SERVER_AWG_NIC}.conf" SERVER_PRIV_KEY=$(awg genkey) SERVER_PUB_KEY=$(echo "${SERVER_PRIV_KEY}" | awg pubkey) # Save WireGuard settings echo "SERVER_PUB_IP=${SERVER_PUB_IP} SERVER_PUB_NIC=${SERVER_PUB_NIC} SERVER_AWG_NIC=${SERVER_AWG_NIC} SERVER_AWG_IPV4=${SERVER_AWG_IPV4} SERVER_AWG_IPV6=${SERVER_AWG_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} ALLOWED_IPS=${ALLOWED_IPS} SERVER_AWG_JC=${SERVER_AWG_JC} SERVER_AWG_JMIN=${SERVER_AWG_JMIN} SERVER_AWG_JMAX=${SERVER_AWG_JMAX} SERVER_AWG_S1=${SERVER_AWG_S1} SERVER_AWG_S2=${SERVER_AWG_S2} SERVER_AWG_H1=${SERVER_AWG_H1} SERVER_AWG_H2=${SERVER_AWG_H2} SERVER_AWG_H3=${SERVER_AWG_H3} SERVER_AWG_H4=${SERVER_AWG_H4}" >"$PARAMS_FILE" # Add server interface echo "[Interface] Address = ${SERVER_AWG_IPV4}/24,${SERVER_AWG_IPV6}/64 ListenPort = ${SERVER_PORT} PrivateKey = ${SERVER_PRIV_KEY} Jc = ${SERVER_AWG_JC} Jmin = ${SERVER_AWG_JMIN} Jmax = ${SERVER_AWG_JMAX} S1 = ${SERVER_AWG_S1} S2 = ${SERVER_AWG_S2} H1 = ${SERVER_AWG_H1} H2 = ${SERVER_AWG_H2} H3 = ${SERVER_AWG_H3} H4 = ${SERVER_AWG_H4}" >"${SERVER_AWG_CONF}" if pgrep firewalld; then FIREWALLD_IPV4_ADDRESS=$(echo "${SERVER_AWG_IPV4}" | cut -d"." -f1-3)".0" FIREWALLD_IPV6_ADDRESS=$(echo "${SERVER_AWG_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'" >>"${SERVER_AWG_CONF}" else echo "PostUp = iptables -I INPUT -p udp --dport ${SERVER_PORT} -j ACCEPT PostUp = iptables -I FORWARD -i ${SERVER_PUB_NIC} -o ${SERVER_AWG_NIC} -j ACCEPT PostUp = iptables -I FORWARD -i ${SERVER_AWG_NIC} -j ACCEPT PostUp = iptables -t nat -A POSTROUTING -o ${SERVER_PUB_NIC} -j MASQUERADE PostUp = ip6tables -I INPUT -p udp --dport ${SERVER_PORT} -j ACCEPT PostUp = ip6tables -I FORWARD -i ${SERVER_PUB_NIC} -o ${SERVER_AWG_NIC} -j ACCEPT PostUp = ip6tables -I FORWARD -i ${SERVER_AWG_NIC} -j ACCEPT PostUp = ip6tables -t nat -A POSTROUTING -o ${SERVER_PUB_NIC} -j MASQUERADE PostDown = iptables -D INPUT -p udp --dport ${SERVER_PORT} -j ACCEPT PostDown = iptables -D FORWARD -i ${SERVER_PUB_NIC} -o ${SERVER_AWG_NIC} -j ACCEPT PostDown = iptables -D FORWARD -i ${SERVER_AWG_NIC} -j ACCEPT PostDown = iptables -t nat -D POSTROUTING -o ${SERVER_PUB_NIC} -j MASQUERADE PostDown = ip6tables -D INPUT -p udp --dport ${SERVER_PORT} -j ACCEPT PostDown = ip6tables -D FORWARD -i ${SERVER_PUB_NIC} -o ${SERVER_AWG_NIC} -j ACCEPT PostDown = ip6tables -D FORWARD -i ${SERVER_AWG_NIC} -j ACCEPT PostDown = ip6tables -t nat -D POSTROUTING -o ${SERVER_PUB_NIC} -j MASQUERADE" >>"${SERVER_AWG_CONF}" fi # Enable routing on the server echo "net.ipv4.ip_forward = 1 net.ipv6.conf.all.forwarding = 1" >/etc/sysctl.d/awg.conf sysctl --system systemctl start "awg-quick@${SERVER_AWG_NIC}" systemctl enable "awg-quick@${SERVER_AWG_NIC}" newClient echo -e "${GREEN}If you want to add more clients, you simply need to run this script another time!${NC}" # Check if AmneziaWG is running systemctl is-active --quiet "awg-quick@${SERVER_AWG_NIC}" AWG_RUNNING=$? # AmneziaWG might not work if we updated the kernel. Tell the user to reboot if [[ ${AWG_RUNNING} -ne 0 ]]; then echo -e "\n${RED}WARNING: AmneziaWG does not seem to be running.${NC}" echo -e "${ORANGE}You can check if AmneziaWG is running with: systemctl status awg-quick@${SERVER_AWG_NIC}${NC}" echo -e "${ORANGE}If you get something like \"Cannot find device ${SERVER_AWG_NIC}\", please reboot!${NC}" else # AmneziaWG is running echo -e "\n${GREEN}AmneziaWG is running.${NC}" echo -e "${GREEN}You can check the status of AmneziaWG with: systemctl status awg-quick@${SERVER_AWG_NIC}\n\n${NC}" echo -e "${ORANGE}If you don't have internet connectivity from your client, try to reboot the server.${NC}" fi } function newClient() { # If SERVER_PUB_IP is IPv6, add brackets if missing if [[ ${SERVER_PUB_IP} =~ .*:.* ]]; then if [[ ${SERVER_PUB_IP} != *"["* ]] || [[ ${SERVER_PUB_IP} != *"]"* ]]; then SERVER_PUB_IP="[${SERVER_PUB_IP}]" fi fi ENDPOINT="${SERVER_PUB_IP}:${SERVER_PORT}" echo "" echo "Client configuration" echo "" echo "The client name must consist of alphanumeric character(s). It may also include underscores or dashes 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}\$" "${SERVER_AWG_CONF}") if [[ ${CLIENT_EXISTS} != 0 ]]; then echo "" echo -e "${ORANGE}A client with the specified name was already created, please choose another name.${NC}" echo "" fi done for DOT_IP in {2..254}; do DOT_EXISTS=$(grep -c "${SERVER_AWG_IPV4::-1}${DOT_IP}" "${SERVER_AWG_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_AWG_IPV4" | awk -F '.' '{ print $1"."$2"."$3 }') until [[ ${IPV4_EXISTS} == '0' ]]; do read -rp "Client AmneziaWG IPv4: ${BASE_IP}." -e -i "${DOT_IP}" DOT_IP CLIENT_AWG_IPV4="${BASE_IP}.${DOT_IP}" IPV4_EXISTS=$(grep -c "$CLIENT_AWG_IPV4/32" "${SERVER_AWG_CONF}") if [[ ${IPV4_EXISTS} != 0 ]]; then echo "" echo -e "${ORANGE}A client with the specified IPv4 was already created, please choose another IPv4.${NC}" echo "" fi done BASE_IP=$(echo "$SERVER_AWG_IPV6" | awk -F '::' '{ print $1 }') until [[ ${IPV6_EXISTS} == '0' ]]; do read -rp "Client AmneziaWG IPv6: ${BASE_IP}::" -e -i "${DOT_IP}" DOT_IP CLIENT_AWG_IPV6="${BASE_IP}::${DOT_IP}" IPV6_EXISTS=$(grep -c "${CLIENT_AWG_IPV6}/128" "${SERVER_AWG_CONF}") if [[ ${IPV6_EXISTS} != 0 ]]; then echo "" echo -e "${ORANGE}A client with the specified IPv6 was already created, please choose another IPv6.${NC}" echo "" fi done # Generate key pair for the client CLIENT_PRIV_KEY=$(awg genkey) CLIENT_PUB_KEY=$(echo "${CLIENT_PRIV_KEY}" | awg pubkey) CLIENT_PRE_SHARED_KEY=$(awg genpsk) HOME_DIR=$(getHomeDirForClient "${CLIENT_NAME}") # Create client file and add the server as a peer echo "[Interface] PrivateKey = ${CLIENT_PRIV_KEY} Address = ${CLIENT_AWG_IPV4}/32,${CLIENT_AWG_IPV6}/128 DNS = ${CLIENT_DNS_1},${CLIENT_DNS_2} Jc = ${SERVER_AWG_JC} Jmin = ${SERVER_AWG_JMIN} Jmax = ${SERVER_AWG_JMAX} S1 = ${SERVER_AWG_S1} S2 = ${SERVER_AWG_S2} H1 = ${SERVER_AWG_H1} H2 = ${SERVER_AWG_H2} H3 = ${SERVER_AWG_H3} H4 = ${SERVER_AWG_H4} [Peer] PublicKey = ${SERVER_PUB_KEY} PresharedKey = ${CLIENT_PRE_SHARED_KEY} Endpoint = ${ENDPOINT} AllowedIPs = ${ALLOWED_IPS}" >"${HOME_DIR}/${SERVER_AWG_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_AWG_IPV4}/32,${CLIENT_AWG_IPV6}/128" >>"${SERVER_AWG_CONF}" awg syncconf "${SERVER_AWG_NIC}" <(awg-quick strip "${SERVER_AWG_NIC}") # Generate QR code if qrencode is installed if command -v qrencode &>/dev/null; then echo -e "${GREEN}\nHere is your client config file as a QR Code:\n${NC}" qrencode -t ansiutf8 -l L <"${HOME_DIR}/${SERVER_AWG_NIC}-client-${CLIENT_NAME}.conf" echo "" fi echo -e "${GREEN}Your client config file is in ${HOME_DIR}/${SERVER_AWG_NIC}-client-${CLIENT_NAME}.conf${NC}" } function listClients() { NUMBER_OF_CLIENTS=$(grep -c -E "^### Client" "${SERVER_AWG_CONF}") if [[ ${NUMBER_OF_CLIENTS} -eq 0 ]]; then echo "" echo "You have no existing clients!" exit 1 fi grep -E "^### Client" "${SERVER_AWG_CONF}" | cut -d ' ' -f 3 | nl -s ') ' } function revokeClient() { NUMBER_OF_CLIENTS=$(grep -c -E "^### Client" "${SERVER_AWG_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" "${SERVER_AWG_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" "${SERVER_AWG_CONF}" | cut -d ' ' -f 3 | sed -n "${CLIENT_NUMBER}"p) # remove [Peer] block matching $CLIENT_NAME sed -i "/^### Client ${CLIENT_NAME}\$/,/^$/d" "${SERVER_AWG_CONF}" # remove generated client file HOME_DIR=$(getHomeDirForClient "${CLIENT_NAME}") rm -f "${HOME_DIR}/${SERVER_AWG_NIC}-client-${CLIENT_NAME}.conf" # restart AmneziaWG to apply changes awg syncconf "${SERVER_AWG_NIC}" <(awg-quick strip "${SERVER_AWG_NIC}") } function uninstallAmneziaWG() { echo "" echo -e "\n${RED}WARNING: This will uninstall AmneziaWG and remove all the configuration files!${NC}" echo -e "${ORANGE}Please backup the /etc/amnezia/amneziawg directory if you want to keep your configuration files.\n${NC}" read -rp "Do you really want to remove AmneziaWG? [y/n]: " -e REMOVE REMOVE=${REMOVE:-n} if [[ $REMOVE == 'y' ]]; then checkOS systemctl stop "awg-quick@${SERVER_AWG_NIC}" systemctl disable "awg-quick@${SERVER_AWG_NIC}" # Disable routing rm -f /etc/sysctl.d/awg.conf sysctl --system # Remove config files rm -rf ${AMNEZIAWG_DIR}/* if [[ ${OS} == 'ubuntu' ]]; then apt remove -y amneziawg amneziawg-tools add-apt-repository -ry ppa:amnezia/ppa if [[ -e /etc/apt/sources.list.d/ubuntu.sources ]]; then rm -f /etc/apt/sources.list.d/amneziawg.sources else rm -f /etc/apt/sources.list.d/amneziawg.sources.list fi elif [[ ${OS} == 'debian' ]]; then apt-get remove -y amneziawg amneziawg-tools rm -f /etc/apt/sources.list.d/amneziawg.sources.list apt-key del 57290828 apt update elif [[ ${OS} == 'fedora' ]]; then dnf remove -y amneziawg-dkms amneziawg-tools dnf copr disable -y amneziavpn/amneziawg elif [[ ${OS} == 'centos' ]] || [[ ${OS} == 'almalinux' ]] || [[ ${OS} == 'rocky' ]]; then dnf remove -y amneziawg-dkms amneziawg-tools dnf copr disable -y amneziavpn/amneziawg fi # Check if AmneziaWG is running systemctl is-active --quiet "awg-quick@${SERVER_AWG_NIC}" AWG_RUNNING=$? if [[ ${AWG_RUNNING} -eq 0 ]]; then echo "AmneziaWG failed to uninstall properly." exit 1 else echo "AmneziaWG uninstalled successfully." exit 0 fi else echo "" echo "Removal aborted!" fi } function loadParams() { source "${PARAMS_FILE}" SERVER_AWG_CONF="${AMNEZIAWG_DIR}/${SERVER_AWG_NIC}.conf" } function manageMenu() { echo "AmneziaWG server installer (https://github.com/varckin/amneziawg-install)" echo "" echo "It looks like AmneziaWG is already installed." echo "" echo "What do you want to do?" echo " 1) Add a new user" echo " 2) List all users" echo " 3) Revoke existing user" echo " 4) Uninstall AmneziaWG" echo " 5) Exit" until [[ ${MENU_OPTION} =~ ^[1-5]$ ]]; do read -rp "Select an option [1-5]: " MENU_OPTION done case "${MENU_OPTION}" in 1) newClient ;; 2) listClients ;; 3) revokeClient ;; 4) uninstallAmneziaWG ;; 5) exit 0 ;; esac } # Check for root, virt, OS... initialCheck # Check if AmneziaWG is already installed and load params if [[ -e "${PARAMS_FILE}" ]]; then loadParams manageMenu else installAmneziaWG fi