openvpn-install.sh 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568
  1. #!/bin/bash
  2. #
  3. # https://github.com/Nyr/openvpn-install
  4. #
  5. # Copyright (c) 2013 Nyr. Released under the MIT License.
  6. # Detect Debian users running the script with "sh" instead of bash
  7. if readlink /proc/$$/exe | grep -q "dash"; then
  8. echo 'This installer needs to be run with "bash", not "sh".'
  9. exit
  10. fi
  11. # Discard stdin. Needed when running from an one-liner which includes a newline
  12. read -N 999999 -t 0.001
  13. # Detect OpenVZ 6
  14. if [[ $(uname -r | cut -d "." -f 1) -eq 2 ]]; then
  15. echo "The system is running an old kernel, which is incompatible with this installer."
  16. exit
  17. fi
  18. # Detect OS
  19. # $os_version variables aren't always in use, but are kept here for convenience
  20. if grep -qs "ubuntu" /etc/os-release; then
  21. os="ubuntu"
  22. os_version=$(grep 'VERSION_ID' /etc/os-release | cut -d '"' -f 2 | tr -d '.')
  23. group_name="nogroup"
  24. elif [[ -e /etc/debian_version ]]; then
  25. os="debian"
  26. os_version=$(grep -oE '[0-9]+' /etc/debian_version | head -1)
  27. group_name="nogroup"
  28. elif [[ -e /etc/almalinux-release || -e /etc/rocky-release || -e /etc/centos-release ]]; then
  29. os="centos"
  30. os_version=$(grep -shoE '[0-9]+' /etc/almalinux-release /etc/rocky-release /etc/centos-release | head -1)
  31. group_name="nobody"
  32. elif [[ -e /etc/fedora-release ]]; then
  33. os="fedora"
  34. os_version=$(grep -oE '[0-9]+' /etc/fedora-release | head -1)
  35. group_name="nobody"
  36. else
  37. echo "This installer seems to be running on an unsupported distribution.
  38. Supported distros are Ubuntu, Debian, AlmaLinux, Rocky Linux, CentOS and Fedora."
  39. exit
  40. fi
  41. if [[ "$os" == "ubuntu" && "$os_version" -lt 1804 ]]; then
  42. echo "Ubuntu 18.04 or higher is required to use this installer.
  43. This version of Ubuntu is too old and unsupported."
  44. exit
  45. fi
  46. if [[ "$os" == "debian" && "$os_version" -lt 9 ]]; then
  47. echo "Debian 9 or higher is required to use this installer.
  48. This version of Debian is too old and unsupported."
  49. exit
  50. fi
  51. if [[ "$os" == "centos" && "$os_version" -lt 7 ]]; then
  52. echo "CentOS 7 or higher is required to use this installer.
  53. This version of CentOS is too old and unsupported."
  54. exit
  55. fi
  56. # Detect environments where $PATH does not include the sbin directories
  57. if ! grep -q sbin <<< "$PATH"; then
  58. echo '$PATH does not include sbin. Try using "su -" instead of "su".'
  59. exit
  60. fi
  61. if [[ "$EUID" -ne 0 ]]; then
  62. echo "This installer needs to be run with superuser privileges."
  63. exit
  64. fi
  65. if [[ ! -e /dev/net/tun ]] || ! ( exec 7<>/dev/net/tun ) 2>/dev/null; then
  66. echo "The system does not have the TUN device available.
  67. TUN needs to be enabled before running this installer."
  68. exit
  69. fi
  70. new_client () {
  71. # Generates the custom client.ovpn
  72. {
  73. cat /etc/openvpn/server/client-common.txt
  74. echo "<ca>"
  75. cat /etc/openvpn/server/easy-rsa/pki/ca.crt
  76. echo "</ca>"
  77. echo "<cert>"
  78. sed -ne '/BEGIN CERTIFICATE/,$ p' /etc/openvpn/server/easy-rsa/pki/issued/"$client".crt
  79. echo "</cert>"
  80. echo "<key>"
  81. cat /etc/openvpn/server/easy-rsa/pki/private/"$client".key
  82. echo "</key>"
  83. echo "<tls-crypt>"
  84. sed -ne '/BEGIN OpenVPN Static key/,$ p' /etc/openvpn/server/tc.key
  85. echo "</tls-crypt>"
  86. } > ~/"$client".ovpn
  87. }
  88. if [[ ! -e /etc/openvpn/server/server.conf ]]; then
  89. # Detect some Debian minimal setups where neither wget nor curl are installed
  90. if ! hash wget 2>/dev/null && ! hash curl 2>/dev/null; then
  91. echo "Wget is required to use this installer."
  92. read -n1 -r -p "Press any key to install Wget and continue..."
  93. apt-get update
  94. apt-get install -y wget
  95. fi
  96. clear
  97. echo 'Welcome to this OpenVPN road warrior installer!'
  98. # If system has a single IPv4, it is selected automatically. Else, ask the user
  99. if [[ $(ip -4 addr | grep inet | grep -vEc '127(\.[0-9]{1,3}){3}') -eq 1 ]]; then
  100. ip=$(ip -4 addr | grep inet | grep -vE '127(\.[0-9]{1,3}){3}' | cut -d '/' -f 1 | grep -oE '[0-9]{1,3}(\.[0-9]{1,3}){3}')
  101. else
  102. number_of_ip=$(ip -4 addr | grep inet | grep -vEc '127(\.[0-9]{1,3}){3}')
  103. echo
  104. echo "Which IPv4 address should be used?"
  105. ip -4 addr | grep inet | grep -vE '127(\.[0-9]{1,3}){3}' | cut -d '/' -f 1 | grep -oE '[0-9]{1,3}(\.[0-9]{1,3}){3}' | nl -s ') '
  106. read -p "IPv4 address [1]: " ip_number
  107. until [[ -z "$ip_number" || "$ip_number" =~ ^[0-9]+$ && "$ip_number" -le "$number_of_ip" ]]; do
  108. echo "$ip_number: invalid selection."
  109. read -p "IPv4 address [1]: " ip_number
  110. done
  111. [[ -z "$ip_number" ]] && ip_number="1"
  112. ip=$(ip -4 addr | grep inet | grep -vE '127(\.[0-9]{1,3}){3}' | cut -d '/' -f 1 | grep -oE '[0-9]{1,3}(\.[0-9]{1,3}){3}' | sed -n "$ip_number"p)
  113. fi
  114. # If $ip is a private IP address, the server must be behind NAT
  115. if echo "$ip" | grep -qE '^(10\.|172\.1[6789]\.|172\.2[0-9]\.|172\.3[01]\.|192\.168)'; then
  116. echo
  117. echo "This server is behind NAT. What is the public IPv4 address or hostname?"
  118. # Get public IP and sanitize with grep
  119. get_public_ip=$(grep -m 1 -oE '^[0-9]{1,3}(\.[0-9]{1,3}){3}$' <<< "$(wget -T 10 -t 1 -4qO- "http://ip1.dynupdate.no-ip.com/" || curl -m 10 -4Ls "http://ip1.dynupdate.no-ip.com/")")
  120. read -p "Public IPv4 address / hostname [$get_public_ip]: " public_ip
  121. # If the checkip service is unavailable and user didn't provide input, ask again
  122. until [[ -n "$get_public_ip" || -n "$public_ip" ]]; do
  123. echo "Invalid input."
  124. read -p "Public IPv4 address / hostname: " public_ip
  125. done
  126. [[ -z "$public_ip" ]] && public_ip="$get_public_ip"
  127. fi
  128. # If system has a single IPv6, it is selected automatically
  129. if [[ $(ip -6 addr | grep -c 'inet6 [23]') -eq 1 ]]; then
  130. ip6=$(ip -6 addr | grep 'inet6 [23]' | cut -d '/' -f 1 | grep -oE '([0-9a-fA-F]{0,4}:){1,7}[0-9a-fA-F]{0,4}')
  131. fi
  132. # If system has multiple IPv6, ask the user to select one
  133. if [[ $(ip -6 addr | grep -c 'inet6 [23]') -gt 1 ]]; then
  134. number_of_ip6=$(ip -6 addr | grep -c 'inet6 [23]')
  135. echo
  136. echo "Which IPv6 address should be used?"
  137. ip -6 addr | grep 'inet6 [23]' | cut -d '/' -f 1 | grep -oE '([0-9a-fA-F]{0,4}:){1,7}[0-9a-fA-F]{0,4}' | nl -s ') '
  138. read -p "IPv6 address [1]: " ip6_number
  139. until [[ -z "$ip6_number" || "$ip6_number" =~ ^[0-9]+$ && "$ip6_number" -le "$number_of_ip6" ]]; do
  140. echo "$ip6_number: invalid selection."
  141. read -p "IPv6 address [1]: " ip6_number
  142. done
  143. [[ -z "$ip6_number" ]] && ip6_number="1"
  144. ip6=$(ip -6 addr | grep 'inet6 [23]' | cut -d '/' -f 1 | grep -oE '([0-9a-fA-F]{0,4}:){1,7}[0-9a-fA-F]{0,4}' | sed -n "$ip6_number"p)
  145. fi
  146. echo
  147. echo "Which protocol should OpenVPN use?"
  148. echo " 1) UDP (recommended)"
  149. echo " 2) TCP"
  150. read -p "Protocol [1]: " protocol
  151. until [[ -z "$protocol" || "$protocol" =~ ^[12]$ ]]; do
  152. echo "$protocol: invalid selection."
  153. read -p "Protocol [1]: " protocol
  154. done
  155. case "$protocol" in
  156. 1|"")
  157. protocol=udp
  158. ;;
  159. 2)
  160. protocol=tcp
  161. ;;
  162. esac
  163. echo
  164. echo "What port should OpenVPN listen to?"
  165. read -p "Port [1194]: " port
  166. until [[ -z "$port" || "$port" =~ ^[0-9]+$ && "$port" -le 65535 ]]; do
  167. echo "$port: invalid port."
  168. read -p "Port [1194]: " port
  169. done
  170. [[ -z "$port" ]] && port="1194"
  171. echo
  172. echo "Select a DNS server for the clients:"
  173. echo " 1) Current system resolvers"
  174. echo " 2) Google"
  175. echo " 3) 1.1.1.1"
  176. echo " 4) OpenDNS"
  177. echo " 5) Quad9"
  178. echo " 6) AdGuard"
  179. read -p "DNS server [1]: " dns
  180. until [[ -z "$dns" || "$dns" =~ ^[1-6]$ ]]; do
  181. echo "$dns: invalid selection."
  182. read -p "DNS server [1]: " dns
  183. done
  184. echo
  185. echo "Enter a name for the first client:"
  186. read -p "Name [client]: " unsanitized_client
  187. # Allow a limited set of characters to avoid conflicts
  188. client=$(sed 's/[^0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_-]/_/g' <<< "$unsanitized_client")
  189. [[ -z "$client" ]] && client="client"
  190. echo
  191. echo "OpenVPN installation is ready to begin."
  192. # Install a firewall if firewalld or iptables are not already available
  193. if ! systemctl is-active --quiet firewalld.service && ! hash iptables 2>/dev/null; then
  194. if [[ "$os" == "centos" || "$os" == "fedora" ]]; then
  195. firewall="firewalld"
  196. # We don't want to silently enable firewalld, so we give a subtle warning
  197. # If the user continues, firewalld will be installed and enabled during setup
  198. echo "firewalld, which is required to manage routing tables, will also be installed."
  199. elif [[ "$os" == "debian" || "$os" == "ubuntu" ]]; then
  200. # iptables is way less invasive than firewalld so no warning is given
  201. firewall="iptables"
  202. fi
  203. fi
  204. read -n1 -r -p "Press any key to continue..."
  205. # If running inside a container, disable LimitNPROC to prevent conflicts
  206. if systemd-detect-virt -cq; then
  207. mkdir /etc/systemd/system/openvpn-server@server.service.d/ 2>/dev/null
  208. echo "[Service]
  209. LimitNPROC=infinity" > /etc/systemd/system/openvpn-server@server.service.d/disable-limitnproc.conf
  210. fi
  211. if [[ "$os" = "debian" || "$os" = "ubuntu" ]]; then
  212. apt-get update
  213. apt-get install -y openvpn openssl ca-certificates $firewall
  214. elif [[ "$os" = "centos" ]]; then
  215. yum install -y epel-release
  216. yum install -y openvpn openssl ca-certificates tar $firewall
  217. else
  218. # Else, OS must be Fedora
  219. dnf install -y openvpn openssl ca-certificates tar $firewall
  220. fi
  221. # If firewalld was just installed, enable it
  222. if [[ "$firewall" == "firewalld" ]]; then
  223. systemctl enable --now firewalld.service
  224. fi
  225. # Get easy-rsa
  226. easy_rsa_url='https://github.com/OpenVPN/easy-rsa/releases/download/v3.0.8/EasyRSA-3.0.8.tgz'
  227. mkdir -p /etc/openvpn/server/easy-rsa/
  228. { wget -qO- "$easy_rsa_url" 2>/dev/null || curl -sL "$easy_rsa_url" ; } | tar xz -C /etc/openvpn/server/easy-rsa/ --strip-components 1
  229. chown -R root:root /etc/openvpn/server/easy-rsa/
  230. cd /etc/openvpn/server/easy-rsa/
  231. # Create the PKI, set up the CA and the server and client certificates
  232. ./easyrsa init-pki
  233. ./easyrsa --batch build-ca nopass
  234. EASYRSA_CERT_EXPIRE=3650 ./easyrsa build-server-full server nopass
  235. EASYRSA_CERT_EXPIRE=3650 ./easyrsa build-client-full "$client" nopass
  236. EASYRSA_CRL_DAYS=3650 ./easyrsa gen-crl
  237. # Move the stuff we need
  238. cp pki/ca.crt pki/private/ca.key pki/issued/server.crt pki/private/server.key pki/crl.pem /etc/openvpn/server
  239. # CRL is read with each client connection, while OpenVPN is dropped to nobody
  240. chown nobody:"$group_name" /etc/openvpn/server/crl.pem
  241. # Without +x in the directory, OpenVPN can't run a stat() on the CRL file
  242. chmod o+x /etc/openvpn/server/
  243. # Generate key for tls-crypt
  244. openvpn --genkey --secret /etc/openvpn/server/tc.key
  245. # Create the DH parameters file using the predefined ffdhe2048 group
  246. echo '-----BEGIN DH PARAMETERS-----
  247. MIIBCAKCAQEA//////////+t+FRYortKmq/cViAnPTzx2LnFg84tNpWp4TZBFGQz
  248. +8yTnc4kmz75fS/jY2MMddj2gbICrsRhetPfHtXV/WVhJDP1H18GbtCFY2VVPe0a
  249. 87VXE15/V8k1mE8McODmi3fipona8+/och3xWKE2rec1MKzKT0g6eXq8CrGCsyT7
  250. YdEIqUuyyOP7uWrat2DX9GgdT0Kj3jlN9K5W7edjcrsZCwenyO4KbXCeAvzhzffi
  251. 7MA0BM0oNC9hkXL+nOmFg/+OTxIy7vKBg8P+OxtMb61zO7X8vC7CIAXFjvGDfRaD
  252. ssbzSibBsu/6iGtCOGEoXJf//////////wIBAg==
  253. -----END DH PARAMETERS-----' > /etc/openvpn/server/dh.pem
  254. # Generate server.conf
  255. echo "local $ip
  256. port $port
  257. proto $protocol
  258. dev tun
  259. ca ca.crt
  260. cert server.crt
  261. key server.key
  262. dh dh.pem
  263. auth SHA512
  264. tls-crypt tc.key
  265. topology subnet
  266. server 10.8.0.0 255.255.255.0" > /etc/openvpn/server/server.conf
  267. # IPv6
  268. if [[ -z "$ip6" ]]; then
  269. echo 'push "redirect-gateway def1 bypass-dhcp"' >> /etc/openvpn/server/server.conf
  270. else
  271. echo 'server-ipv6 fddd:1194:1194:1194::/64' >> /etc/openvpn/server/server.conf
  272. echo 'push "redirect-gateway def1 ipv6 bypass-dhcp"' >> /etc/openvpn/server/server.conf
  273. fi
  274. echo 'ifconfig-pool-persist ipp.txt' >> /etc/openvpn/server/server.conf
  275. # DNS
  276. case "$dns" in
  277. 1|"")
  278. # Locate the proper resolv.conf
  279. # Needed for systems running systemd-resolved
  280. if grep -q '^nameserver 127.0.0.53' "/etc/resolv.conf"; then
  281. resolv_conf="/run/systemd/resolve/resolv.conf"
  282. else
  283. resolv_conf="/etc/resolv.conf"
  284. fi
  285. # Obtain the resolvers from resolv.conf and use them for OpenVPN
  286. grep -v '^#\|^;' "$resolv_conf" | grep '^nameserver' | grep -oE '[0-9]{1,3}(\.[0-9]{1,3}){3}' | while read line; do
  287. echo "push \"dhcp-option DNS $line\"" >> /etc/openvpn/server/server.conf
  288. done
  289. ;;
  290. 2)
  291. echo 'push "dhcp-option DNS 8.8.8.8"' >> /etc/openvpn/server/server.conf
  292. echo 'push "dhcp-option DNS 8.8.4.4"' >> /etc/openvpn/server/server.conf
  293. ;;
  294. 3)
  295. echo 'push "dhcp-option DNS 1.1.1.1"' >> /etc/openvpn/server/server.conf
  296. echo 'push "dhcp-option DNS 1.0.0.1"' >> /etc/openvpn/server/server.conf
  297. ;;
  298. 4)
  299. echo 'push "dhcp-option DNS 208.67.222.222"' >> /etc/openvpn/server/server.conf
  300. echo 'push "dhcp-option DNS 208.67.220.220"' >> /etc/openvpn/server/server.conf
  301. ;;
  302. 5)
  303. echo 'push "dhcp-option DNS 9.9.9.9"' >> /etc/openvpn/server/server.conf
  304. echo 'push "dhcp-option DNS 149.112.112.112"' >> /etc/openvpn/server/server.conf
  305. ;;
  306. 6)
  307. echo 'push "dhcp-option DNS 94.140.14.14"' >> /etc/openvpn/server/server.conf
  308. echo 'push "dhcp-option DNS 94.140.15.15"' >> /etc/openvpn/server/server.conf
  309. ;;
  310. esac
  311. echo "keepalive 10 120
  312. cipher AES-256-CBC
  313. user nobody
  314. group $group_name
  315. persist-key
  316. persist-tun
  317. verb 3
  318. crl-verify crl.pem" >> /etc/openvpn/server/server.conf
  319. if [[ "$protocol" = "udp" ]]; then
  320. echo "explicit-exit-notify" >> /etc/openvpn/server/server.conf
  321. fi
  322. # Enable net.ipv4.ip_forward for the system
  323. echo 'net.ipv4.ip_forward=1' > /etc/sysctl.d/99-openvpn-forward.conf
  324. # Enable without waiting for a reboot or service restart
  325. echo 1 > /proc/sys/net/ipv4/ip_forward
  326. if [[ -n "$ip6" ]]; then
  327. # Enable net.ipv6.conf.all.forwarding for the system
  328. echo "net.ipv6.conf.all.forwarding=1" >> /etc/sysctl.d/99-openvpn-forward.conf
  329. # Enable without waiting for a reboot or service restart
  330. echo 1 > /proc/sys/net/ipv6/conf/all/forwarding
  331. fi
  332. if systemctl is-active --quiet firewalld.service; then
  333. # Using both permanent and not permanent rules to avoid a firewalld
  334. # reload.
  335. # We don't use --add-service=openvpn because that would only work with
  336. # the default port and protocol.
  337. firewall-cmd --add-port="$port"/"$protocol"
  338. firewall-cmd --zone=trusted --add-source=10.8.0.0/24
  339. firewall-cmd --permanent --add-port="$port"/"$protocol"
  340. firewall-cmd --permanent --zone=trusted --add-source=10.8.0.0/24
  341. # Set NAT for the VPN subnet
  342. 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"
  343. 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"
  344. if [[ -n "$ip6" ]]; then
  345. firewall-cmd --zone=trusted --add-source=fddd:1194:1194:1194::/64
  346. firewall-cmd --permanent --zone=trusted --add-source=fddd:1194:1194:1194::/64
  347. firewall-cmd --direct --add-rule ipv6 nat POSTROUTING 0 -s fddd:1194:1194:1194::/64 ! -d fddd:1194:1194:1194::/64 -j SNAT --to "$ip6"
  348. firewall-cmd --permanent --direct --add-rule ipv6 nat POSTROUTING 0 -s fddd:1194:1194:1194::/64 ! -d fddd:1194:1194:1194::/64 -j SNAT --to "$ip6"
  349. fi
  350. else
  351. # Create a service to set up persistent iptables rules
  352. iptables_path=$(command -v iptables)
  353. ip6tables_path=$(command -v ip6tables)
  354. # nf_tables is not available as standard in OVZ kernels. So use iptables-legacy
  355. # if we are in OVZ, with a nf_tables backend and iptables-legacy is available.
  356. if [[ $(systemd-detect-virt) == "openvz" ]] && readlink -f "$(command -v iptables)" | grep -q "nft" && hash iptables-legacy 2>/dev/null; then
  357. iptables_path=$(command -v iptables-legacy)
  358. ip6tables_path=$(command -v ip6tables-legacy)
  359. fi
  360. echo "[Unit]
  361. Before=network.target
  362. [Service]
  363. Type=oneshot
  364. ExecStart=$iptables_path -t nat -A POSTROUTING -s 10.8.0.0/24 ! -d 10.8.0.0/24 -j SNAT --to $ip
  365. ExecStart=$iptables_path -I INPUT -p $protocol --dport $port -j ACCEPT
  366. ExecStart=$iptables_path -I FORWARD -s 10.8.0.0/24 -j ACCEPT
  367. ExecStart=$iptables_path -I FORWARD -m state --state RELATED,ESTABLISHED -j ACCEPT
  368. ExecStop=$iptables_path -t nat -D POSTROUTING -s 10.8.0.0/24 ! -d 10.8.0.0/24 -j SNAT --to $ip
  369. ExecStop=$iptables_path -D INPUT -p $protocol --dport $port -j ACCEPT
  370. ExecStop=$iptables_path -D FORWARD -s 10.8.0.0/24 -j ACCEPT
  371. ExecStop=$iptables_path -D FORWARD -m state --state RELATED,ESTABLISHED -j ACCEPT" > /etc/systemd/system/openvpn-iptables.service
  372. if [[ -n "$ip6" ]]; then
  373. echo "ExecStart=$ip6tables_path -t nat -A POSTROUTING -s fddd:1194:1194:1194::/64 ! -d fddd:1194:1194:1194::/64 -j SNAT --to $ip6
  374. ExecStart=$ip6tables_path -I FORWARD -s fddd:1194:1194:1194::/64 -j ACCEPT
  375. ExecStart=$ip6tables_path -I FORWARD -m state --state RELATED,ESTABLISHED -j ACCEPT
  376. ExecStop=$ip6tables_path -t nat -D POSTROUTING -s fddd:1194:1194:1194::/64 ! -d fddd:1194:1194:1194::/64 -j SNAT --to $ip6
  377. ExecStop=$ip6tables_path -D FORWARD -s fddd:1194:1194:1194::/64 -j ACCEPT
  378. ExecStop=$ip6tables_path -D FORWARD -m state --state RELATED,ESTABLISHED -j ACCEPT" >> /etc/systemd/system/openvpn-iptables.service
  379. fi
  380. echo "RemainAfterExit=yes
  381. [Install]
  382. WantedBy=multi-user.target" >> /etc/systemd/system/openvpn-iptables.service
  383. systemctl enable --now openvpn-iptables.service
  384. fi
  385. # If SELinux is enabled and a custom port was selected, we need this
  386. if sestatus 2>/dev/null | grep "Current mode" | grep -q "enforcing" && [[ "$port" != 1194 ]]; then
  387. # Install semanage if not already present
  388. if ! hash semanage 2>/dev/null; then
  389. if [[ "$os_version" -eq 7 ]]; then
  390. # Centos 7
  391. yum install -y policycoreutils-python
  392. else
  393. # CentOS 8 or Fedora
  394. dnf install -y policycoreutils-python-utils
  395. fi
  396. fi
  397. semanage port -a -t openvpn_port_t -p "$protocol" "$port"
  398. fi
  399. # If the server is behind NAT, use the correct IP address
  400. [[ -n "$public_ip" ]] && ip="$public_ip"
  401. # client-common.txt is created so we have a template to add further users later
  402. echo "client
  403. dev tun
  404. proto $protocol
  405. remote $ip $port
  406. resolv-retry infinite
  407. nobind
  408. persist-key
  409. persist-tun
  410. remote-cert-tls server
  411. auth SHA512
  412. cipher AES-256-CBC
  413. ignore-unknown-option block-outside-dns
  414. block-outside-dns
  415. verb 3" > /etc/openvpn/server/client-common.txt
  416. # Enable and start the OpenVPN service
  417. systemctl enable --now openvpn-server@server.service
  418. # Generates the custom client.ovpn
  419. new_client
  420. echo
  421. echo "Finished!"
  422. echo
  423. echo "The client configuration is available in:" ~/"$client.ovpn"
  424. echo "New clients can be added by running this script again."
  425. else
  426. clear
  427. echo "OpenVPN is already installed."
  428. echo
  429. echo "Select an option:"
  430. echo " 1) Add a new client"
  431. echo " 2) Revoke an existing client"
  432. echo " 3) Remove OpenVPN"
  433. echo " 4) Exit"
  434. read -p "Option: " option
  435. until [[ "$option" =~ ^[1-4]$ ]]; do
  436. echo "$option: invalid selection."
  437. read -p "Option: " option
  438. done
  439. case "$option" in
  440. 1)
  441. echo
  442. echo "Provide a name for the client:"
  443. read -p "Name: " unsanitized_client
  444. client=$(sed 's/[^0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_-]/_/g' <<< "$unsanitized_client")
  445. while [[ -z "$client" || -e /etc/openvpn/server/easy-rsa/pki/issued/"$client".crt ]]; do
  446. echo "$client: invalid name."
  447. read -p "Name: " unsanitized_client
  448. client=$(sed 's/[^0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_-]/_/g' <<< "$unsanitized_client")
  449. done
  450. cd /etc/openvpn/server/easy-rsa/
  451. EASYRSA_CERT_EXPIRE=3650 ./easyrsa build-client-full "$client" nopass
  452. # Generates the custom client.ovpn
  453. new_client
  454. echo
  455. echo "$client added. Configuration available in:" ~/"$client.ovpn"
  456. exit
  457. ;;
  458. 2)
  459. # This option could be documented a bit better and maybe even be simplified
  460. # ...but what can I say, I want some sleep too
  461. number_of_clients=$(tail -n +2 /etc/openvpn/server/easy-rsa/pki/index.txt | grep -c "^V")
  462. if [[ "$number_of_clients" = 0 ]]; then
  463. echo
  464. echo "There are no existing clients!"
  465. exit
  466. fi
  467. echo
  468. echo "Select the client to revoke:"
  469. tail -n +2 /etc/openvpn/server/easy-rsa/pki/index.txt | grep "^V" | cut -d '=' -f 2 | nl -s ') '
  470. read -p "Client: " client_number
  471. until [[ "$client_number" =~ ^[0-9]+$ && "$client_number" -le "$number_of_clients" ]]; do
  472. echo "$client_number: invalid selection."
  473. read -p "Client: " client_number
  474. done
  475. client=$(tail -n +2 /etc/openvpn/server/easy-rsa/pki/index.txt | grep "^V" | cut -d '=' -f 2 | sed -n "$client_number"p)
  476. echo
  477. read -p "Confirm $client revocation? [y/N]: " revoke
  478. until [[ "$revoke" =~ ^[yYnN]*$ ]]; do
  479. echo "$revoke: invalid selection."
  480. read -p "Confirm $client revocation? [y/N]: " revoke
  481. done
  482. if [[ "$revoke" =~ ^[yY]$ ]]; then
  483. cd /etc/openvpn/server/easy-rsa/
  484. ./easyrsa --batch revoke "$client"
  485. EASYRSA_CRL_DAYS=3650 ./easyrsa gen-crl
  486. rm -f /etc/openvpn/server/crl.pem
  487. cp /etc/openvpn/server/easy-rsa/pki/crl.pem /etc/openvpn/server/crl.pem
  488. # CRL is read with each client connection, when OpenVPN is dropped to nobody
  489. chown nobody:"$group_name" /etc/openvpn/server/crl.pem
  490. echo
  491. echo "$client revoked!"
  492. else
  493. echo
  494. echo "$client revocation aborted!"
  495. fi
  496. exit
  497. ;;
  498. 3)
  499. echo
  500. read -p "Confirm OpenVPN removal? [y/N]: " remove
  501. until [[ "$remove" =~ ^[yYnN]*$ ]]; do
  502. echo "$remove: invalid selection."
  503. read -p "Confirm OpenVPN removal? [y/N]: " remove
  504. done
  505. if [[ "$remove" =~ ^[yY]$ ]]; then
  506. port=$(grep '^port ' /etc/openvpn/server/server.conf | cut -d " " -f 2)
  507. protocol=$(grep '^proto ' /etc/openvpn/server/server.conf | cut -d " " -f 2)
  508. if systemctl is-active --quiet firewalld.service; then
  509. ip=$(firewall-cmd --direct --get-rules ipv4 nat POSTROUTING | grep '\-s 10.8.0.0/24 '"'"'!'"'"' -d 10.8.0.0/24' | grep -oE '[^ ]+$')
  510. # Using both permanent and not permanent rules to avoid a firewalld reload.
  511. firewall-cmd --remove-port="$port"/"$protocol"
  512. firewall-cmd --zone=trusted --remove-source=10.8.0.0/24
  513. firewall-cmd --permanent --remove-port="$port"/"$protocol"
  514. firewall-cmd --permanent --zone=trusted --remove-source=10.8.0.0/24
  515. 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"
  516. 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"
  517. if grep -qs "server-ipv6" /etc/openvpn/server/server.conf; then
  518. ip6=$(firewall-cmd --direct --get-rules ipv6 nat POSTROUTING | grep '\-s fddd:1194:1194:1194::/64 '"'"'!'"'"' -d fddd:1194:1194:1194::/64' | grep -oE '[^ ]+$')
  519. firewall-cmd --zone=trusted --remove-source=fddd:1194:1194:1194::/64
  520. firewall-cmd --permanent --zone=trusted --remove-source=fddd:1194:1194:1194::/64
  521. firewall-cmd --direct --remove-rule ipv6 nat POSTROUTING 0 -s fddd:1194:1194:1194::/64 ! -d fddd:1194:1194:1194::/64 -j SNAT --to "$ip6"
  522. firewall-cmd --permanent --direct --remove-rule ipv6 nat POSTROUTING 0 -s fddd:1194:1194:1194::/64 ! -d fddd:1194:1194:1194::/64 -j SNAT --to "$ip6"
  523. fi
  524. else
  525. systemctl disable --now openvpn-iptables.service
  526. rm -f /etc/systemd/system/openvpn-iptables.service
  527. fi
  528. if sestatus 2>/dev/null | grep "Current mode" | grep -q "enforcing" && [[ "$port" != 1194 ]]; then
  529. semanage port -d -t openvpn_port_t -p "$protocol" "$port"
  530. fi
  531. systemctl disable --now openvpn-server@server.service
  532. rm -f /etc/systemd/system/openvpn-server@server.service.d/disable-limitnproc.conf
  533. rm -f /etc/sysctl.d/99-openvpn-forward.conf
  534. if [[ "$os" = "debian" || "$os" = "ubuntu" ]]; then
  535. rm -rf /etc/openvpn/server
  536. apt-get remove --purge -y openvpn
  537. else
  538. # Else, OS must be CentOS or Fedora
  539. yum remove -y openvpn
  540. rm -rf /etc/openvpn/server
  541. fi
  542. echo
  543. echo "OpenVPN removed!"
  544. else
  545. echo
  546. echo "OpenVPN removal aborted!"
  547. fi
  548. exit
  549. ;;
  550. 4)
  551. exit
  552. ;;
  553. esac
  554. fi