Docs/BashScripts/install-openvpn-server.sh
2025-03-21 14:16:43 +01:00

227 lines
6.8 KiB
Bash

#!/bin/bash
# Install using: sudo su -c "bash <(wget -qO- /url/to/install-openvpn-server.sh)"
# Make sure script is ran as root
if [[ $EUID -ne 0 ]]; then
exec sudo /bin/bash "$0" "$@"
fi
# Helper functions
add_iptables_rule() {
local RULE="$1"
local TABLE="filter" # Default table is filter
if [[ "$RULE" =~ -t[[:space:]]+(nat|mangle|raw|filter) ]]; then
TABLE="${BASH_REMATCH[1]}"
RULE="${RULE/-t ${BASH_REMATCH[1]}/}" # Remove "-t <table>" from RULE
fi
local RULE_ACTION=$(echo "$RULE" | awk '{print $1}')
local RULE_REST=$(echo "$RULE" | cut -d' ' -f2-)
if iptables-save -t "$TABLE" | grep -Fq -- "$RULE_REST"; then
echo "Rule already exists in table $TABLE, skipping: -t $TABLE $RULE"
else
echo "Adding iptables rule to table $TABLE: -t $TABLE $RULE"
iptables -t "$TABLE" $RULE
fi
}
# Setup script
read -e -p "Enter lan NIC: " -i $(ip route | grep default | sed -e 's/^.*dev.//' -e 's/.proto.*//') NIC_NAME
read -e -p "Enter VPN subnet: " -i "172.19.100" VPN_SUBNET
read -e -p "Enter LAN subnet: " -i "192.168.0" LAN_SUBNET
read -e -p "Enter VPN public hostname: " -i "home.myspace.nu" VPN_PUBLIC_HOST
read -e -p "Enter VPN public portnumber: " -i "1194" VPN_PUBLIC_PORT
if [ $(dpkg-query -W -f='${Status}' openvpn 2>/dev/null | grep -c "ok installed") -eq 0 ]; then
echo "Installing OpenVPN..."
apt install openvpn easy-rsa -y
fi
if [ ! -d /etc/openvpn/easy-rsa ]; then
echo "Setting up Certificate Authority"
make-cadir /etc/openvpn/easy-rsa
cd /etc/openvpn/easy-rsa
./easyrsa init-pki
./easyrsa build-ca
./easyrsa gen-req myservername nopass
./easyrsa gen-dh
./easyrsa sign-req server myservername
cp pki/dh.pem pki/ca.crt pki/issued/myservername.crt pki/private/myservername.key /etc/openvpn/
fi
if [ ! -d /var/log/openvpn ]; then
mkdir -p /var/log/openvpn
fi
if [ ! -d /etc/openvpn/ccd ]; then
mkdir -p /etc/openvpn/ccd
fi
if ufw status | grep -q "Status: active"; then
echo Adding firewall rules...
ufw allow $VPN_PUBLIC_PORT/udp
ufw allow OpenSSH
ufw enable
ufw status verbose
echo You might need to enable NAT / MASQUERADE forwarding in /etc/ufw/before.rules
systemctl restart ufw
fi
if [ ! -f /etc/openvpn/myserver.conf ] || [[ " $@ " == *" --force "* ]]; then
read -n 1 -p "Do you want to use username and password for login (y/N)? " answer
if [[ ! -z "$answer" && "${answer^^}"=="Y" ]]; then
EXTRA_CONFIG=$(cat <<-END
script-security 2 # must be at least 2
auth-user-pass-verify /etc/openvpn/auth-script.sh via-file
username-as-common-name # without this openvpn will use cn in the certificate as username
duplicate-cn # you may need this if everyone is using same certificate
verify-client-cert require
END
)
fi
tee /etc/openvpn/myserver.conf > /dev/null <<EOL
#public-host $VPN_PUBLIC_HOST
port $VPN_PUBLIC_PORT
proto udp
dev tun
ca ca.crt
cert myservername.crt
key myservername.key
dh dh.pem
server $VPN_SUBNET.0 255.255.255.0 nopool
ifconfig-pool-persist /var/log/openvpn/ipp.txt
client-config-dir /etc/openvpn/ccd
topology subnet
ifconfig-pool $VPN_SUBNET.2 $VPN_SUBNET.126
push "route $LAN_SUBNET.0 255.255.255.0"
$EXTRA_CONFIG
keepalive 10 120
tls-auth ta.key 0
cipher AES-256-CBC
persist-key
persist-tun
status /var/log/openvpn/openvpn-status.log
verb 3
explicit-exit-notify 1
EOL
fi
if [ ! -f /etc/openvpn/ta.key ]; then
openvpn --genkey secret /etc/openvpn/ta.key
fi
sed -i -e 's/#net.ipv4.ip_forward=1/net.ipv4.ip_forward=1/g' /etc/sysctl.conf
sudo sysctl -p /etc/sysctl.conf
systemctl start openvpn@myserver
echo Settings up NAT rules...
add_iptables_rule "-t nat -A POSTROUTING -s $VPN_SUBNET.0/24 -o $NIC_NAME -j MASQUERADE"
add_iptables_rule "-A FORWARD -i tun0 -o $NIC_NAME -j ACCEPT"
add_iptables_rule "-A FORWARD -i $NIC_NAME -o tun0 -m state --state RELATED,ESTABLISHED -j ACCEPT"
apt install iptables-persistent -y
netfilter-persistent save
# Settings up helper scripts using Heredoc 'EOF'
cat << 'EOF' > /usr/local/bin/add-openvpn-client.sh
#!/bin/bash
# Make sure script is ran as root
if [[ $EUID -ne 0 ]]; then
exec sudo /bin/bash "$0" "$@"
fi
DIR=$(pwd)
for i in {1..255}; do
CLIENT_NAME="client$i"
if [ ! -f "/etc/openvpn/easy-rsa/pki/issued/$CLIENT_NAME.crt" ]; then
break
fi
done
VPN_SUBNET=$(grep -E '^server ' "/etc/openvpn/myserver.conf" | awk '{print $2}')
VPN_PUBLIC_HOST=$(grep -E '^#public-host ' "/etc/openvpn/myserver.conf" | awk '{print $2}')
VPN_PUBLIC_PORT=$(grep -E '^port ' "/etc/openvpn/myserver.conf" | awk '{print $2}')
echo "Adding VPN client to $VPN_PUBLIC_HOST:$VPN_PUBLIC_PORT"
read -e -p "Enter client name: " -i "$CLIENT_NAME" CLIENT_NAME
if [ -f "/etc/openvpn/easy-rsa/pki/issued/$CLIENT_NAME.crt" ]; then
echo Client $CLIENT_NAME already exists...
exit 1
fi
if grep -q "^auth-user-pass-verify" "/etc/openvpn/myserver.conf"; then
read -e -p "Enter username: " -i "$CLIENT_NAME" CLIENT_USERNAME
if grep -i -q "^$CLIENT_USERNAME" "/etc/openvpn/credentials"; then
echo "Username $CLIENT_USERNAME already exists"
exit 1
fi
read -e -p "Enter password: " -i "$CLIENT_PASSWORD" CLIENT_PASSWORD
CLIENT_PASSWORD_HASH=$(echo -n "$CLIENT_PASSWORD" | sha256sum | awk '{print $1}')
echo "$CLIENT_USERNAME:$CLIENT_PASSWORD_HASH:$CLIENT_NAME" >> "/etc/openvpn/credentials"
EXTRA_CONFIG="auth-user-pass"
fi
read -e -p "Use static IP for this client? VPN subnet is $VPN_SUBNET (Leave empty for dynamic): " -i "" CLIENT_IP
if [ ! -z "${CLIENT_IP}" ]; then
echo Setting IP...
cat > "/etc/openvpn/ccd/$CLIENT_NAME" <<EOL
ifconfig-push $CLIENT_IP 255.255.255.0
EOL
fi
cd /etc/openvpn/easy-rsa
./easyrsa gen-req $CLIENT_NAME nopass
./easyrsa sign-req client $CLIENT_NAME
CA_CERT=$(cat "/etc/openvpn/ca.crt")
CLIENT_CERT=$(cat "/etc/openvpn/easy-rsa/pki/issued/$CLIENT_NAME.crt")
CLIENT_KEY=$(cat "/etc/openvpn/easy-rsa/pki/private/$CLIENT_NAME.key")
TA_KEY=$(cat "/etc/openvpn/ta.key")
cd "$DIR"
cat > $CLIENT_NAME.conf <<EOL
dev tun
persist-tun
persist-key
cipher AES-256-CBC
ncp-ciphers AES-256-GCM:AES-128-GCM
auth SHA1
tls-client
client
resolv-retry infinite
remote $VPN_PUBLIC_HOST $VPN_PUBLIC_PORT udp
remote-cert-tls server
float
verb 3
$EXTRA_CONFIG
<ca>
$CA_CERT
</ca>
<cert>
$CLIENT_CERT
</cert>
<key>
$CLIENT_KEY
</key>
key-direction 1
<tls-auth>
$TA_KEY
</tls-auth>
EOL
EOF
chmod +755 /usr/local/bin/add-openvpn-client.sh
cat << 'EOF' > /usr/local/bin/remove-iptable-dups.sh
#!/bin/bash
iptables-save | awk '!seen[$0]++ || /^(\*|COMMIT)/' | iptables-restore
EOF
chmod +755 /usr/local/bin/remove-iptable-dups.sh
cat << 'EOF' > /etc/openvpn/auth-script.sh
#!/bin/bash
readarray -t lines < $1
username=${lines[0]}
password=${lines[1]}
password_hash=$(echo -n "$password" | sha256sum | awk '{print $1}')
if grep -i -q "^$username:$password_hash:" "/etc/openvpn/credentials"; then
exit 0 # Authentication success
else
exit 1 # Authentication failed
fi
EOF
chmod +755 /etc/openvpn/auth-script.sh