This commit is contained in:
simono41 2017-09-26 22:27:59 +02:00
parent 2446f6e84d
commit 31d3a872cf

View file

@ -1,88 +1,114 @@
#!/bin/bash #!/bin/bash
# OpenVPN road warrior installer for Debian, Ubuntu and CentOS
# This script will work on Debian, Ubuntu, CentOS and probably other distros # Secure OpenVPN server installer for Debian, Ubuntu, CentOS and Arch Linux
# of the same families, although no support is offered for them. It isn't # https://github.com/Angristan/OpenVPN-install
# bulletproof but it will probably work if you simply want to setup a VPN on
# your Debian/Ubuntu/CentOS box. It has been designed to be as unobtrusive and
# universal as possible.
# Detect Debian users running the script with "sh" instead of bash
if readlink /proc/$$/exe | grep -qs "dash"; then
echo "This script needs to be run with bash, not sh"
exit 1
fi
if [[ "$EUID" -ne 0 ]]; then if [[ "$EUID" -ne 0 ]]; then
echo "Sorry, you need to run this as root" echo "Sorry, you need to run this as root"
exit 2 exit 1
fi fi
if [[ ! -e /dev/net/tun ]]; then if [[ ! -e /dev/net/tun ]]; then
echo "The TUN device is not available echo "TUN is not available"
You need to enable TUN before running this script" exit 2
exit 3
fi fi
if grep -qs "CentOS release 5" "/etc/redhat-release"; then if grep -qs "CentOS release 5" "/etc/redhat-release"; then
echo "CentOS 5 is too old and not supported" echo "CentOS 5 is too old and not supported"
exit 4 exit 3
fi fi
if [[ -e /etc/debian_version ]]; then if [[ -e /etc/debian_version ]]; then
OS=debian OS="debian"
GROUPNAME=nogroup # Getting the version number, to verify that a recent version of OpenVPN is available
VERSION_ID=$(cat /etc/os-release | grep "VERSION_ID")
RCLOCAL='/etc/rc.local' RCLOCAL='/etc/rc.local'
SYSCTL='/etc/sysctl.conf'
if [[ "$VERSION_ID" != 'VERSION_ID="7"' ]] && [[ "$VERSION_ID" != 'VERSION_ID="8"' ]] && [[ "$VERSION_ID" != 'VERSION_ID="9"' ]] && [[ "$VERSION_ID" != 'VERSION_ID="12.04"' ]] && [[ "$VERSION_ID" != 'VERSION_ID="14.04"' ]] && [[ "$VERSION_ID" != 'VERSION_ID="16.04"' ]] && [[ "$VERSION_ID" != 'VERSION_ID="16.10"' ]] && [[ "$VERSION_ID" != 'VERSION_ID="17.04"' ]]; then
echo "Your version of Debian/Ubuntu is not supported."
echo "I can't install a recent version of OpenVPN on your system."
echo ""
echo "However, if you're using Debian unstable/testing, or Ubuntu beta,"
echo "then you can continue, a recent version of OpenVPN is available on these."
echo "Keep in mind they are not supported, though."
while [[ $CONTINUE != "y" && $CONTINUE != "n" ]]; do
read -p "Continue ? [y/n]: " -e CONTINUE
done
if [[ "$CONTINUE" = "n" ]]; then
echo "Ok, bye !"
exit 4
fi
fi
elif [[ -e /etc/centos-release || -e /etc/redhat-release ]]; then elif [[ -e /etc/centos-release || -e /etc/redhat-release ]]; then
OS=centos OS=centos
GROUPNAME=nobody
RCLOCAL='/etc/rc.d/rc.local' RCLOCAL='/etc/rc.d/rc.local'
SYSCTL='/etc/sysctl.conf'
# Needed for CentOS 7
chmod +x /etc/rc.d/rc.local
elif [[ -e /etc/arch-release ]]; then
OS=arch
RCLOCAL='/etc/rc.local'
SYSCTL='/etc/sysctl.d/openvpn.conf'
else else
echo "Looks like you aren't running this installer on Debian, Ubuntu or CentOS" echo "Looks like you aren't running this installer on a Debian, Ubuntu, CentOS or ArchLinux system"
exit 5 exit 4
fi fi
newclient () { newclient () {
# Where to write the custom client.ovpn?
if [ -e /home/$1 ]; then # if $1 is a user name
homeDir="/home/$1"
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 # Generates the custom client.ovpn
cp /etc/openvpn/client-common.txt ~/$1.ovpn cp /etc/openvpn/client-template.txt $homeDir/$1.ovpn
echo "<ca>" >> ~/$1.ovpn echo "<ca>" >> $homeDir/$1.ovpn
cat /etc/openvpn/easy-rsa/pki/ca.crt >> ~/$1.ovpn cat /etc/openvpn/easy-rsa/pki/ca.crt >> $homeDir/$1.ovpn
echo "</ca>" >> ~/$1.ovpn echo "</ca>" >> $homeDir/$1.ovpn
echo "<cert>" >> ~/$1.ovpn echo "<cert>" >> $homeDir/$1.ovpn
cat /etc/openvpn/easy-rsa/pki/issued/$1.crt >> ~/$1.ovpn cat /etc/openvpn/easy-rsa/pki/issued/$1.crt >> $homeDir/$1.ovpn
echo "</cert>" >> ~/$1.ovpn echo "</cert>" >> $homeDir/$1.ovpn
echo "<key>" >> ~/$1.ovpn echo "<key>" >> $homeDir/$1.ovpn
cat /etc/openvpn/easy-rsa/pki/private/$1.key >> ~/$1.ovpn cat /etc/openvpn/easy-rsa/pki/private/$1.key >> $homeDir/$1.ovpn
echo "</key>" >> ~/$1.ovpn echo "</key>" >> $homeDir/$1.ovpn
echo "<tls-auth>" >> ~/$1.ovpn echo "key-direction 1" >> $homeDir/$1.ovpn
cat /etc/openvpn/ta.key >> ~/$1.ovpn echo "<tls-auth>" >> $homeDir/$1.ovpn
echo "</tls-auth>" >> ~/$1.ovpn cat /etc/openvpn/tls-auth.key >> $homeDir/$1.ovpn
echo "</tls-auth>" >> $homeDir/$1.ovpn
} }
# Try to get our IP from the system and fallback to the Internet. # Try to get our IP from the system and fallback to the Internet.
# I do this to make the script compatible with NATed servers (lowendspirit.com) # I do this to make the script compatible with NATed servers (LowEndSpirit/Scaleway)
# and to avoid getting an IPv6. # and to avoid getting an IPv6.
IP=$(ip addr | grep 'inet' | grep -v inet6 | grep -vE '127\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}' | grep -o -E '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}' | head -1) IP=$(ip addr | grep 'inet' | grep -v inet6 | grep -vE '127\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}' | grep -o -E '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}' | head -1)
if [[ "$IP" = "" ]]; then if [[ "$IP" = "" ]]; then
IP=$(wget -4qO- "http://whatismyip.akamai.com/") IP=$(wget -qO- ipv4.icanhazip.com)
fi fi
# Get Internet network interface with default route
NIC=$(ip -4 route ls | grep default | grep -Po '(?<=dev )(\S+)')
if [[ -e /etc/openvpn/server.conf ]]; then if [[ -e /etc/openvpn/server.conf ]]; then
while : while :
do do
clear clear
echo "OpenVPN-install (github.com/Angristan/OpenVPN-install)"
echo ""
echo "Looks like OpenVPN is already installed" echo "Looks like OpenVPN is already installed"
echo "" echo ""
echo "What do you want to do?" echo "What do you want to do?"
echo " 1) Add a new user" echo " 1) Add a cert for a new user"
echo " 2) Revoke an existing user" echo " 2) Revoke existing user cert"
echo " 3) Remove OpenVPN" echo " 3) Remove OpenVPN"
echo " 4) Exit" echo " 4) Exit"
read -p "Select an option [1-4]: " option read -p "Select an option [1-4]: " option
case $option in case $option in
1) 1)
echo "" echo ""
echo "Tell me a name for the client certificate" echo "Tell me a name for the client cert"
echo "Please, use one word only, no special characters" echo "Please, use one word only, no special characters"
read -p "Client name: " -e -i client CLIENT read -p "Client name: " -e -i client CLIENT
cd /etc/openvpn/easy-rsa/ cd /etc/openvpn/easy-rsa/
@ -90,17 +116,15 @@ if [[ -e /etc/openvpn/server.conf ]]; then
# Generates the custom client.ovpn # Generates the custom client.ovpn
newclient "$CLIENT" newclient "$CLIENT"
echo "" echo ""
echo "Client $CLIENT added, configuration is available at" ~/"$CLIENT.ovpn" echo "Client $CLIENT added, certs available at $homeDir/$CLIENT.ovpn"
exit exit
;; ;;
2) 2)
# This option could be documented a bit better and maybe even be simplimplified
# ...but what can I say, I want some sleep too
NUMBEROFCLIENTS=$(tail -n +2 /etc/openvpn/easy-rsa/pki/index.txt | grep -c "^V") NUMBEROFCLIENTS=$(tail -n +2 /etc/openvpn/easy-rsa/pki/index.txt | grep -c "^V")
if [[ "$NUMBEROFCLIENTS" = '0' ]]; then if [[ "$NUMBEROFCLIENTS" = '0' ]]; then
echo "" echo ""
echo "You have no existing clients!" echo "You have no existing clients!"
exit 6 exit 5
fi fi
echo "" echo ""
echo "Select the existing client certificate you want to revoke" echo "Select the existing client certificate you want to revoke"
@ -119,53 +143,46 @@ if [[ -e /etc/openvpn/server.conf ]]; then
rm -rf pki/issued/$CLIENT.crt rm -rf pki/issued/$CLIENT.crt
rm -rf /etc/openvpn/crl.pem rm -rf /etc/openvpn/crl.pem
cp /etc/openvpn/easy-rsa/pki/crl.pem /etc/openvpn/crl.pem cp /etc/openvpn/easy-rsa/pki/crl.pem /etc/openvpn/crl.pem
# CRL is read with each client connection, when OpenVPN is dropped to nobody chmod 644 /etc/openvpn/crl.pem
chown nobody:$GROUPNAME /etc/openvpn/crl.pem
echo "" echo ""
echo "Certificate for client $CLIENT revoked" echo "Certificate for client $CLIENT revoked"
echo "Exiting..."
exit exit
;; ;;
3) 3)
echo "" echo ""
read -p "Do you really want to remove OpenVPN? [y/n]: " -e -i n REMOVE read -p "Do you really want to remove OpenVPN? [y/n]: " -e -i n REMOVE
if [[ "$REMOVE" = 'y' ]]; then if [[ "$REMOVE" = 'y' ]]; then
PORT=$(grep '^port ' /etc/openvpn/server.conf | cut -d " " -f 2) PORT=$(grep '^port ' /etc/openvpn/server.conf | cut -d " " -f 2)
PROTOCOL=$(grep '^proto ' /etc/openvpn/server.conf | cut -d " " -f 2)
if pgrep firewalld; then if pgrep firewalld; then
IP=$(firewall-cmd --direct --get-rules ipv4 nat POSTROUTING | grep '\-s 10.8.0.0/24 '"'"'!'"'"' -d 10.8.0.0/24 -j SNAT --to ' | cut -d " " -f 10)
# Using both permanent and not permanent rules to avoid a firewalld reload. # Using both permanent and not permanent rules to avoid a firewalld reload.
firewall-cmd --zone=public --remove-port=$PORT/$PROTOCOL firewall-cmd --zone=public --remove-port=$PORT/udp
firewall-cmd --zone=trusted --remove-source=10.8.0.0/24 firewall-cmd --zone=trusted --remove-source=10.8.0.0/24
firewall-cmd --permanent --zone=public --remove-port=$PORT/$PROTOCOL firewall-cmd --permanent --zone=public --remove-port=$PORT/udp
firewall-cmd --permanent --zone=trusted --remove-source=10.8.0.0/24 firewall-cmd --permanent --zone=trusted --remove-source=10.8.0.0/24
firewall-cmd --direct --remove-rule ipv4 nat POSTROUTING 0 -s 10.8.0.0/24 ! -d 10.8.0.0/24 -j SNAT --to $IP
firewall-cmd --permanent --direct --remove-rule ipv4 nat POSTROUTING 0 -s 10.8.0.0/24 ! -d 10.8.0.0/24 -j SNAT --to $IP
else
IP=$(grep 'iptables -t nat -A POSTROUTING -s 10.8.0.0/24 ! -d 10.8.0.0/24 -j SNAT --to ' $RCLOCAL | cut -d " " -f 14)
iptables -t nat -D POSTROUTING -s 10.8.0.0/24 ! -d 10.8.0.0/24 -j SNAT --to $IP
sed -i '/iptables -t nat -A POSTROUTING -s 10.8.0.0\/24 ! -d 10.8.0.0\/24 -j SNAT --to /d' $RCLOCAL
if iptables -L -n | grep -qE '^ACCEPT'; then
iptables -D INPUT -p $PROTOCOL --dport $PORT -j ACCEPT
iptables -D FORWARD -s 10.8.0.0/24 -j ACCEPT
iptables -D FORWARD -m state --state RELATED,ESTABLISHED -j ACCEPT
sed -i "/iptables -I INPUT -p $PROTOCOL --dport $PORT -j ACCEPT/d" $RCLOCAL
sed -i "/iptables -I FORWARD -s 10.8.0.0\/24 -j ACCEPT/d" $RCLOCAL
sed -i "/iptables -I FORWARD -m state --state RELATED,ESTABLISHED -j ACCEPT/d" $RCLOCAL
fi
fi fi
if iptables -L -n | grep -qE 'REJECT|DROP'; then
sed -i "/iptables -I INPUT -p udp --dport $PORT -j ACCEPT/d" $RCLOCAL
sed -i "/iptables -I FORWARD -s 10.8.0.0\/24 -j ACCEPT/d" $RCLOCAL
sed -i "/iptables -I FORWARD -m state --state RELATED,ESTABLISHED -j ACCEPT/d" $RCLOCAL
fi
sed -i '/iptables -t nat -A POSTROUTING -s 10.8.0.0\/24 -j SNAT --to /d' $RCLOCAL
if hash sestatus 2>/dev/null; then if hash sestatus 2>/dev/null; then
if sestatus | grep "Current mode" | grep -qs "enforcing"; then if sestatus | grep "Current mode" | grep -qs "enforcing"; then
if [[ "$PORT" != '1194' || "$PROTOCOL" = 'tcp' ]]; then if [[ "$PORT" != '1194' ]]; then
semanage port -d -t openvpn_port_t -p $PROTOCOL $PORT semanage port -d -t openvpn_port_t -p udp $PORT
fi fi
fi fi
fi fi
if [[ "$OS" = 'debian' ]]; then if [[ "$OS" = 'debian' ]]; then
apt-get remove --purge -y openvpn apt-get autoremove --purge -y openvpn
elif [[ "$OS" = 'arch' ]]; then
pacman -R openvpn --noconfirm
else else
yum remove openvpn -y yum remove openvpn -y
fi fi
rm -rf /etc/openvpn rm -rf /etc/openvpn
rm -rf /usr/share/doc/openvpn*
echo "" echo ""
echo "OpenVPN removed!" echo "OpenVPN removed!"
else else
@ -179,184 +196,364 @@ if [[ -e /etc/openvpn/server.conf ]]; then
done done
else else
clear clear
echo 'Welcome to this quick OpenVPN "road warrior" installer' echo "Welcome to the secure OpenVPN installer (github.com/Angristan/OpenVPN-install)"
echo "" echo ""
# OpenVPN setup and first user creation # OpenVPN setup and first user creation
echo "I need to ask you a few questions before starting the setup" 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 "You can leave the default options and just press enter if you are ok with them"
echo "" echo ""
echo "First I need to know the IPv4 address of the network interface you want OpenVPN" echo "I need to know the IPv4 address of the network interface you want OpenVPN listening to."
echo "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."
read -p "IP address: " -e -i $IP IP read -p "IP address: " -e -i $IP IP
echo "" echo ""
echo "Which protocol do you want for OpenVPN connections?" echo "What port do you want for OpenVPN?"
echo " 1) UDP (recommended)" read -p "Port: " -e -i 1194 PORT
echo " 2) TCP" echo ""
read -p "Protocol [1-2]: " -e -i 1 PROTOCOL echo "What protocol do you want for OpenVPN?"
case $PROTOCOL in echo "Unless UDP is blocked, you should not use TCP (unnecessarily slower)"
1) while [[ $PROTOCOL != "UDP" && $PROTOCOL != "TCP" ]]; do
PROTOCOL=udp read -p "Protocol [UDP/TCP]: " -e -i UDP PROTOCOL
done
echo ""
echo "What DNS do you want to use with the VPN?"
echo " 1) Current system resolvers (in /etc/resolv.conf)"
echo " 2) FDN (France)"
echo " 3) DNS.WATCH (Germany)"
echo " 4) OpenDNS (Anycast: worldwide)"
echo " 5) Google (Anycast: worldwide)"
echo " 6) Yandex Basic (Russia)"
while [[ $DNS != "1" && $DNS != "2" && $DNS != "3" && $DNS != "4" && $DNS != "5" && $DNS != "6" ]]; do
read -p "DNS [1-6]: " -e -i 1 DNS
done
echo ""
echo "See https://github.com/Angristan/OpenVPN-install#encryption to learn more about "
echo "the encryption in OpenVPN and the choices I made in this script."
echo "Please note that all the choices proposed are secure (to a different degree)"
echo "and are still viable to date, unlike some default OpenVPN options"
echo ''
echo "Choose which cipher you want to use for the data channel:"
echo " 1) AES-128-CBC (fastest and sufficiently secure for everyone, recommended)"
echo " 2) AES-192-CBC"
echo " 3) AES-256-CBC"
echo "Alternatives to AES, use them only if you know what you're doing."
echo "They are relatively slower but as secure as AES."
echo " 4) CAMELLIA-128-CBC"
echo " 5) CAMELLIA-192-CBC"
echo " 6) CAMELLIA-256-CBC"
echo " 7) SEED-CBC"
while [[ $CIPHER != "1" && $CIPHER != "2" && $CIPHER != "3" && $CIPHER != "4" && $CIPHER != "5" && $CIPHER != "6" && $CIPHER != "7" ]]; do
read -p "Cipher [1-7]: " -e -i 1 CIPHER
done
case $CIPHER in
1)
CIPHER="cipher AES-128-CBC"
;; ;;
2) 2)
PROTOCOL=tcp CIPHER="cipher AES-192-CBC"
;;
3)
CIPHER="cipher AES-256-CBC"
;;
4)
CIPHER="cipher CAMELLIA-128-CBC"
;;
5)
CIPHER="cipher CAMELLIA-192-CBC"
;;
6)
CIPHER="cipher CAMELLIA-256-CBC"
;;
7)
CIPHER="cipher SEED-CBC"
;; ;;
esac esac
echo "" echo ""
echo "What port do you want OpenVPN listening to?" echo "Choose what size of Diffie-Hellman key you want to use:"
read -p "Port: " -e -i 1194 PORT echo " 1) 2048 bits (fastest)"
echo " 2) 3072 bits (recommended, best compromise)"
echo " 3) 4096 bits (most secure)"
while [[ $DH_KEY_SIZE != "1" && $DH_KEY_SIZE != "2" && $DH_KEY_SIZE != "3" ]]; do
read -p "DH key size [1-3]: " -e -i 2 DH_KEY_SIZE
done
case $DH_KEY_SIZE in
1)
DH_KEY_SIZE="2048"
;;
2)
DH_KEY_SIZE="3072"
;;
3)
DH_KEY_SIZE="4096"
;;
esac
echo "" echo ""
echo "Which DNS do you want to use with the VPN?" echo "Choose what size of RSA key you want to use:"
echo " 1) Current system resolvers" echo " 1) 2048 bits (fastest)"
echo " 2) Google" echo " 2) 3072 bits (recommended, best compromise)"
echo " 3) OpenDNS" echo " 3) 4096 bits (most secure)"
echo " 4) NTT" while [[ $RSA_KEY_SIZE != "1" && $RSA_KEY_SIZE != "2" && $RSA_KEY_SIZE != "3" ]]; do
echo " 5) Hurricane Electric" read -p "DH key size [1-3]: " -e -i 2 RSA_KEY_SIZE
echo " 6) Verisign" done
read -p "DNS [1-6]: " -e -i 1 DNS case $RSA_KEY_SIZE in
1)
RSA_KEY_SIZE="2048"
;;
2)
RSA_KEY_SIZE="3072"
;;
3)
RSA_KEY_SIZE="4096"
;;
esac
echo "" echo ""
echo "Finally, tell me your name for the client certificate" echo "Finally, tell me a name for the client certificate and configuration"
echo "Please, use one word only, no special characters" while [[ $CLIENT = "" ]]; do
read -p "Client name: " -e -i client CLIENT echo "Please, use one word only, no special characters"
read -p "Client name: " -e -i client CLIENT
done
echo "" echo ""
echo "Okay, that was all I needed. We are ready to setup your OpenVPN server now" echo "Okay, that was all I needed. We are ready to setup your OpenVPN server now"
read -n1 -r -p "Press any key to continue..." read -n1 -r -p "Press any key to continue..."
if [[ "$OS" = 'debian' ]]; then if [[ "$OS" = 'debian' ]]; then
apt-get update apt-get install ca-certificates -y
apt-get install openvpn iptables openssl ca-certificates -y # We add the OpenVPN repo to get the latest version.
else # Debian 7
# Else, the distro is CentOS if [[ "$VERSION_ID" = 'VERSION_ID="7"' ]]; then
echo "deb http://build.openvpn.net/debian/openvpn/stable wheezy 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
# Debian 8
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 update
fi
# Ubuntu 12.04
if [[ "$VERSION_ID" = 'VERSION_ID="12.04"' ]]; then
echo "deb http://build.openvpn.net/debian/openvpn/stable precise 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 14.04
if [[ "$VERSION_ID" = 'VERSION_ID="14.04"' ]]; then
echo "deb http://build.openvpn.net/debian/openvpn/stable trusty 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.
# The we install OpenVPN
apt-get install openvpn iptables openssl wget ca-certificates curl -y
elif [[ "$OS" = 'centos' ]]; then
yum install epel-release -y yum install epel-release -y
yum install openvpn iptables openssl wget ca-certificates -y yum install openvpn iptables openssl wget ca-certificates curl -y
else
# Else, the distro is ArchLinux
echo ""
echo ""
echo "As you're using ArchLinux, I need to update the packages on your system to install those I need."
echo "Not doing that could cause problems between dependencies, or missing files in repositories."
echo ""
echo "Continuing will update your installed packages and install needed ones."
while [[ $CONTINUE != "y" && $CONTINUE != "n" ]]; do
read -p "Continue ? [y/n]: " -e -i y CONTINUE
done
if [[ "$CONTINUE" = "n" ]]; then
echo "Ok, bye !"
exit 4
fi
if [[ "$OS" = 'arch' ]]; then
# Install rc.local
echo "[Unit]
Description=/etc/rc.local compatibility
[Service]
Type=oneshot
ExecStart=/etc/rc.local
RemainAfterExit=yes
[Install]
WantedBy=multi-user.target" > /etc/systemd/system/rc-local.service
chmod +x /etc/rc.local
systemctl enable rc-local.service
if ! grep '#!' $RCLOCAL; then
echo "#!/bin/bash" > $RCLOCAL
fi
fi
# Install dependencies
pacman -Syu openvpn iptables openssl wget ca-certificates curl --needed --noconfirm
if [[ "$OS" = 'arch' ]]; then
touch /etc/iptables/iptables.rules # iptables won't start if this file does not exist
systemctl enable iptables
systemctl start iptables
fi
fi 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 # An old version of easy-rsa was available by default in some openvpn packages
if [[ -d /etc/openvpn/easy-rsa/ ]]; then if [[ -d /etc/openvpn/easy-rsa/ ]]; then
rm -rf /etc/openvpn/easy-rsa/ rm -rf /etc/openvpn/easy-rsa/
fi fi
# Get easy-rsa # Get easy-rsa
wget -O ~/EasyRSA-3.0.1.tgz "https://github.com/OpenVPN/easy-rsa/releases/download/3.0.1/EasyRSA-3.0.1.tgz" wget -O ~/EasyRSA-3.0.3.tgz https://github.com/OpenVPN/easy-rsa/releases/download/v3.0.3/EasyRSA-3.0.3.tgz
tar xzf ~/EasyRSA-3.0.1.tgz -C ~/ tar xzf ~/EasyRSA-3.0.3.tgz -C ~/
mv ~/EasyRSA-3.0.1/ /etc/openvpn/ mv ~/EasyRSA-3.0.3/ /etc/openvpn/
mv /etc/openvpn/EasyRSA-3.0.1/ /etc/openvpn/easy-rsa/ mv /etc/openvpn/EasyRSA-3.0.3/ /etc/openvpn/easy-rsa/
chown -R root:root /etc/openvpn/easy-rsa/ chown -R root:root /etc/openvpn/easy-rsa/
rm -rf ~/EasyRSA-3.0.1.tgz rm -rf ~/EasyRSA-3.0.3.tgz
cd /etc/openvpn/easy-rsa/ cd /etc/openvpn/easy-rsa/
echo "set_var EASYRSA_KEY_SIZE $RSA_KEY_SIZE" > vars
# Create the PKI, set up the CA, the DH params and the server + client certificates # Create the PKI, set up the CA, the DH params and the server + client certificates
./easyrsa init-pki ./easyrsa init-pki
./easyrsa --batch build-ca nopass ./easyrsa --batch build-ca nopass
./easyrsa gen-dh openssl dhparam -out dh.pem $DH_KEY_SIZE
./easyrsa build-server-full server nopass ./easyrsa build-server-full server nopass
./easyrsa build-client-full $CLIENT nopass ./easyrsa build-client-full $CLIENT nopass
./easyrsa gen-crl ./easyrsa gen-crl
# Move the stuff we need # generate tls-auth key
cp pki/ca.crt pki/private/ca.key pki/dh.pem pki/issued/server.crt pki/private/server.key pki/crl.pem /etc/openvpn openvpn --genkey --secret /etc/openvpn/tls-auth.key
# CRL is read with each client connection, when OpenVPN is dropped to nobody # Move all the generated files
chown nobody:$GROUPNAME /etc/openvpn/crl.pem cp pki/ca.crt pki/private/ca.key dh.pem pki/issued/server.crt pki/private/server.key /etc/openvpn/easy-rsa/pki/crl.pem /etc/openvpn
# Generate key for tls-auth # Make cert revocation list readable for non-root
openvpn --genkey --secret /etc/openvpn/ta.key chmod 644 /etc/openvpn/crl.pem
# Generate server.conf # Generate server.conf
echo "port $PORT echo "local $IP" > /etc/openvpn/server.conf
proto $PROTOCOL echo "port $PORT" >> /etc/openvpn/server.conf
dev tun if [[ "$PROTOCOL" = 'UDP' ]]; then
sndbuf 0 echo "proto udp" >> /etc/openvpn/server.conf
rcvbuf 0 elif [[ "$PROTOCOL" = 'TCP' ]]; then
ca ca.crt echo "proto tcp" >> /etc/openvpn/server.conf
cert server.crt fi
key server.key echo "dev tun
dh dh.pem user nobody
auth SHA512 group $NOGROUP
tls-auth ta.key 0 persist-key
persist-tun
keepalive 10 120
topology subnet topology subnet
server 10.8.0.0 255.255.255.0 server 10.8.0.0 255.255.255.0
ifconfig-pool-persist ipp.txt" > /etc/openvpn/server.conf ifconfig-pool-persist ipp.txt" >> /etc/openvpn/server.conf
echo 'push "redirect-gateway def1 bypass-dhcp"' >> /etc/openvpn/server.conf # DNS resolvers
# DNS
case $DNS in case $DNS in
1) 1)
# Obtain the resolvers from resolv.conf and use them for OpenVPN # Obtain the resolvers from resolv.conf and use them for OpenVPN
grep -v '#' /etc/resolv.conf | grep 'nameserver' | grep -E -o '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}' | while read line; do grep -v '#' /etc/resolv.conf | grep 'nameserver' | grep -E -o '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}' | while read line; do
echo "push \"dhcp-option DNS $line\"" >> /etc/openvpn/server.conf echo "push \"dhcp-option DNS $line\"" >> /etc/openvpn/server.conf
done done
;; ;;
2) 2) #FDN
echo 'push "dhcp-option DNS 8.8.8.8"' >> /etc/openvpn/server.conf echo 'push "dhcp-option DNS 80.67.169.12"' >> /etc/openvpn/server.conf
echo 'push "dhcp-option DNS 8.8.4.4"' >> /etc/openvpn/server.conf echo 'push "dhcp-option DNS 80.67.169.40"' >> /etc/openvpn/server.conf
;; ;;
3) 3) #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
;;
4) #OpenDNS
echo 'push "dhcp-option DNS 208.67.222.222"' >> /etc/openvpn/server.conf 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 echo 'push "dhcp-option DNS 208.67.220.220"' >> /etc/openvpn/server.conf
;; ;;
4) 5) #Google
echo 'push "dhcp-option DNS 129.250.35.250"' >> /etc/openvpn/server.conf echo 'push "dhcp-option DNS 8.8.8.8"' >> /etc/openvpn/server.conf
echo 'push "dhcp-option DNS 129.250.35.251"' >> /etc/openvpn/server.conf echo 'push "dhcp-option DNS 8.8.4.4"' >> /etc/openvpn/server.conf
;; ;;
5) 6) #Yandex Basic
echo 'push "dhcp-option DNS 74.82.42.42"' >> /etc/openvpn/server.conf 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
6)
echo 'push "dhcp-option DNS 64.6.64.6"' >> /etc/openvpn/server.conf
echo 'push "dhcp-option DNS 64.6.65.6"' >> /etc/openvpn/server.conf
;; ;;
esac esac
echo "keepalive 10 120 echo 'push "redirect-gateway def1 bypass-dhcp" '>> /etc/openvpn/server.conf
cipher AES-256-CBC echo "crl-verify crl.pem
comp-lzo ca ca.crt
user nobody cert server.crt
group $GROUPNAME key server.key
persist-key tls-auth tls-auth.key 0
persist-tun dh dh.pem
status openvpn-status.log auth SHA256
verb 3 $CIPHER
crl-verify crl.pem" >> /etc/openvpn/server.conf tls-server
tls-version-min 1.2
tls-cipher TLS-DHE-RSA-WITH-AES-128-GCM-SHA256
status openvpn.log
verb 3" >> /etc/openvpn/server.conf
# Create the sysctl configuration file if needed (mainly for Arch Linux)
if [[ ! -e $SYSCTL ]]; then
touch $SYSCTL
fi
# Enable net.ipv4.ip_forward for the system # Enable net.ipv4.ip_forward for the system
sed -i '/\<net.ipv4.ip_forward\>/c\net.ipv4.ip_forward=1' /etc/sysctl.conf sed -i '/\<net.ipv4.ip_forward\>/c\net.ipv4.ip_forward=1' $SYSCTL
if ! grep -q "\<net.ipv4.ip_forward\>" /etc/sysctl.conf; then if ! grep -q "\<net.ipv4.ip_forward\>" $SYSCTL; then
echo 'net.ipv4.ip_forward=1' >> /etc/sysctl.conf echo 'net.ipv4.ip_forward=1' >> $SYSCTL
fi fi
# Avoid an unneeded reboot # Avoid an unneeded reboot
echo 1 > /proc/sys/net/ipv4/ip_forward echo 1 > /proc/sys/net/ipv4/ip_forward
if pgrep firewalld; then # Needed to use rc.local with some systemd distros
# Using both permanent and not permanent rules to avoid a firewalld if [[ "$OS" = 'debian' && ! -e $RCLOCAL ]]; then
# reload. echo '#!/bin/sh -e
# We don't use --add-service=openvpn because that would only work with exit 0' > $RCLOCAL
# the default port and protocol.
firewall-cmd --zone=public --add-port=$PORT/$PROTOCOL
firewall-cmd --zone=trusted --add-source=10.8.0.0/24
firewall-cmd --permanent --zone=public --add-port=$PORT/$PROTOCOL
firewall-cmd --permanent --zone=trusted --add-source=10.8.0.0/24
# Set NAT for the VPN subnet
firewall-cmd --direct --add-rule ipv4 nat POSTROUTING 0 -s 10.8.0.0/24 ! -d 10.8.0.0/24 -j SNAT --to $IP
firewall-cmd --permanent --direct --add-rule ipv4 nat POSTROUTING 0 -s 10.8.0.0/24 ! -d 10.8.0.0/24 -j SNAT --to $IP
else
# Needed to use rc.local with some systemd distros
if [[ "$OS" = 'debian' && ! -e $RCLOCAL ]]; then
echo '#!/bin/sh -e
exit 0' > $RCLOCAL
fi
chmod +x $RCLOCAL
# Set NAT for the VPN subnet
iptables -t nat -A POSTROUTING -s 10.8.0.0/24 ! -d 10.8.0.0/24 -j SNAT --to $IP
sed -i "1 a\iptables -t nat -A POSTROUTING -s 10.8.0.0/24 ! -d 10.8.0.0/24 -j SNAT --to $IP" $RCLOCAL
if iptables -L -n | grep -qE '^(REJECT|DROP)'; then
# If iptables has at least one REJECT rule, we asume this is needed.
# Not the best approach but I can't think of other and this shouldn't
# cause problems.
iptables -I INPUT -p $PROTOCOL --dport $PORT -j ACCEPT
iptables -I FORWARD -s 10.8.0.0/24 -j ACCEPT
iptables -I FORWARD -m state --state RELATED,ESTABLISHED -j ACCEPT
sed -i "1 a\iptables -I INPUT -p $PROTOCOL --dport $PORT -j ACCEPT" $RCLOCAL
sed -i "1 a\iptables -I FORWARD -s 10.8.0.0/24 -j ACCEPT" $RCLOCAL
sed -i "1 a\iptables -I FORWARD -m state --state RELATED,ESTABLISHED -j ACCEPT" $RCLOCAL
fi
fi fi
# If SELinux is enabled and a custom port or TCP was selected, we need this chmod +x $RCLOCAL
# Set NAT for the VPN subnet
iptables -t nat -A POSTROUTING -o $NIC -s 10.8.0.0/24 -j MASQUERADE
sed -i "1 a\iptables -t nat -A POSTROUTING -o $NIC -s 10.8.0.0/24 -j MASQUERADE" $RCLOCAL
if pgrep firewalld; then
# We don't use --add-service=openvpn because that would only work with
# the default port. Using both permanent and not permanent rules to
# avoid a firewalld reload.
if [[ "$PROTOCOL" = 'UDP' ]]; then
firewall-cmd --zone=public --add-port=$PORT/udp
firewall-cmd --permanent --zone=public --add-port=$PORT/udp
elif [[ "$PROTOCOL" = 'TCP' ]]; then
firewall-cmd --zone=public --add-port=$PORT/tcp
firewall-cmd --permanent --zone=public --add-port=$PORT/tcp
fi
firewall-cmd --zone=trusted --add-source=10.8.0.0/24
firewall-cmd --permanent --zone=trusted --add-source=10.8.0.0/24
fi
if iptables -L -n | grep -qE 'REJECT|DROP'; then
# If iptables has at least one REJECT rule, we asume this is needed.
# Not the best approach but I can't think of other and this shouldn't
# cause problems.
if [[ "$PROTOCOL" = 'UDP' ]]; then
iptables -I INPUT -p udp --dport $PORT -j ACCEPT
elif [[ "$PROTOCOL" = 'TCP' ]]; then
iptables -I INPUT -p tcp --dport $PORT -j ACCEPT
fi
iptables -I FORWARD -s 10.8.0.0/24 -j ACCEPT
iptables -I FORWARD -m state --state RELATED,ESTABLISHED -j ACCEPT
if [[ "$PROTOCOL" = 'UDP' ]]; then
sed -i "1 a\iptables -I INPUT -p udp --dport $PORT -j ACCEPT" $RCLOCAL
elif [[ "$PROTOCOL" = 'TCP' ]]; then
sed -i "1 a\iptables -I INPUT -p tcp --dport $PORT -j ACCEPT" $RCLOCAL
fi
sed -i "1 a\iptables -I FORWARD -s 10.8.0.0/24 -j ACCEPT" $RCLOCAL
sed -i "1 a\iptables -I FORWARD -m state --state RELATED,ESTABLISHED -j ACCEPT" $RCLOCAL
fi
# If SELinux is enabled and a custom port was selected, we need this
if hash sestatus 2>/dev/null; then if hash sestatus 2>/dev/null; then
if sestatus | grep "Current mode" | grep -qs "enforcing"; then if sestatus | grep "Current mode" | grep -qs "enforcing"; then
if [[ "$PORT" != '1194' || "$PROTOCOL" = 'tcp' ]]; then if [[ "$PORT" != '1194' ]]; then
# semanage isn't available in CentOS 6 by default # semanage isn't available in CentOS 6 by default
if ! hash semanage 2>/dev/null; then if ! hash semanage 2>/dev/null; then
yum install policycoreutils-python -y yum install policycoreutils-python -y
fi fi
semanage port -a -t openvpn_port_t -p $PROTOCOL $PORT if [[ "$PROTOCOL" = 'UDP' ]]; then
semanage port -a -t openvpn_port_t -p udp $PORT
elif [[ "$PROTOCOL" = 'TCP' ]]; then
semanage port -a -t openvpn_port_t -p tcp $PORT
fi
fi fi
fi fi
fi fi
@ -364,55 +561,85 @@ exit 0' > $RCLOCAL
if [[ "$OS" = 'debian' ]]; then if [[ "$OS" = 'debian' ]]; then
# Little hack to check for systemd # Little hack to check for systemd
if pgrep systemd-journal; then if pgrep systemd-journal; then
systemctl restart openvpn@server.service if [[ "$VERSION_ID" = 'VERSION_ID="9"' ]]; then
#Workaround to fix OpenVPN service on Debian 9 OpenVZ
sed -i 's|LimitNPROC|#LimitNPROC|' /lib/systemd/system/openvpn-server\@.service
sed -i 's|/etc/openvpn/server|/etc/openvpn|' /lib/systemd/system/openvpn-server\@.service
sed -i 's|%i.conf|server.conf|' /lib/systemd/system/openvpn-server\@.service
systemctl daemon-reload
systemctl restart openvpn-server@openvpn.service
systemctl enable openvpn-server@openvpn.service
else
systemctl restart openvpn@server.service
fi
else else
/etc/init.d/openvpn restart /etc/init.d/openvpn restart
fi fi
else else
if pgrep systemd-journal; then if pgrep systemd-journal; then
systemctl restart openvpn@server.service if [[ "$OS" = 'arch' ]]; then
systemctl enable openvpn@server.service #Workaround to avoid rewriting the entire script for Arch
sed -i 's|/etc/openvpn/server|/etc/openvpn|' /usr/lib/systemd/system/openvpn-server@.service
sed -i 's|%i.conf|server.conf|' /usr/lib/systemd/system/openvpn-server@.service
systemctl daemon-reload
systemctl restart openvpn-server@openvpn.service
systemctl enable openvpn-server@openvpn.service
else
systemctl restart openvpn@server.service
systemctl enable openvpn@server.service
fi
else else
service openvpn restart service openvpn restart
chkconfig openvpn on chkconfig openvpn on
fi fi
fi fi
# Try to detect a NATed connection and ask about it to potential LowEndSpirit users # Try to detect a NATed connection and ask about it to potential LowEndSpirit/Scaleway users
EXTERNALIP=$(wget -4qO- "http://whatismyip.akamai.com/") EXTERNALIP=$(wget -qO- ipv4.icanhazip.com)
if [[ "$IP" != "$EXTERNALIP" ]]; then if [[ "$IP" != "$EXTERNALIP" ]]; then
echo "" echo ""
echo "Looks like your server is behind a NAT!" echo "Looks like your server is behind a NAT!"
echo "" echo ""
echo "If your server is NATed (e.g. LowEndSpirit), I need to know the external IP" echo "If your server is NATed (e.g. LowEndSpirit, Scaleway, or behind a router),"
echo "If that's not the case, just ignore this and leave the next field blank" echo "then I need to know the address that can be used to access it from outside."
read -p "External IP: " -e USEREXTERNALIP echo "If that's not the case, just ignore this and leave the next field blank"
read -p "External IP or domain name: " -e USEREXTERNALIP
if [[ "$USEREXTERNALIP" != "" ]]; then if [[ "$USEREXTERNALIP" != "" ]]; then
IP=$USEREXTERNALIP IP=$USEREXTERNALIP
fi fi
fi fi
# client-common.txt is created so we have a template to add further users later # client-template.txt is created so we have a template to add further users later
echo "client 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 dev tun
proto $PROTOCOL
sndbuf 0
rcvbuf 0
remote $IP $PORT
resolv-retry infinite resolv-retry infinite
nobind nobind
persist-key persist-key
persist-tun persist-tun
remote-cert-tls server remote-cert-tls server
auth SHA512 auth SHA256
cipher AES-256-CBC $CIPHER
comp-lzo tls-client
tls-version-min 1.2
tls-cipher TLS-DHE-RSA-WITH-AES-128-GCM-SHA256
setenv opt block-outside-dns setenv opt block-outside-dns
key-direction 1 verb 3" >> /etc/openvpn/client-template.txt
verb 3" > /etc/openvpn/client-common.txt
# Generates the custom client.ovpn # Generate the custom client.ovpn
newclient "$CLIENT" newclient "$CLIENT"
echo "" echo ""
echo "Finished!" echo "Finished!"
echo "" echo ""
echo "Your client configuration is available at" ~/"$CLIENT.ovpn" echo "Your client config is available at $homeDir/$CLIENT.ovpn"
echo "If you want to add more clients, you simply need to run this script again!" echo "If you want to add more clients, you simply need to run this script another time!"
fi fi
exit 0;
# routing
iptables -t nat -F POSTROUTING
echo 1 > /proc/sys/net/ipv4/ip_forward
iptables -t nat -A POSTROUTING -o eth0 -s 10.8.0.0/24 -j MASQUERADE