
A lot of people don't know much about cryptography. Since the script already overwrite OpenVPN's default settings, there is no need for most people to modify them.
854 lines
26 KiB
Bash
854 lines
26 KiB
Bash
#!/bin/bash
|
||
|
||
# Secure OpenVPN server installer for Debian, Ubuntu, CentOS and Fedora
|
||
# https://github.com/angristan/openvpn-install
|
||
|
||
function isRoot () {
|
||
if [ "$EUID" -ne 0 ]; then
|
||
return 1
|
||
fi
|
||
}
|
||
|
||
function tunAvailable () {
|
||
if [ ! -e /dev/net/tun ]; then
|
||
return 1
|
||
fi
|
||
}
|
||
|
||
function checkOS () {
|
||
if [[ -e /etc/debian_version ]]; then
|
||
OS="debian"
|
||
# Getting the version number, to verify that a recent version of OpenVPN is available
|
||
source /etc/os-release
|
||
if [[ ! $VERSION_ID =~ (8|9|16.04|17.10|18.04) ]]; then
|
||
echo "⚠️ Your version of Debian/Ubuntu is not supported."
|
||
echo ""
|
||
echo "However, if you're using Debian unstable/testing, or Ubuntu beta, then you can continue."
|
||
echo "Keep in mind they are not supported, though."
|
||
echo ""
|
||
while [[ $CONTINUE != "y" && $CONTINUE != "n" ]]; do
|
||
read -rp "Continue? [y/n]: " -e CONTINUE
|
||
done
|
||
if [[ "$CONTINUE" = "n" ]]; then
|
||
echo "Ok, bye!"
|
||
exit 1
|
||
fi
|
||
fi
|
||
elif [[ -e /etc/fedora-release ]]; then
|
||
OS=fedora
|
||
elif [[ -e /etc/centos-release ]]; then
|
||
if ! grep -qs "^CentOS Linux release 7" /etc/centos-release; then
|
||
echo "Your version of CentOS is not supported."
|
||
echo "The script only support CentOS 7."
|
||
echo ""
|
||
unset CONTINUE
|
||
while [[ $CONTINUE != "y" && $CONTINUE != "n" ]]; do
|
||
read -rp "Continue anyway? [y/n]: " -e CONTINUE
|
||
done
|
||
if [[ "$CONTINUE" = "n" ]]; then
|
||
echo "Ok, bye!"
|
||
exit 1
|
||
fi
|
||
fi
|
||
OS=centos
|
||
else
|
||
echo "Looks like you aren't running this installer on a Debian, Ubuntu, Fedora or CentOS system"
|
||
exit 1
|
||
fi
|
||
}
|
||
|
||
function initialCheck () {
|
||
if ! isRoot; then
|
||
echo "Sorry, you need to run this as root"
|
||
exit 1
|
||
fi
|
||
if ! tunAvailable; then
|
||
echo "TUN is not available"
|
||
exit 1
|
||
fi
|
||
checkOS
|
||
}
|
||
|
||
function installUnbound () {
|
||
if [[ ! -e /etc/unbound/unbound.conf ]]; then
|
||
|
||
if [[ "$OS" = "debian" ]]; then
|
||
apt-get install -y unbound
|
||
|
||
# Configuration
|
||
echo 'interface: 10.8.0.1
|
||
access-control: 10.8.0.1/24 allow
|
||
hide-identity: yes
|
||
hide-version: yes
|
||
use-caps-for-id: yes
|
||
prefetch: yes' >> /etc/unbound/unbound.conf
|
||
|
||
elif [[ "$OS" = "centos" ]]; then
|
||
yum install -y unbound
|
||
|
||
# Configuration
|
||
sed -i 's|# interface: 0.0.0.0$|interface: 10.8.0.1|' /etc/unbound/unbound.conf
|
||
sed -i 's|# access-control: 127.0.0.0/8 allow|access-control: 10.8.0.1/24 allow|' /etc/unbound/unbound.conf
|
||
sed -i 's|# hide-identity: no|hide-identity: yes|' /etc/unbound/unbound.conf
|
||
sed -i 's|# hide-version: no|hide-version: yes|' /etc/unbound/unbound.conf
|
||
sed -i 's|use-caps-for-id: no|use-caps-for-id: yes|' /etc/unbound/unbound.conf
|
||
|
||
elif [[ "$OS" = "fedora" ]]; then
|
||
dnf install -y unbound
|
||
|
||
# Configuration
|
||
sed -i 's|# interface: 0.0.0.0$|interface: 10.8.0.1|' /etc/unbound/unbound.conf
|
||
sed -i 's|# access-control: 127.0.0.0/8 allow|access-control: 10.8.0.1/24 allow|' /etc/unbound/unbound.conf
|
||
sed -i 's|# hide-identity: no|hide-identity: yes|' /etc/unbound/unbound.conf
|
||
sed -i 's|# hide-version: no|hide-version: yes|' /etc/unbound/unbound.conf
|
||
sed -i 's|# use-caps-for-id: no|use-caps-for-id: yes|' /etc/unbound/unbound.conf
|
||
fi
|
||
|
||
if [[ ! "$OS" =~ (fedora|centos) ]];then
|
||
# DNS Rebinding fix
|
||
echo "private-address: 10.0.0.0/8
|
||
private-address: 172.16.0.0/12
|
||
private-address: 192.168.0.0/16
|
||
private-address: 169.254.0.0/16
|
||
private-address: fd00::/8
|
||
private-address: fe80::/10
|
||
private-address: 127.0.0.0/8
|
||
private-address: ::ffff:0:0/96" >> /etc/unbound/unbound.conf
|
||
fi
|
||
else # Unbound is already installed
|
||
echo 'include: /etc/unbound/openvpn.conf' >> /etc/unbound/unbound.conf
|
||
|
||
# Add Unbound 'server' for the OpenVPN subnet
|
||
echo 'server:
|
||
interface: 10.8.0.1
|
||
access-control: 10.8.0.1/24 allow
|
||
hide-identity: yes
|
||
hide-version: yes
|
||
use-caps-for-id: yes
|
||
prefetch: yes
|
||
private-address: 10.0.0.0/8
|
||
private-address: 172.16.0.0/12
|
||
private-address: 192.168.0.0/16
|
||
private-address: 169.254.0.0/16
|
||
private-address: fd00::/8
|
||
private-address: fe80::/10
|
||
private-address: 127.0.0.0/8
|
||
private-address: ::ffff:0:0/96' > /etc/unbound/openvpn.conf
|
||
fi
|
||
|
||
systemctl enable unbound
|
||
systemctl restart unbound
|
||
}
|
||
|
||
function installOpenVPN () {
|
||
echo "Welcome to the OpenVPN installer!"
|
||
echo "The git repository is available at: https://github.com/angristan/openvpn-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 ""
|
||
echo "I need to know the IPv4 address of the network interface you want OpenVPN listening to."
|
||
echo "If your server is running behind a NAT, (e.g. LowEndSpirit, Scaleway) leave the IP address as it is. (local/private IP)"
|
||
echo "Otherwise, it should be your public IPv4 address."
|
||
|
||
# Detect public IPv4 address and pre-fill for the user
|
||
IP=$(ip addr | grep 'inet' | grep -v inet6 | grep -vE '127\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}' | grep -oE '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}' | head -1)
|
||
read -rp "IP address: " -e -i $IP IP
|
||
# If $IP is a private IP address, the server must be behind NAT
|
||
if echo "$IP" | grep -qE '^(10\.|172\.1[6789]\.|172\.2[0-9]\.|172\.3[01]\.|192\.168)'; then
|
||
echo ""
|
||
echo "This server is behind NAT. What is the public IPv4 address or hostname?"
|
||
read -rp "Public IP address / hostname: " -e PUBLICIP
|
||
fi
|
||
|
||
echo ""
|
||
echo "Checking for IPv6 connectivity..."
|
||
ping6 -c4 ipv6.google.com > /dev/null 2>&1;
|
||
echo ""
|
||
if [[ $? == 0 ]]; then
|
||
echo "Your host appears to have IPv6 connectivity."
|
||
SUGGESTION="y"
|
||
else
|
||
echo "Your host does not appear to have IPv6 connectivity."
|
||
SUGGESTION="n"
|
||
fi
|
||
echo ""
|
||
# Ask the user if they want to enable IPv6 regardless its availability.
|
||
while [[ $IPV6_SUPPORT != "y" && $IPV6_SUPPORT != "n" ]]; do
|
||
read -rp "Do you want to enable IPv6 support (NAT)? [y/n]: " -e -i $SUGGESTION IPV6_SUPPORT
|
||
done
|
||
echo ""
|
||
echo "What port do you want OpenVPN to listen to?"
|
||
echo " 1) Default: 1194"
|
||
echo " 2) Custom"
|
||
echo " 3) Random [49152-65535]"
|
||
until [[ "$PORT_CHOICE" =~ ^[1-3]$ ]]; do
|
||
read -p "Port choice [1-3]: " -e -i 1 PORT_CHOICE
|
||
done
|
||
case $PORT_CHOICE in
|
||
1)
|
||
PORT="1194"
|
||
;;
|
||
2)
|
||
until [[ "$PORT" =~ ^[0-9]+$ ]] && [ "$PORT" -ge 1 -a "$PORT" -le 65535 ]; do
|
||
read -p "Custom port [1-65535]: " -e -i 1194 PORT
|
||
done
|
||
;;
|
||
3)
|
||
# Generate random number within private ports range
|
||
PORT=$(shuf -i49152-65535 -n1)
|
||
echo "Random Port: $PORT"
|
||
;;
|
||
esac
|
||
echo ""
|
||
echo "What protocol do you want OpenVPN to use?"
|
||
echo "UDP is faster. Unless it is not available, you shoudn't use TCP."
|
||
echo " 1) UDP"
|
||
echo " 2) TCP"
|
||
until [[ "$PROTOCOL_CHOICE" =~ ^[1-2] ]]; do
|
||
read -rp "Protocol [1-2]: " -e -i 1 PROTOCOL_CHOICE
|
||
done
|
||
case $PROTOCOL_CHOICE in
|
||
1)
|
||
PROTOCOL="udp"
|
||
;;
|
||
2)
|
||
PROTOCOL="tcp"
|
||
;;
|
||
esac
|
||
echo ""
|
||
echo "What DNS resolvers do you want to use with the VPN?"
|
||
echo " 1) Current system resolvers (from /etc/resolv.conf)"
|
||
echo " 2) Self-hosted DNS Resolver (Unbound)"
|
||
echo " 3) Cloudflare (Anycast: worldwide)"
|
||
echo " 4) Quad9 (Anycast: worldwide)"
|
||
echo " 5) FDN (France)"
|
||
echo " 6) DNS.WATCH (Germany)"
|
||
echo " 7) OpenDNS (Anycast: worldwide)"
|
||
echo " 8) Google (Anycast: worldwide)"
|
||
echo " 9) Yandex Basic (Russia)"
|
||
echo " 10) AdGuard DNS (Russia)"
|
||
until [[ "$DNS" =~ ^[0-9]+$ ]] && [ "$DNS" -ge 1 -a "$DNS" -le 10 ]; do
|
||
read -rp "DNS [1-10]: " -e -i 3 DNS
|
||
if [[ $DNS == 2 ]] && [[ -e /etc/unbound/unbound.conf ]]; then
|
||
echo ""
|
||
echo "Unbound is already installed."
|
||
echo "You can allow the script to configure it in order to use it from your OpenVPN clients"
|
||
echo "We will simply add a second server to /etc/unbound/unbound.conf for the OpenVPN subnet."
|
||
echo "No changes are made to the current configuration."
|
||
echo ""
|
||
|
||
while [[ $CONTINUE != "y" && $CONTINUE != "n" ]]; do
|
||
read -rp "Apply configuration changes to Unbound? [y/n]: " -e CONTINUE
|
||
done
|
||
if [[ $CONTINUE = "n" ]];then
|
||
# Break the loop and cleanup
|
||
unset DNS
|
||
unset CONTINUE
|
||
fi
|
||
fi
|
||
done
|
||
echo ""
|
||
echo "Do you want to customize encryption settings?"
|
||
echo "Unless you know what you're doing, you should stick with the default parameters provided by the script."
|
||
echo "Note that whatever you choose, all the choices presented in the script are safe. (Unlike OpenVPN's defaults)"
|
||
echo "See https://github.com/angristan/openvpn-install#encryption to learn more."
|
||
echo ""
|
||
until [[ $CUSTOMIZE_ENC =~ (y|n) ]]; do
|
||
read -rp "Customize encryption settings? [y/n]: " -e -i n CUSTOMIZE_ENC
|
||
done
|
||
if [[ $CUSTOMIZE_ENC == "n" ]];then
|
||
# Use default, sane and fast paramters
|
||
CIPHER="cipher AES-128-CBC"
|
||
DH_KEY_SIZE="2048"
|
||
RSA_KEY_SIZE="2048"
|
||
else
|
||
echo ""
|
||
echo "Choose which cipher you want to use for the data channel:"
|
||
echo " 1) AES-128-CBC (recommended)"
|
||
echo " 2) AES-192-CBC"
|
||
echo " 3) AES-256-CBC"
|
||
until [[ "$CIPHER_CHOICE" =~ ^[0-9]+$ ]] && [ "$CIPHER_CHOICE" -ge 1 -a "$CIPHER_CHOICE" -le 3 ]; do
|
||
read -rp "Cipher [1-7]: " -e -i 1 CIPHER_CHOICE
|
||
done
|
||
case $CIPHER_CHOICE in
|
||
1)
|
||
CIPHER="cipher AES-128-CBC"
|
||
;;
|
||
2)
|
||
CIPHER="cipher AES-192-CBC"
|
||
;;
|
||
3)
|
||
CIPHER="cipher AES-256-CBC"
|
||
;;
|
||
esac
|
||
echo ""
|
||
echo "Choose what size of Diffie-Hellman key you want to use:"
|
||
echo " 1) 2048 bits (fastest)"
|
||
echo " 2) 3072 bits (recommended, best compromise)"
|
||
echo " 3) 4096 bits (most secure)"
|
||
until [[ "$DH_KEY_SIZE_CHOICE" =~ ^[0-9]+$ ]] && [ "$DH_KEY_SIZE_CHOICE" -ge 1 -a "$DH_KEY_SIZE_CHOICE" -le 3 ]; do
|
||
read -rp "DH key size [1-3]: " -e -i 2 DH_KEY_SIZE_CHOICE
|
||
done
|
||
case $DH_KEY_SIZE_CHOICE in
|
||
1)
|
||
DH_KEY_SIZE="2048"
|
||
;;
|
||
2)
|
||
DH_KEY_SIZE="3072"
|
||
;;
|
||
3)
|
||
DH_KEY_SIZE="4096"
|
||
;;
|
||
esac
|
||
echo ""
|
||
echo "Choose what size of RSA key you want to use for the certificate:"
|
||
echo " 1) 2048 bits (fastest)"
|
||
echo " 2) 3072 bits (recommended, best compromise)"
|
||
echo " 3) 4096 bits (most secure)"
|
||
until [[ "$RSA_KEY_SIZE_CHOICE" =~ ^[0-9]+$ ]] && [ "$RSA_KEY_SIZE_CHOICE" -ge 1 -a "$RSA_KEY_SIZE_CHOICE" -le 3 ]; do
|
||
read -rp "RSA key size [1-3]: " -e -i 2 RSA_KEY_SIZE_CHOICE
|
||
done
|
||
case $RSA_KEY_SIZE_CHOICE in
|
||
1)
|
||
RSA_KEY_SIZE="2048"
|
||
;;
|
||
2)
|
||
RSA_KEY_SIZE="3072"
|
||
;;
|
||
3)
|
||
RSA_KEY_SIZE="4096"
|
||
;;
|
||
esac
|
||
fi
|
||
echo ""
|
||
echo "Okay, that was all I needed. We are ready to setup your OpenVPN server now."
|
||
echo "You will be able to generate a client at the end of the installtion."
|
||
read -n1 -r -p "Press any key to continue..."
|
||
|
||
# Get the "public" interface from the default route
|
||
NIC=$(ip -4 route ls | grep default | grep -Po '(?<=dev )(\S+)' | head -1)
|
||
|
||
if [[ "$OS" = 'debian' ]]; then
|
||
apt-get update
|
||
apt-get install ca-certificates gnupg -y
|
||
# We add the OpenVPN repo to get the latest version.
|
||
if [[ "$VERSION_ID" = 'VERSION_ID="8"' ]]; then
|
||
echo "deb http://build.openvpn.net/debian/openvpn/stable jessie main" > /etc/apt/sources.list.d/openvpn.list
|
||
wget -O - https://swupdate.openvpn.net/repos/repo-public.gpg | apt-key add -
|
||
apt-get update
|
||
fi
|
||
# Ubuntu >= 16.04 and Debian > 8 have OpenVPN > 2.3.3 without the need of a third party repository.
|
||
apt-get install openvpn iptables openssl wget ca-certificates curl -y
|
||
elif [[ "$OS" = 'centos' ]]; then
|
||
yum install epel-release openvpn iptables openssl wget ca-certificates curl -y
|
||
elif [[ "$OS" = 'fedora' ]]; then
|
||
dnf install openvpn iptables openssl wget ca-certificates curl -y
|
||
fi
|
||
|
||
# Find out if the machine uses nogroup or nobody for the permissionless group
|
||
if grep -qs "^nogroup:" /etc/group; then
|
||
NOGROUP=nogroup
|
||
else
|
||
NOGROUP=nobody
|
||
fi
|
||
|
||
# An old version of easy-rsa was available by default in some openvpn packages
|
||
if [[ -d /etc/openvpn/easy-rsa/ ]]; then
|
||
rm -rf /etc/openvpn/easy-rsa/
|
||
fi
|
||
|
||
# Install the latest version of easy-rsa from source
|
||
local version="3.0.4"
|
||
wget -O ~/EasyRSA-${version}.tgz https://github.com/OpenVPN/easy-rsa/releases/download/v${version}/EasyRSA-${version}.tgz
|
||
tar xzf ~/EasyRSA-${version}.tgz -C ~/
|
||
mv ~/EasyRSA-${version}/ /etc/openvpn/
|
||
mv /etc/openvpn/EasyRSA-${version}/ /etc/openvpn/easy-rsa/
|
||
chown -R root:root /etc/openvpn/easy-rsa/
|
||
rm -f ~/EasyRSA-${version}.tgz
|
||
|
||
cd /etc/openvpn/easy-rsa/
|
||
# Generate a random, alphanumeric identifier of 16 characters for CN and one for server name
|
||
SERVER_CN="cn_$(head /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 16 | head -n 1)"
|
||
SERVER_NAME="server_$(head /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 16 | head -n 1)"
|
||
echo "set_var EASYRSA_KEY_SIZE $RSA_KEY_SIZE" > vars
|
||
echo "set_var EASYRSA_REQ_CN $SERVER_CN" >> vars
|
||
# Create the PKI, set up the CA, the DH params and the server certificate
|
||
./easyrsa init-pki
|
||
./easyrsa --batch build-ca nopass
|
||
openssl dhparam -out dh.pem $DH_KEY_SIZE
|
||
./easyrsa build-server-full $SERVER_NAME nopass
|
||
EASYRSA_CRL_DAYS=3650 ./easyrsa gen-crl
|
||
# Generate tls-auth key
|
||
openvpn --genkey --secret /etc/openvpn/tls-auth.key
|
||
# Move all the generated files
|
||
cp pki/ca.crt pki/private/ca.key dh.pem pki/issued/$SERVER_NAME.crt pki/private/$SERVER_NAME.key /etc/openvpn/easy-rsa/pki/crl.pem /etc/openvpn
|
||
# Make cert revocation list readable for non-root
|
||
chmod 644 /etc/openvpn/crl.pem
|
||
|
||
# Generate server.conf
|
||
echo "port $PORT" > /etc/openvpn/server.conf
|
||
if [[ "$IPV6_SUPPORT" = 'n' ]]; then
|
||
echo "proto $PROTOCOL" >> /etc/openvpn/server.conf
|
||
elif [[ "$IPV6_SUPPORT" = 'y' ]]; then
|
||
echo "proto ${PROTOCOL}6" >> /etc/openvpn/server.conf
|
||
fi
|
||
|
||
echo "dev tun
|
||
user nobody
|
||
group $NOGROUP
|
||
persist-key
|
||
persist-tun
|
||
keepalive 10 120
|
||
topology subnet
|
||
server 10.8.0.0 255.255.255.0
|
||
ifconfig-pool-persist ipp.txt" >> /etc/openvpn/server.conf
|
||
|
||
# DNS resolvers
|
||
case $DNS in
|
||
1)
|
||
# Locate the proper resolv.conf
|
||
# Needed for systems running systemd-resolved
|
||
if grep -q "127.0.0.53" "/etc/resolv.conf"; then
|
||
RESOLVCONF='/run/systemd/resolve/resolv.conf'
|
||
else
|
||
RESOLVCONF='/etc/resolv.conf'
|
||
fi
|
||
# Obtain the resolvers from resolv.conf and use them for OpenVPN
|
||
grep -v '#' $RESOLVCONF | grep 'nameserver' | grep -E -o '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}' | while read -r line; do
|
||
echo "push \"dhcp-option DNS $line\"" >> /etc/openvpn/server.conf
|
||
done
|
||
;;
|
||
2)
|
||
echo 'push "dhcp-option DNS 10.8.0.1"' >> /etc/openvpn/server.conf
|
||
;;
|
||
3) # Cloudflare
|
||
echo 'push "dhcp-option DNS 1.0.0.1"' >> /etc/openvpn/server.conf
|
||
echo 'push "dhcp-option DNS 1.1.1.1"' >> /etc/openvpn/server.conf
|
||
;;
|
||
4) # Quad9
|
||
echo 'push "dhcp-option DNS 9.9.9.9"' >> /etc/openvpn/server.conf
|
||
echo 'push "dhcp-option DNS 149.112.112.112"' >> /etc/openvpn/server.conf
|
||
;;
|
||
5) # FDN
|
||
echo 'push "dhcp-option DNS 80.67.169.40"' >> /etc/openvpn/server.conf
|
||
echo 'push "dhcp-option DNS 80.67.169.12"' >> /etc/openvpn/server.conf
|
||
;;
|
||
6) # DNS.WATCH
|
||
echo 'push "dhcp-option DNS 84.200.69.80"' >> /etc/openvpn/server.conf
|
||
echo 'push "dhcp-option DNS 84.200.70.40"' >> /etc/openvpn/server.conf
|
||
;;
|
||
7) # OpenDNS
|
||
echo 'push "dhcp-option DNS 208.67.222.222"' >> /etc/openvpn/server.conf
|
||
echo 'push "dhcp-option DNS 208.67.220.220"' >> /etc/openvpn/server.conf
|
||
;;
|
||
8) # Google
|
||
echo 'push "dhcp-option DNS 8.8.8.8"' >> /etc/openvpn/server.conf
|
||
echo 'push "dhcp-option DNS 8.8.4.4"' >> /etc/openvpn/server.conf
|
||
;;
|
||
9) # Yandex Basic
|
||
echo 'push "dhcp-option DNS 77.88.8.8"' >> /etc/openvpn/server.conf
|
||
echo 'push "dhcp-option DNS 77.88.8.1"' >> /etc/openvpn/server.conf
|
||
;;
|
||
10) # AdGuard DNS
|
||
echo 'push "dhcp-option DNS 176.103.130.130"' >> /etc/openvpn/server.conf
|
||
echo 'push "dhcp-option DNS 176.103.130.131"' >> /etc/openvpn/server.conf
|
||
;;
|
||
esac
|
||
echo 'push "redirect-gateway def1 bypass-dhcp" '>> /etc/openvpn/server.conf
|
||
|
||
# IPv6 network settings if needed
|
||
if [[ "$IPV6_SUPPORT" = 'y' ]]; then
|
||
echo 'server-ipv6 fd42:42:42:42::/112
|
||
tun-ipv6
|
||
push tun-ipv6
|
||
push "route-ipv6 2000::/3"
|
||
push "redirect-gateway ipv6"' >> /etc/openvpn/server.conf
|
||
fi
|
||
|
||
echo "crl-verify crl.pem
|
||
ca ca.crt
|
||
cert $SERVER_NAME.crt
|
||
key $SERVER_NAME.key
|
||
tls-auth tls-auth.key 0
|
||
dh dh.pem
|
||
auth SHA256
|
||
$CIPHER
|
||
tls-server
|
||
tls-version-min 1.2
|
||
tls-cipher TLS-DHE-RSA-WITH-AES-128-GCM-SHA256
|
||
status /var/log/openvpn/status.log
|
||
verb 3" >> /etc/openvpn/server.conf
|
||
|
||
# Create log dir
|
||
mkdir -p /var/log/openvpn
|
||
|
||
# Enable routing
|
||
echo 'net.ipv4.ip_forward=1' >> /etc/sysctl.d/20-openvpn.conf
|
||
if [[ "$IPV6_SUPPORT" = 'y' ]]; then
|
||
echo 'net.ipv6.conf.all.forwarding=1' >> /etc/sysctl.d/20-openvpn.conf
|
||
fi
|
||
# Avoid an unneeded reboot
|
||
sysctl --system
|
||
|
||
# If SELinux is enabled and a custom port was selected, we need this
|
||
if hash sestatus 2>/dev/null; then
|
||
if sestatus | grep "Current mode" | grep -qs "enforcing"; then
|
||
if [[ "$PORT" != '1194' ]]; then
|
||
semanage port -a -t openvpn_port_t -p $PROTOCOL $PORT
|
||
fi
|
||
fi
|
||
fi
|
||
|
||
# Finally, restart and enable OpenVPN
|
||
if [[ "$OS" = 'fedora' ]]; then
|
||
# Workaround to fix OpenVPN service on OpenVZ
|
||
sed -i 's|LimitNPROC|#LimitNPROC|' /usr/lib/systemd/system/openvpn-server@.service
|
||
# Another workaround to keep using /etc/openvpn/
|
||
sed -i 's|/etc/openvpn/server|/etc/openvpn|' /usr/lib/systemd/system/openvpn-server@.service
|
||
systemctl daemon-reload
|
||
systemctl restart openvpn-server@server
|
||
systemctl enable openvpn-server@server
|
||
else
|
||
# Workaround to fix OpenVPN service on OpenVZ
|
||
sed -i 's|LimitNPROC|#LimitNPROC|' /lib/systemd/system/openvpn\@.service
|
||
# Another workaround to keep using /etc/openvpn/
|
||
sed -i 's|/etc/openvpn/server|/etc/openvpn|' /lib/systemd/system/openvpn\@.service
|
||
systemctl daemon-reload
|
||
systemctl restart openvpn@server
|
||
systemctl enable openvpn@server
|
||
fi
|
||
|
||
if [[ $DNS == 2 ]];then
|
||
installUnbound
|
||
fi
|
||
|
||
# Add iptables rules in two scripts
|
||
mkdir /etc/iptables
|
||
|
||
# Script to add rules
|
||
echo "#!/bin/sh
|
||
iptables -t nat -A POSTROUTING -s 10.8.0.0/24 -o $NIC -j MASQUERADE
|
||
iptables -A INPUT -i tun0 -j ACCEPT
|
||
iptables -A FORWARD -i $NIC -o tun0 -j ACCEPT
|
||
iptables -A FORWARD -i tun0 -o $NIC -j ACCEPT
|
||
iptables -A INPUT -i $NIC -p $PROTOCOL --dport $PORT -j ACCEPT" > /etc/iptables/add-openvpn-rules.sh
|
||
|
||
if [[ "$IPV6_SUPPORT" = 'y' ]]; then
|
||
echo "ip6tables -t nat -A POSTROUTING -s fd42:42:42:42::/112 -o $NIC -j MASQUERADE
|
||
ip6tables -A INPUT -i tun0 -j ACCEPT
|
||
ip6tables -A FORWARD -i $NIC -o tun0 -j ACCEPT
|
||
ip6tables -A FORWARD -i tun0 -o $NIC -j ACCEPT" >> /etc/iptables/add-openvpn-rules.sh
|
||
fi
|
||
|
||
# Script to remove rules
|
||
echo "#!/bin/sh
|
||
iptables -t nat -D POSTROUTING -s 10.8.0.0/24 -o $NIC -j MASQUERADE
|
||
iptables -D INPUT -i tun0 -j ACCEPT
|
||
iptables -D FORWARD -i $NIC -o tun0 -j ACCEPT
|
||
iptables -D FORWARD -i tun0 -o $NIC -j ACCEPT
|
||
iptables -D INPUT -i $NIC -p $PROTOCOL --dport $PORT -j ACCEPT" > /etc/iptables/rm-openvpn-rules.sh
|
||
|
||
if [[ "$IPV6_SUPPORT" = 'y' ]]; then
|
||
echo "ip6tables -t nat -D POSTROUTING -s fd42:42:42:42::/112 -o $NIC -j MASQUERADE
|
||
ip6tables -D INPUT -i tun0 -j ACCEPT
|
||
ip6tables -D FORWARD -i $NIC -o tun0 -j ACCEPT
|
||
ip6tables -D FORWARD -i tun0 -o $NIC -j ACCEPT" >> /etc/iptables/rm-openvpn-rules.sh
|
||
fi
|
||
|
||
chmod +x /etc/iptables/add-openvpn-rules.sh
|
||
chmod +x /etc/iptables/rm-openvpn-rules.sh
|
||
|
||
# Handle the rules via a systemd script
|
||
echo "[Unit]
|
||
Description=iptables rules for OpenVPN
|
||
Before=network-pre.target
|
||
Wants=network-pre.target
|
||
|
||
[Service]
|
||
Type=oneshot
|
||
ExecStart=/etc/iptables/add-openvpn-rules.sh
|
||
ExecStop=/etc/iptables/rm-openvpn-rules.sh
|
||
RemainAfterExit=yes
|
||
|
||
[Install]
|
||
WantedBy=multi-user.target" > /etc/systemd/system/iptables-openvpn.service
|
||
|
||
# Enable service and apply rules
|
||
systemctl daemon-reload
|
||
systemctl enable iptables-openvpn
|
||
systemctl start iptables-openvpn
|
||
|
||
# If the server is behind a NAT, use the correct IP address for the clients to connect to
|
||
if [[ "$PUBLICIP" != "" ]]; then
|
||
IP=$PUBLICIP
|
||
fi
|
||
|
||
# client-template.txt is created so we have a template to add further users later
|
||
echo "client" > /etc/openvpn/client-template.txt
|
||
if [[ "$PROTOCOL" = 'udp' ]]; then
|
||
echo "proto udp" >> /etc/openvpn/client-template.txt
|
||
elif [[ "$PROTOCOL" = 'tcp' ]]; then
|
||
echo "proto tcp-client" >> /etc/openvpn/client-template.txt
|
||
fi
|
||
echo "remote $IP $PORT
|
||
dev tun
|
||
resolv-retry infinite
|
||
nobind
|
||
persist-key
|
||
persist-tun
|
||
remote-cert-tls server
|
||
verify-x509-name $SERVER_NAME name
|
||
auth SHA256
|
||
auth-nocache
|
||
$CIPHER
|
||
tls-client
|
||
tls-version-min 1.2
|
||
tls-cipher TLS-DHE-RSA-WITH-AES-128-GCM-SHA256
|
||
setenv opt block-outside-dns # Prevent Windows 10 DNS leak
|
||
verb 3" >> /etc/openvpn/client-template.txt
|
||
|
||
# Generate the custom client.ovpn
|
||
newClient
|
||
echo "If you want to add more clients, you simply need to run this script another time!"
|
||
}
|
||
|
||
function newClient () {
|
||
echo ""
|
||
echo "Tell me a name for the client."
|
||
echo "Use one word only, no special characters."
|
||
|
||
until [[ "$CLIENT" =~ ^[a-zA-Z0-9_]+$ ]]; do
|
||
read -rp "Client name: " -e CLIENT
|
||
done
|
||
|
||
echo ""
|
||
echo "Do you want to protect the configuration file with a password?"
|
||
echo "(e.g. encrypt the private key with a password)"
|
||
echo " 1) Add a passwordless client"
|
||
echo " 2) Use a password for the client"
|
||
|
||
until [[ "$PASS" =~ ^[1-2]$ ]]; do
|
||
read -rp "Select an option [1-2]: " -e -i 1 PASS
|
||
done
|
||
|
||
cd /etc/openvpn/easy-rsa/ || return
|
||
case $PASS in
|
||
1)
|
||
./easyrsa build-client-full $CLIENT nopass
|
||
;;
|
||
2)
|
||
echo "⚠️ You will be asked for the client password below ⚠️"
|
||
./easyrsa build-client-full $CLIENT
|
||
;;
|
||
esac
|
||
|
||
# Home directory of the user, where the client configuration (.ovpn) will be written
|
||
if [ -e "/home/$CLIENT" ]; then # if $1 is a user name
|
||
homeDir="/home/$CLIENT"
|
||
elif [ "${SUDO_USER}" ]; then # if not, use SUDO_USER
|
||
homeDir="/home/${SUDO_USER}"
|
||
else # if not SUDO_USER, use /root
|
||
homeDir="/root"
|
||
fi
|
||
|
||
# Generates the custom client.ovpn
|
||
cp /etc/openvpn/client-template.txt "$homeDir/$CLIENT.ovpn"
|
||
{
|
||
echo "<ca>"
|
||
cat "/etc/openvpn/easy-rsa/pki/ca.crt"
|
||
echo "</ca>"
|
||
|
||
echo "<cert>"
|
||
cat "/etc/openvpn/easy-rsa/pki/issued/$CLIENT.crt"
|
||
echo "</cert>"
|
||
|
||
echo "<key>"
|
||
cat "/etc/openvpn/easy-rsa/pki/private/$CLIENT.key"
|
||
echo "</key>"
|
||
echo "key-direction 1"
|
||
|
||
echo "<tls-auth>"
|
||
cat "/etc/openvpn/tls-auth.key"
|
||
echo "</tls-auth>"
|
||
} >> "$homeDir/$CLIENT.ovpn"
|
||
|
||
echo ""
|
||
echo "Client $CLIENT added, the configuration file is available at $homeDir/$CLIENT.ovpn."
|
||
echo "Download the .ovpn file and import it in your OpenVPN client."
|
||
}
|
||
|
||
function revokeClient () {
|
||
NUMBEROFCLIENTS=$(tail -n +2 /etc/openvpn/easy-rsa/pki/index.txt | grep -c "^V")
|
||
if [[ "$NUMBEROFCLIENTS" = '0' ]]; then
|
||
echo ""
|
||
echo "You have no existing clients!"
|
||
exit 1
|
||
fi
|
||
|
||
echo ""
|
||
echo "Select the existing client certificate you want to revoke"
|
||
tail -n +2 /etc/openvpn/easy-rsa/pki/index.txt | grep "^V" | cut -d '=' -f 2 | nl -s ') '
|
||
if [[ "$NUMBEROFCLIENTS" = '1' ]]; then
|
||
read -rp "Select one client [1]: " CLIENTNUMBER
|
||
else
|
||
read -rp "Select one client [1-$NUMBEROFCLIENTS]: " CLIENTNUMBER
|
||
fi
|
||
|
||
CLIENT=$(tail -n +2 /etc/openvpn/easy-rsa/pki/index.txt | grep "^V" | cut -d '=' -f 2 | sed -n "$CLIENTNUMBER"p)
|
||
cd /etc/openvpn/easy-rsa/
|
||
./easyrsa --batch revoke $CLIENT
|
||
EASYRSA_CRL_DAYS=3650 ./easyrsa gen-crl
|
||
# Cleanup
|
||
rm -f pki/reqs/$CLIENT.req
|
||
rm -f pki/private/$CLIENT.key
|
||
rm -f pki/issued/$CLIENT.crt
|
||
rm -f /etc/openvpn/crl.pem
|
||
cp /etc/openvpn/easy-rsa/pki/crl.pem /etc/openvpn/crl.pem
|
||
chmod 644 /etc/openvpn/crl.pem
|
||
rm -f $(find /home -maxdepth 2 | grep $CLIENT.ovpn) 2>/dev/null
|
||
rm -f /root/$CLIENT.ovpn 2>/dev/null
|
||
|
||
echo ""
|
||
echo "Certificate for client $CLIENT revoked."
|
||
}
|
||
|
||
function removeUnbound () {
|
||
# Remove OpenVPN-related config
|
||
sed -i 's|include: \/etc\/unbound\/openvpn.conf||' /etc/unbound/unbound.conf
|
||
rm /etc/unbound/openvpn.conf
|
||
systemctl restart unbound
|
||
|
||
until [[ $REMOVE_UNBOUND == "y" || $REMOVE_UNBOUND == "n" ]]; do
|
||
echo ""
|
||
echo "If you were already using Unbound before installing OpenVPN, I removed the configuration related to OpenVPN."
|
||
read -rp "Do you want to completely remove Unbound? [y/n]: " -e REMOVE_UNBOUND
|
||
done
|
||
|
||
if [[ "$REMOVE_UNBOUND" = 'y' ]]; then
|
||
# Stop Unbound
|
||
systemctl stop unbound
|
||
|
||
if [[ "$OS" = 'debian' ]]; then
|
||
apt-get autoremove --purge -y unbound
|
||
elif [[ "$OS" = 'centos' ]]; then
|
||
yum remove unbound -y
|
||
elif [[ "$OS" = 'fedora' ]]; then
|
||
dnf remove unbound -y
|
||
fi
|
||
|
||
rm -rf /etc/unbound/
|
||
|
||
echo ""
|
||
echo "Unbound removed!"
|
||
else
|
||
echo ""
|
||
echo "Unbound wasn't removed."
|
||
fi
|
||
}
|
||
|
||
function removeOpenVPN () {
|
||
echo ""
|
||
read -rp "Do you really want to remove OpenVPN? [y/n]: " -e -i n REMOVE
|
||
if [[ "$REMOVE" = 'y' ]]; then
|
||
# Get OpenVPN port from the configuration
|
||
PORT=$(grep '^port ' /etc/openvpn/server.conf | cut -d " " -f 2)
|
||
|
||
# Stop OpenVPN
|
||
if [[ "$OS" = 'fedora' ]]; then
|
||
systemctl stop openvpn-server@server
|
||
else
|
||
systemctl stop openvpn@server
|
||
fi
|
||
|
||
# Remove the iptables rules related to the script
|
||
systemctl stop iptables-openvpn
|
||
# Cleanup
|
||
systemctl disable iptables-openvpn
|
||
rm /etc/systemd/system/iptables-openvpn.service
|
||
systemctl daemon-reload
|
||
rm /etc/iptables/add-openvpn-rules.sh
|
||
rm /etc/iptables/rm-openvpn-rules.sh
|
||
|
||
# SELinux
|
||
if hash sestatus 2>/dev/null; then
|
||
if sestatus | grep "Current mode" | grep -qs "enforcing"; then
|
||
if [[ "$PORT" != '1194' ]]; then
|
||
semanage port -d -t openvpn_port_t -p udp $PORT
|
||
fi
|
||
fi
|
||
fi
|
||
|
||
if [[ "$OS" = 'debian' ]]; then
|
||
apt-get autoremove --purge -y openvpn
|
||
elif [[ "$OS" = 'centos' ]]; then
|
||
yum remove openvpn -y
|
||
elif [[ "$OS" = 'fedora' ]]; then
|
||
dnf remove openvpn -y
|
||
fi
|
||
|
||
# Cleanup
|
||
OVPNS=$(ls /etc/openvpn/easy-rsa/pki/issued | awk -F "." {'print $1'})
|
||
for i in $OVPNS;do
|
||
rm $(find /home -maxdepth 2 | grep $i.ovpn) 2>/dev/null
|
||
rm /root/$i.ovpn 2>/dev/null
|
||
done
|
||
rm -rf /etc/openvpn
|
||
rm -rf /usr/share/doc/openvpn*
|
||
rm -f /etc/sysctl.d/20-openvpn.conf
|
||
|
||
# Unbound
|
||
if [[ -e /etc/unbound/openvpn.conf ]]; then
|
||
removeUnbound
|
||
fi
|
||
echo ""
|
||
echo "OpenVPN removed!"
|
||
else
|
||
echo ""
|
||
echo "Removal aborted!"
|
||
fi
|
||
}
|
||
|
||
function manageMenu () {
|
||
clear
|
||
echo "Welcome to OpenVPN-install!"
|
||
echo "The git repository is available at: https://github.com/angristan/openvpn-install"
|
||
echo ""
|
||
echo "It looks like OpenVPN is already installed."
|
||
echo ""
|
||
echo "What do you want to do?"
|
||
echo " 1) Add a new user"
|
||
echo " 2) Revoke existing user"
|
||
echo " 3) Remove OpenVPN"
|
||
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)
|
||
removeOpenVPN
|
||
;;
|
||
4)
|
||
exit 0
|
||
;;
|
||
esac
|
||
}
|
||
|
||
# Check for root, TUN, OS...
|
||
initialCheck
|
||
|
||
# Check if OpenVPN is already installed
|
||
if [[ -e /etc/openvpn/server.conf ]]; then
|
||
manageMenu
|
||
else
|
||
installOpenVPN
|
||
fi
|