Created
June 27, 2019 21:10
-
-
Save gregology/3730c20be7d80bc23e7e6663c2a5c33f to your computer and use it in GitHub Desktop.
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 | |
# | |
# https://github.com/Nyr/openvpn-install | |
# | |
# Copyright (c) 2013 Nyr. Released under the MIT License. | |
# Detect Debian users running the script with "sh" instead of bash | |
if readlink /proc/$$/exe | grep -q "dash"; then | |
echo "This script needs to be run with bash, not sh" | |
exit | |
fi | |
if [[ "$EUID" -ne 0 ]]; then | |
echo "Sorry, you need to run this as root" | |
exit | |
fi | |
if [[ ! -e /dev/net/tun ]]; then | |
echo "The TUN device is not available | |
You need to enable TUN before running this script" | |
exit | |
fi | |
if [[ -e /etc/debian_version ]]; then | |
OS=debian | |
GROUPNAME=nogroup | |
RCLOCAL='/etc/rc.local' | |
elif [[ -e /etc/centos-release || -e /etc/redhat-release ]]; then | |
OS=centos | |
GROUPNAME=nobody | |
RCLOCAL='/etc/rc.d/rc.local' | |
else | |
echo "Looks like you aren't running this installer on Debian, Ubuntu or CentOS" | |
exit | |
fi | |
newclient () { | |
# Generates the custom client.ovpn | |
cp /etc/openvpn/client-common.txt ~/$1.ovpn | |
echo "<ca>" >> ~/$1.ovpn | |
cat /etc/openvpn/easy-rsa/pki/ca.crt >> ~/$1.ovpn | |
echo "</ca>" >> ~/$1.ovpn | |
echo "<cert>" >> ~/$1.ovpn | |
sed -ne '/BEGIN CERTIFICATE/,$ p' /etc/openvpn/easy-rsa/pki/issued/$1.crt >> ~/$1.ovpn | |
echo "</cert>" >> ~/$1.ovpn | |
echo "<key>" >> ~/$1.ovpn | |
cat /etc/openvpn/easy-rsa/pki/private/$1.key >> ~/$1.ovpn | |
echo "</key>" >> ~/$1.ovpn | |
echo "<tls-auth>" >> ~/$1.ovpn | |
sed -ne '/BEGIN OpenVPN Static key/,$ p' /etc/openvpn/ta.key >> ~/$1.ovpn | |
echo "</tls-auth>" >> ~/$1.ovpn | |
} | |
if [[ -e /etc/openvpn/server.conf ]]; then | |
while : | |
do | |
clear | |
echo "Looks like OpenVPN is already installed." | |
echo | |
echo "What do you want to do?" | |
echo " 1) Add a new user" | |
echo " 2) Revoke an existing user" | |
echo " 3) Remove OpenVPN" | |
echo " 4) Exit" | |
read -p "Select an option [1-4]: " option | |
case $option in | |
1) | |
echo | |
echo "Tell me a name for the client certificate." | |
echo "Please, use one word only, no special characters." | |
read -p "Client name: " -e CLIENT | |
cd /etc/openvpn/easy-rsa/ | |
EASYRSA_CERT_EXPIRE=3650 ./easyrsa build-client-full $CLIENT nopass | |
# Generates the custom client.ovpn | |
newclient "$CLIENT" | |
echo | |
echo "Client $CLIENT added, configuration is available at:" ~/"$CLIENT.ovpn" | |
exit | |
;; | |
2) | |
# This option could be documented a bit better and maybe even be simplified | |
# ...but what can I say, I want some sleep too | |
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 | |
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 -p "Select one client [1]: " CLIENTNUMBER | |
else | |
read -p "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) | |
echo | |
read -p "Do you really want to revoke access for client $CLIENT? [y/N]: " -e REVOKE | |
if [[ "$REVOKE" = 'y' || "$REVOKE" = 'Y' ]]; then | |
cd /etc/openvpn/easy-rsa/ | |
./easyrsa --batch revoke $CLIENT | |
EASYRSA_CRL_DAYS=3650 ./easyrsa gen-crl | |
rm -f /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 | |
chown nobody:$GROUPNAME /etc/openvpn/crl.pem | |
echo | |
echo "Certificate for client $CLIENT revoked!" | |
else | |
echo | |
echo "Certificate revocation for client $CLIENT aborted!" | |
fi | |
exit | |
;; | |
3) | |
echo | |
read -p "Do you really want to remove OpenVPN? [y/N]: " -e REMOVE | |
if [[ "$REMOVE" = 'y' || "$REMOVE" = 'Y' ]]; then | |
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 | |
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. | |
firewall-cmd --zone=public --remove-port=$PORT/$PROTOCOL | |
firewall-cmd --zone=trusted --remove-source=10.8.0.0/24 | |
firewall-cmd --permanent --zone=public --remove-port=$PORT/$PROTOCOL | |
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 | |
if sestatus 2>/dev/null | grep "Current mode" | grep -q "enforcing" && [[ "$PORT" != '1194' ]]; then | |
semanage port -d -t openvpn_port_t -p $PROTOCOL $PORT | |
fi | |
if [[ "$OS" = 'debian' ]]; then | |
apt-get remove --purge -y openvpn | |
else | |
yum remove openvpn -y | |
fi | |
rm -rf /etc/openvpn | |
rm -f /etc/sysctl.d/30-openvpn-forward.conf | |
echo | |
echo "OpenVPN removed!" | |
else | |
echo | |
echo "Removal aborted!" | |
fi | |
exit | |
;; | |
4) exit;; | |
esac | |
done | |
else | |
clear | |
echo 'Welcome to this OpenVPN "road warrior" installer!' | |
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 "First, provide the IPv4 address of the network interface you want OpenVPN" | |
echo "listening to." | |
# Autodetect IP 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 -p "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 -p "Public IP address / hostname: " -e PUBLICIP | |
fi | |
echo | |
echo "Which protocol do you want for OpenVPN connections?" | |
echo " 1) UDP (recommended)" | |
echo " 2) TCP" | |
read -p "Protocol [1-2]: " -e -i 1 PROTOCOL | |
case $PROTOCOL in | |
1) | |
PROTOCOL=udp | |
;; | |
2) | |
PROTOCOL=tcp | |
;; | |
esac | |
echo | |
echo "What port do you want OpenVPN listening to?" | |
read -p "Port: " -e -i 1194 PORT | |
echo | |
echo "Which DNS do you want to use with the VPN?" | |
echo " 1) Current system resolvers" | |
echo " 2) 1.1.1.1" | |
echo " 3) Google" | |
echo " 4) OpenDNS" | |
echo " 5) Verisign" | |
read -p "DNS [1-5]: " -e -i 1 DNS | |
echo | |
echo "Finally, tell me your name for the client certificate." | |
echo "Please, use one word only, no special characters." | |
read -p "Client name: " -e -i client CLIENT | |
echo | |
echo "Okay, that was all I needed. We are ready to set up your OpenVPN server now." | |
read -n1 -r -p "Press any key to continue..." | |
if [[ "$OS" = 'debian' ]]; then | |
apt-get update | |
apt-get install openvpn iptables openssl ca-certificates -y | |
else | |
# Else, the distro is CentOS | |
yum install epel-release -y | |
yum install openvpn iptables openssl ca-certificates -y | |
fi | |
# Get easy-rsa | |
EASYRSAURL='https://github.com/OpenVPN/easy-rsa/releases/download/v3.0.6/EasyRSA-unix-v3.0.6.tgz' | |
wget -O ~/easyrsa.tgz "$EASYRSAURL" 2>/dev/null || curl -Lo ~/easyrsa.tgz "$EASYRSAURL" | |
tar xzf ~/easyrsa.tgz -C ~/ | |
mv ~/EasyRSA-v3.0.6/ /etc/openvpn/ | |
mv /etc/openvpn/EasyRSA-v3.0.6/ /etc/openvpn/easy-rsa/ | |
chown -R root:root /etc/openvpn/easy-rsa/ | |
rm -f ~/easyrsa.tgz | |
cd /etc/openvpn/easy-rsa/ | |
# Create the PKI, set up the CA and the server and client certificates | |
./easyrsa init-pki | |
./easyrsa --batch build-ca nopass | |
EASYRSA_CERT_EXPIRE=3650 ./easyrsa build-server-full server nopass | |
EASYRSA_CERT_EXPIRE=3650 ./easyrsa build-client-full $CLIENT nopass | |
EASYRSA_CRL_DAYS=3650 ./easyrsa gen-crl | |
# Move the stuff we need | |
cp pki/ca.crt pki/private/ca.key pki/issued/server.crt pki/private/server.key pki/crl.pem /etc/openvpn | |
# CRL is read with each client connection, when OpenVPN is dropped to nobody | |
chown nobody:$GROUPNAME /etc/openvpn/crl.pem | |
# Generate key for tls-auth | |
openvpn --genkey --secret /etc/openvpn/ta.key | |
# Create the DH parameters file using the predefined ffdhe2048 group | |
echo '-----BEGIN DH PARAMETERS----- | |
MIIBCAKCAQEA//////////+t+FRYortKmq/cViAnPTzx2LnFg84tNpWp4TZBFGQz | |
+8yTnc4kmz75fS/jY2MMddj2gbICrsRhetPfHtXV/WVhJDP1H18GbtCFY2VVPe0a | |
87VXE15/V8k1mE8McODmi3fipona8+/och3xWKE2rec1MKzKT0g6eXq8CrGCsyT7 | |
YdEIqUuyyOP7uWrat2DX9GgdT0Kj3jlN9K5W7edjcrsZCwenyO4KbXCeAvzhzffi | |
7MA0BM0oNC9hkXL+nOmFg/+OTxIy7vKBg8P+OxtMb61zO7X8vC7CIAXFjvGDfRaD | |
ssbzSibBsu/6iGtCOGEoXJf//////////wIBAg== | |
-----END DH PARAMETERS-----' > /etc/openvpn/dh.pem | |
# Generate server.conf | |
echo "port $PORT | |
proto $PROTOCOL | |
dev tun | |
sndbuf 0 | |
rcvbuf 0 | |
ca ca.crt | |
cert server.crt | |
key server.key | |
dh dh.pem | |
auth SHA512 | |
tls-auth ta.key 0 | |
topology subnet | |
server 10.8.0.0 255.255.255.0 | |
ifconfig-pool-persist ipp.txt" > /etc/openvpn/server.conf | |
echo 'push "redirect-gateway def1 bypass-dhcp"' >> /etc/openvpn/server.conf | |
# DNS | |
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 line; do | |
echo "push \"dhcp-option DNS $line\"" >> /etc/openvpn/server.conf | |
done | |
;; | |
2) | |
echo 'push "dhcp-option DNS 1.1.1.1"' >> /etc/openvpn/server.conf | |
echo 'push "dhcp-option DNS 1.0.0.1"' >> /etc/openvpn/server.conf | |
;; | |
3) | |
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 | |
;; | |
4) | |
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) | |
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 | |
echo "keepalive 10 120 | |
cipher AES-256-CBC | |
user nobody | |
group $GROUPNAME | |
persist-key | |
persist-tun | |
status openvpn-status.log | |
verb 3 | |
crl-verify crl.pem" >> /etc/openvpn/server.conf | |
# Enable net.ipv4.ip_forward for the system | |
echo 'net.ipv4.ip_forward=1' > /etc/sysctl.d/30-openvpn-forward.conf | |
# Enable without waiting for a reboot or service restart | |
echo 1 > /proc/sys/net/ipv4/ip_forward | |
if pgrep firewalld; then | |
# Using both permanent and not permanent rules to avoid a firewalld | |
# reload. | |
# We don't use --add-service=openvpn because that would only work with | |
# 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 | |
# If SELinux is enabled and a custom port was selected, we need this | |
if sestatus 2>/dev/null | grep "Current mode" | grep -q "enforcing" && [[ "$PORT" != '1194' ]]; then | |
# Install semanage if not already present | |
if ! hash semanage 2>/dev/null; then | |
yum install policycoreutils-python -y | |
fi | |
semanage port -a -t openvpn_port_t -p $PROTOCOL $PORT | |
fi | |
# And finally, restart OpenVPN | |
if [[ "$OS" = 'debian' ]]; then | |
# Little hack to check for systemd | |
if pgrep systemd-journal; then | |
systemctl restart [email protected] | |
else | |
/etc/init.d/openvpn restart | |
fi | |
else | |
if pgrep systemd-journal; then | |
systemctl restart [email protected] | |
systemctl enable [email protected] | |
else | |
service openvpn restart | |
chkconfig openvpn on | |
fi | |
fi | |
# If the server is behind a NAT, use the correct IP address | |
if [[ "$PUBLICIP" != "" ]]; then | |
IP=$PUBLICIP | |
fi | |
# client-common.txt is created so we have a template to add further users later | |
echo "client | |
dev tun | |
proto $PROTOCOL | |
sndbuf 0 | |
rcvbuf 0 | |
remote $IP $PORT | |
resolv-retry infinite | |
nobind | |
persist-key | |
persist-tun | |
remote-cert-tls server | |
auth SHA512 | |
cipher AES-256-CBC | |
setenv opt block-outside-dns | |
key-direction 1 | |
verb 3" > /etc/openvpn/client-common.txt | |
# Generates the custom client.ovpn | |
newclient "$CLIENT" | |
echo | |
echo "Finished!" | |
echo | |
echo "Your client configuration is available at:" ~/"$CLIENT.ovpn" | |
echo "If you want to add more clients, you simply need to run this script again!" | |
fi |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment