-
-
Save 0xBADCA7/39ca4b0edfa74de71d11439e55e4332d to your computer and use it in GitHub Desktop.
This file contains hidden or 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 | |
# Very secure OpenVPN server installer for CentOS | |
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 | |
if [[ -e /etc/centos-release ]]; then | |
OS=centos | |
RCLOCAL='/etc/rc.d/rc.local' | |
SYSCTL='/etc/sysctl.conf' | |
# Needed for CentOS 7 | |
chmod +x /etc/rc.d/rc.local | |
else | |
echo "Looks like you aren't running this installer on a CentOS system" | |
exit 4 | |
fi | |
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/keys/ca.crt >> $homeDir/$1.ovpn | |
echo "</ca>" >> $homeDir/$1.ovpn | |
echo "<cert>" >> $homeDir/$1.ovpn | |
cat /etc/openvpn/easy-rsa/keys/$1.crt >> $homeDir/$1.ovpn | |
echo "</cert>" >> $homeDir/$1.ovpn | |
echo "<key>" >> $homeDir/$1.ovpn | |
cat /etc/openvpn/easy-rsa/keys/$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) | |
if [[ "$IP" = "" ]]; then | |
IP=$(curl -s https://api.ipify.org) | |
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 | |
while : | |
do | |
clear | |
echo "OpenVPN-install (github.com/Angristan/OpenVPN-install)" | |
echo "" | |
echo "Looks like OpenVPN is already installed" | |
echo "" | |
echo "What do you want to do?" | |
echo " 1) Add a cert for a new user" | |
echo " 2) Revoke existing user cert" | |
echo " 3) Exit" | |
read -p "Select an option [1-3]: " option | |
case $option in | |
1) | |
echo "" | |
echo "Tell me a name for the client cert" | |
echo "Please, use one word only, no special characters" | |
read -p "Client name: " -e -i client CLIENT | |
{ | |
cd /etc/openvpn/easy-rsa/ | |
source ./vars | |
./build-key --batch $CLIENT | |
newclient "$CLIENT" | |
} &> /dev/null | |
echo "" | |
echo "Client $CLIENT added, certs available at $homeDir/$CLIENT.ovpn" | |
exit | |
;; | |
2) | |
NUMBEROFCLIENTS=$(tail -n +2 /etc/openvpn/easy-rsa/keys/index.txt | grep -c "^V") | |
if [[ "$NUMBEROFCLIENTS" = '0' ]]; then | |
echo "" | |
echo "You have no existing clients!" | |
exit 5 | |
fi | |
echo "" | |
echo "Select the existing client certificate you want to revoke" | |
tail -n +2 /etc/openvpn/easy-rsa/keys/index.txt | grep "^V" | cut -d '=' -f 7 | cut -f1 -d"/" | 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/keys/index.txt | grep "^V" | cut -d '=' -f 7 | cut -f1 -d"/" | sed -n "$CLIENTNUMBER"P ) | |
cd /etc/openvpn/easy-rsa/ | |
./revoke-full $CLIENT | |
rm -rf keys/$CLIENT.key | |
rm -rf keys/$CLIENT.crt | |
rm -rf /etc/openvpn/crl.pem | |
cp /etc/openvpn/easy-rsa/keys/crl.pem /etc/openvpn/crl.pem | |
chmod 644 /etc/openvpn/crl.pem | |
} &> /dev/null | |
echo "" | |
echo "Certificate for client $CLIENT revoked" | |
echo "Exiting..." | |
exit | |
;; | |
3) exit;; | |
esac | |
done | |
else | |
clear | |
echo "Welcome to the secure OpenVPN 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 "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." | |
read -p "IP address: " -e -i $IP IP | |
echo "" | |
echo "What port do you want for OpenVPN?" | |
read -p "Port: " -e -i 1194 PORT | |
echo "" | |
echo "What protocol do you want for OpenVPN?" | |
echo "Unless UDP is blocked, you should not use TCP (unnecessarily slower)" | |
while [[ $PROTOCOL != "UDP" && $PROTOCOL != "TCP" ]]; do | |
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) DNS.WATCH (Germany)" | |
echo " 3) OpenDNS (Anycast: worldwide)" | |
echo " 4) Custom (Specify Later)" | |
while [[ $DNS != "1" && $DNS != "2" && $DNS != "3" && $DNS != "4" ]]; do | |
read -p "DNS [1-4]: " -e -i 1 DNS | |
done | |
if [[ $DNS = "4" ]]; then | |
echo "" | |
echo "Please specify custom DNS:" | |
read -p "Custom DNS 1: " -e DNS1 | |
read -p "Custom DNS 2: " -e DNS2 | |
fi | |
CIPHER="cipher AES-256-CBC" | |
DH_KEY_SIZE="4096" | |
RSA_KEY_SIZE="4096" | |
echo "" | |
echo "Which infos do you want i use for certificates?" | |
read -p "Country Code: " -e -i CC COUNTRY | |
read -p "Province: " -e -i "Your Province" PROVINCE | |
read -p "City: " -e -i YourCity CITY | |
read -p "Organization: " -e -i YourOrg ORG | |
read -p "Email: " -e -i [email protected] EMAIL | |
read -p "Organizational Unit: " -e -i "Security Team" OU | |
read -p "Key Name: " -e -i server KEYNAME | |
echo "" | |
echo "Finally, tell me a name for the client certificate and configuration" | |
while [[ $CLIENT = "" ]]; do | |
echo "Please, use one word only, no special characters" | |
read -p "Client name: " -e -i client CLIENT | |
done | |
echo "" | |
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..." | |
# Install packages | |
yum install epel-release -y | |
yum install openvpn easy-rsa openssl wget ca-certificates curl -y | |
# 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 | |
mkdir /etc/openvpn/easy-rsa | |
cp -rf /usr/share/easy-rsa/2.0/* /etc/openvpn/easy-rsa | |
cd /etc/openvpn/easy-rsa | |
rm -f vars | |
echo " | |
export EASY_RSA=\"\`pwd\`\" | |
export OPENSSL=\"openssl\" | |
export PKCS11TOOL=\"pkcs11-tool\" | |
export GREP=\"grep\" | |
export KEY_CONFIG=\"\`\$EASY_RSA/whichopensslcnf \$EASY_RSA\`\" | |
export KEY_DIR=\"\$EASY_RSA/keys\" | |
export PKCS11_MODULE_PATH=\"dummy\" | |
export PKCS11_PIN=\"dummy\" | |
export KEY_SIZE=$RSA_KEY_SIZE | |
export CA_EXPIRE=3650 | |
export KEY_EXPIRE=3650 | |
export KEY_COUNTRY=\"$COUNTRY\" | |
export KEY_PROVINCE=\"$PROVINCE\" | |
export KEY_CITY=\"$CITY\" | |
export KEY_ORG=\"$ORG\" | |
export KEY_EMAIL=\"$EMAIL\" | |
export KEY_OU=\"$OU\" | |
export KEY_NAME=\"$KEYNAME\" | |
" >> /etc/openvpn/easy-rsa/vars | |
source ./vars | |
./clean-all | |
./build-ca --batch | |
./build-key-server --batch server | |
./build-dh --batch | |
{ | |
./build-key --batch autorevoked | |
./revoke-full autorevoked | |
} &> /dev/null | |
rm -rf keys/autorevoked.key | |
rm -rf keys/autorevoked.crt | |
./build-key --batch $CLIENT | |
# generate tls-auth key | |
openvpn --genkey --secret /etc/openvpn/tls-auth.key | |
# Move all the generated files | |
cd /etc/openvpn/easy-rsa/keys | |
cp dh$RSA_KEY_SIZE.pem ca.crt server.crt server.key 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 [[ "$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) #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 | |
;; | |
3) #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 | |
;; | |
4) #Custom | |
echo "push \"dhcp-option DNS $DNS1\"" >> /etc/openvpn/server.conf | |
if [[ $DNS2 != "" ]]; then | |
echo "push \"dhcp-option DNS $DNS2\"" >> /etc/openvpn/server.conf | |
fi | |
;; | |
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$RSA_KEY_SIZE.pem | |
auth SHA256 | |
$CIPHER | |
tls-server | |
tls-version-min 1.2 | |
tls-cipher TLS-DHE-RSA-WITH-AES-256-GCM-SHA384 | |
status openvpn.log | |
verb 4" >> /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 | |
chmod +x $RCLOCAL | |
# Set NAT for the VPN subnet | |
if firewall-cmd --state | grep "running"; then | |
systemctl unmask firewalld | |
systemctl enable firewalld | |
systemctl start firewalld | |
fi | |
if [[ "$PROTOCOL" = 'UDP' && "$PORT" = '1194' ]]; then | |
firewall-cmd --permanent --zone=public --add-service=openvpn | |
elif [[ "$PROTOCOL" = 'UDP' && "$PORT" != '1194' ]]; then | |
firewall-cmd --permanent --zone=public --add-port=$PORT/udp | |
elif [[ "$PROTOCOL" = 'TCP' ]]; then | |
firewall-cmd --permanent --zone=public --add-port=$PORT/tcp | |
fi | |
firewall-cmd --permanent --zone=public --add-masquerade | |
firewall-cmd --permanent --zone=trusted --add-source=10.8.0.0/24 | |
firewall-cmd --reload | |
# 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 pgrep systemd-journal; then | |
systemctl restart [email protected] | |
systemctl enable [email protected] | |
else | |
service openvpn restart | |
chkconfig openvpn on | |
fi | |
# Try to detect a NATed connection and ask about it to potential LowEndSpirit/Scaleway users | |
EXTERNALIP=$(curl -s https://api.ipify.org) | |
if [[ "$IP" != "$EXTERNALIP" ]]; then | |
echo "" | |
echo "Looks like your server is behind a NAT!" | |
echo "" | |
echo "If your server is NATed I need to know the address that can be used to access it from outside." | |
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 | |
IP=$USEREXTERNALIP | |
fi | |
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 | |
auth SHA256 | |
$CIPHER | |
tls-client | |
tls-version-min 1.2 | |
tls-cipher TLS-DHE-RSA-WITH-AES-256-GCM-SHA384 | |
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 have to run this script another time!" | |
fi | |
exit 0; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment