Last active
November 4, 2017 15:02
-
-
Save sd65/911414e5f09e21d099e6d17f1b10aaf8 to your computer and use it in GitHub Desktop.
instaVPN
This file contains 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 OpenVPN server installer for Debian, Ubuntu, CentOS and Arch Linux | |
# https://github.com/Angristan/OpenVPN-install | |
if [[ "$EUID" -ne 0 ]]; then | |
echo "Sorry, you need to run this as root" | |
exit 1 | |
fi | |
if [[ ! -e /dev/net/tun ]]; then | |
echo "TUN is not available" | |
exit 2 | |
fi | |
OS=centos | |
RCLOCAL='/etc/rc.d/rc.local' | |
SYSCTL='/etc/sysctl.conf' | |
# Needed for CentOS 7 | |
chmod +x /etc/rc.d/rc.local | |
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 | |
cp /etc/openvpn/client-template.txt $homeDir/$1.ovpn | |
echo "<ca>" >> $homeDir/$1.ovpn | |
cat /etc/openvpn/easy-rsa/pki/ca.crt >> $homeDir/$1.ovpn | |
echo "</ca>" >> $homeDir/$1.ovpn | |
echo "<cert>" >> $homeDir/$1.ovpn | |
cat /etc/openvpn/easy-rsa/pki/issued/$1.crt >> $homeDir/$1.ovpn | |
echo "</cert>" >> $homeDir/$1.ovpn | |
echo "<key>" >> $homeDir/$1.ovpn | |
cat /etc/openvpn/easy-rsa/pki/private/$1.key >> $homeDir/$1.ovpn | |
echo "</key>" >> $homeDir/$1.ovpn | |
echo "key-direction 1" >> $homeDir/$1.ovpn | |
echo "<tls-auth>" >> $homeDir/$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. | |
# I do this to make the script compatible with NATed servers (LowEndSpirit/Scaleway) | |
# 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) | |
# Get Internet network interface with default route | |
NIC=$(ip -4 route ls | grep default | grep -Po '(?<=dev )(\S+)') | |
echo "Welcome to the secure OpenVPN installer (github.com/Angristan/OpenVPN-install)" | |
echo "" | |
# OpenVPN setup and first user creation | |
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." | |
echo "" | |
echo "What port do you want for OpenVPN?" | |
PORT=1194 | |
echo "" | |
echo "What protocol do you want for OpenVPN?" | |
echo "Unless UDP is blocked, you should not use TCP (unnecessarily slower)" | |
PROTOCOL=UDP | |
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)" | |
echo " 7) AdGuard DNS (Russia)" | |
DNS=4 | |
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" | |
CIPHER="cipher AES-128-CBC" | |
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)" | |
DH_KEY_SIZE="2048" | |
echo "" | |
echo "Choose what size of RSA key you want to use:" | |
echo " 1) 2048 bits (fastest)" | |
echo " 2) 3072 bits (recommended, best compromise)" | |
echo " 3) 4096 bits (most secure)" | |
RSA_KEY_SIZE="2048" | |
echo "" | |
echo "Finally, tell me a name for the client certificate and configuration" | |
CLIENT=client | |
echo "" | |
echo "Okay, that was all I needed. We are ready to setup your OpenVPN server now" | |
if [[ "$OS" = 'debian' ]]; then | |
apt-get install ca-certificates -y | |
# We add the OpenVPN repo to get the latest version. | |
# Debian 7 | |
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 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 | |
# 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 | |
# Get easy-rsa | |
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.3.tgz -C ~/ | |
mv ~/EasyRSA-3.0.3/ /etc/openvpn/ | |
mv /etc/openvpn/EasyRSA-3.0.3/ /etc/openvpn/easy-rsa/ | |
chown -R root:root /etc/openvpn/easy-rsa/ | |
rm -rf ~/EasyRSA-3.0.3.tgz | |
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 | |
./easyrsa init-pki | |
./easyrsa --batch build-ca nopass | |
openssl dhparam -out dh.pem $DH_KEY_SIZE | |
./easyrsa build-server-full server nopass | |
./easyrsa build-client-full $CLIENT 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.crt pki/private/server.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 "local $IP" > /etc/openvpn/server.conf | |
echo "port $PORT" >> /etc/openvpn/server.conf | |
if [[ "$PROTOCOL" = 'UDP' ]]; then | |
echo "proto udp" >> /etc/openvpn/server.conf | |
elif [[ "$PROTOCOL" = 'TCP' ]]; then | |
echo "proto tcp" >> /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) | |
# 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 | |
echo "push \"dhcp-option DNS $line\"" >> /etc/openvpn/server.conf | |
done | |
;; | |
2) #FDN | |
echo 'push "dhcp-option DNS 80.67.169.12"' >> /etc/openvpn/server.conf | |
echo 'push "dhcp-option DNS 80.67.169.40"' >> /etc/openvpn/server.conf | |
;; | |
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.220.220"' >> /etc/openvpn/server.conf | |
;; | |
5) #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 | |
;; | |
6) #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 | |
;; | |
7) #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 | |
echo "crl-verify crl.pem | |
ca ca.crt | |
cert server.crt | |
key server.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 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 | |
sed -i '/\<net.ipv4.ip_forward\>/c\net.ipv4.ip_forward=1' $SYSCTL | |
if ! grep -q "\<net.ipv4.ip_forward\>" $SYSCTL; then | |
echo 'net.ipv4.ip_forward=1' >> $SYSCTL | |
fi | |
# Avoid an unneeded reboot | |
echo 1 > /proc/sys/net/ipv4/ip_forward | |
# 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 -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 sestatus | grep "Current mode" | grep -qs "enforcing"; then | |
if [[ "$PORT" != '1194' ]]; then | |
# semanage isn't available in CentOS 6 by default | |
if ! hash semanage 2>/dev/null; then | |
yum install policycoreutils-python -y | |
fi | |
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 | |
# And finally, restart OpenVPN | |
if [[ "$OS" = 'debian' ]]; then | |
# Little hack to check for systemd | |
if pgrep systemd-journal; then | |
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 [email protected] | |
systemctl enable [email protected] | |
else | |
systemctl restart [email protected] | |
fi | |
else | |
/etc/init.d/openvpn restart | |
fi | |
else | |
if pgrep systemd-journal; then | |
if [[ "$OS" = 'arch' ]]; then | |
#Workaround to avoid rewriting the entire script for Arch | |
sed -i 's|/etc/openvpn/server|/etc/openvpn|' /usr/lib/systemd/system/[email protected] | |
sed -i 's|%i.conf|server.conf|' /usr/lib/systemd/system/[email protected] | |
systemctl daemon-reload | |
systemctl restart [email protected] | |
systemctl enable [email protected] | |
else | |
systemctl restart [email protected] | |
systemctl enable [email protected] | |
fi | |
else | |
service openvpn restart | |
chkconfig openvpn on | |
fi | |
fi | |
# Try to detect a NATed connection and ask about it to potential LowEndSpirit/Scaleway users | |
IP=$(wget -qO- ipv4.icanhazip.com) | |
# 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 | |
auth SHA256 | |
$CIPHER | |
tls-client | |
tls-version-min 1.2 | |
tls-cipher TLS-DHE-RSA-WITH-AES-128-GCM-SHA256 | |
setenv opt block-outside-dns | |
verb 3" >> /etc/openvpn/client-template.txt | |
# Generate the custom client.ovpn | |
newclient "$CLIENT" | |
echo "" | |
echo "Finished!" | |
echo "" | |
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 another time!" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment