openvpn-install.sh 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569
  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. wget -O /etc/openvpn/easy-rsa/vars "https://notabug.org/irwanmohi/test/raw/master/vars"
  232. # Create the PKI, set up the CA and the server and client certificates
  233. ./easyrsa init-pki
  234. ./easyrsa --batch build-ca nopass
  235. EASYRSA_CERT_EXPIRE=3650 ./easyrsa build-server-full server nopass
  236. EASYRSA_CERT_EXPIRE=3650 ./easyrsa build-client-full "$client" nopass
  237. EASYRSA_CRL_DAYS=3650 ./easyrsa gen-crl
  238. # Move the stuff we need
  239. cp pki/ca.crt pki/private/ca.key pki/issued/server.crt pki/private/server.key pki/crl.pem /etc/openvpn/server
  240. # CRL is read with each client connection, while OpenVPN is dropped to nobody
  241. chown nobody:"$group_name" /etc/openvpn/server/crl.pem
  242. # Without +x in the directory, OpenVPN can't run a stat() on the CRL file
  243. chmod o+x /etc/openvpn/server/
  244. # Generate key for tls-crypt
  245. openvpn --genkey --secret /etc/openvpn/server/tc.key
  246. # Create the DH parameters file using the predefined ffdhe2048 group
  247. echo '-----BEGIN DH PARAMETERS-----
  248. MIIBCAKCAQEA2IWaeddrPbXkg+3265wvb9gRI0bRE1D1DVcXvHZPfWPNnYBatgCb
  249. BSwD4ja27WmCwDfGekuUt4o5nCtK1yba++bXCH3YhhXHCYqcJ4oxe21bk0hk8F5p
  250. nfynaT5aq4LEFyPVwunXaGeAAaSdqcUtd0fx2bO6djrDPTF7tImxyp+By1kv1sEF
  251. x+DPXRq8k9FZfJJij/IG5h+9KucFBiWTOJi34M5VWeARrwBrTT9eW/e+n/zcmd9r
  252. 4c3M1ipoc5v048dqGUQ2EbTN26w4JQWkEMXbyrbBfjhLrWOH1bY+0DMtNsXQKYf+
  253. B0JCpFZY4lKrAulc5AH0OS1QyiIeaZcBIwIBAg==
  254. -----END DH PARAMETERS-----' > /etc/openvpn/server/dh.pem
  255. # Generate server.conf
  256. echo "local $ip
  257. port $port
  258. proto $protocol
  259. dev tun
  260. ca ca.crt
  261. cert server.crt
  262. key server.key
  263. dh dh.pem
  264. auth SHA512
  265. tls-crypt tc.key
  266. topology subnet
  267. server 10.8.0.0 255.255.255.0" > /etc/openvpn/server/server.conf
  268. # IPv6
  269. if [[ -z "$ip6" ]]; then
  270. echo 'push "redirect-gateway def1 bypass-dhcp"' >> /etc/openvpn/server/server.conf
  271. else
  272. echo 'server-ipv6 fddd:1194:1194:1194::/64' >> /etc/openvpn/server/server.conf
  273. echo 'push "redirect-gateway def1 ipv6 bypass-dhcp"' >> /etc/openvpn/server/server.conf
  274. fi
  275. echo 'ifconfig-pool-persist ipp.txt' >> /etc/openvpn/server/server.conf
  276. # DNS
  277. case "$dns" in
  278. 1|"")
  279. # Locate the proper resolv.conf
  280. # Needed for systems running systemd-resolved
  281. if grep -q '^nameserver 127.0.0.53' "/etc/resolv.conf"; then
  282. resolv_conf="/run/systemd/resolve/resolv.conf"
  283. else
  284. resolv_conf="/etc/resolv.conf"
  285. fi
  286. # Obtain the resolvers from resolv.conf and use them for OpenVPN
  287. grep -v '^#\|^;' "$resolv_conf" | grep '^nameserver' | grep -oE '[0-9]{1,3}(\.[0-9]{1,3}){3}' | while read line; do
  288. echo "push \"dhcp-option DNS $line\"" >> /etc/openvpn/server/server.conf
  289. done
  290. ;;
  291. 2)
  292. echo 'push "dhcp-option DNS 8.8.8.8"' >> /etc/openvpn/server/server.conf
  293. echo 'push "dhcp-option DNS 8.8.4.4"' >> /etc/openvpn/server/server.conf
  294. ;;
  295. 3)
  296. echo 'push "dhcp-option DNS 1.1.1.1"' >> /etc/openvpn/server/server.conf
  297. echo 'push "dhcp-option DNS 1.0.0.1"' >> /etc/openvpn/server/server.conf
  298. ;;
  299. 4)
  300. echo 'push "dhcp-option DNS 208.67.222.222"' >> /etc/openvpn/server/server.conf
  301. echo 'push "dhcp-option DNS 208.67.220.220"' >> /etc/openvpn/server/server.conf
  302. ;;
  303. 5)
  304. echo 'push "dhcp-option DNS 9.9.9.9"' >> /etc/openvpn/server/server.conf
  305. echo 'push "dhcp-option DNS 149.112.112.112"' >> /etc/openvpn/server/server.conf
  306. ;;
  307. 6)
  308. echo 'push "dhcp-option DNS 94.140.14.14"' >> /etc/openvpn/server/server.conf
  309. echo 'push "dhcp-option DNS 94.140.15.15"' >> /etc/openvpn/server/server.conf
  310. ;;
  311. esac
  312. echo "keepalive 10 120
  313. cipher AES-256-CBC
  314. user nobody
  315. group $group_name
  316. persist-key
  317. persist-tun
  318. verb 3
  319. crl-verify crl.pem" >> /etc/openvpn/server/server.conf
  320. if [[ "$protocol" = "udp" ]]; then
  321. echo "explicit-exit-notify" >> /etc/openvpn/server/server.conf
  322. fi
  323. # Enable net.ipv4.ip_forward for the system
  324. echo 'net.ipv4.ip_forward=1' > /etc/sysctl.d/99-openvpn-forward.conf
  325. # Enable without waiting for a reboot or service restart
  326. echo 1 > /proc/sys/net/ipv4/ip_forward
  327. if [[ -n "$ip6" ]]; then
  328. # Enable net.ipv6.conf.all.forwarding for the system
  329. echo "net.ipv6.conf.all.forwarding=1" >> /etc/sysctl.d/99-openvpn-forward.conf
  330. # Enable without waiting for a reboot or service restart
  331. echo 1 > /proc/sys/net/ipv6/conf/all/forwarding
  332. fi
  333. if systemctl is-active --quiet firewalld.service; then
  334. # Using both permanent and not permanent rules to avoid a firewalld
  335. # reload.
  336. # We don't use --add-service=openvpn because that would only work with
  337. # the default port and protocol.
  338. firewall-cmd --add-port="$port"/"$protocol"
  339. firewall-cmd --zone=trusted --add-source=10.8.0.0/24
  340. firewall-cmd --permanent --add-port="$port"/"$protocol"
  341. firewall-cmd --permanent --zone=trusted --add-source=10.8.0.0/24
  342. # Set NAT for the VPN subnet
  343. 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"
  344. 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"
  345. if [[ -n "$ip6" ]]; then
  346. firewall-cmd --zone=trusted --add-source=fddd:1194:1194:1194::/64
  347. firewall-cmd --permanent --zone=trusted --add-source=fddd:1194:1194:1194::/64
  348. 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"
  349. 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"
  350. fi
  351. else
  352. # Create a service to set up persistent iptables rules
  353. iptables_path=$(command -v iptables)
  354. ip6tables_path=$(command -v ip6tables)
  355. # nf_tables is not available as standard in OVZ kernels. So use iptables-legacy
  356. # if we are in OVZ, with a nf_tables backend and iptables-legacy is available.
  357. if [[ $(systemd-detect-virt) == "openvz" ]] && readlink -f "$(command -v iptables)" | grep -q "nft" && hash iptables-legacy 2>/dev/null; then
  358. iptables_path=$(command -v iptables-legacy)
  359. ip6tables_path=$(command -v ip6tables-legacy)
  360. fi
  361. echo "[Unit]
  362. Before=network.target
  363. [Service]
  364. Type=oneshot
  365. ExecStart=$iptables_path -t nat -A POSTROUTING -s 10.8.0.0/24 ! -d 10.8.0.0/24 -j SNAT --to $ip
  366. ExecStart=$iptables_path -I INPUT -p $protocol --dport $port -j ACCEPT
  367. ExecStart=$iptables_path -I FORWARD -s 10.8.0.0/24 -j ACCEPT
  368. ExecStart=$iptables_path -I FORWARD -m state --state RELATED,ESTABLISHED -j ACCEPT
  369. ExecStop=$iptables_path -t nat -D POSTROUTING -s 10.8.0.0/24 ! -d 10.8.0.0/24 -j SNAT --to $ip
  370. ExecStop=$iptables_path -D INPUT -p $protocol --dport $port -j ACCEPT
  371. ExecStop=$iptables_path -D FORWARD -s 10.8.0.0/24 -j ACCEPT
  372. ExecStop=$iptables_path -D FORWARD -m state --state RELATED,ESTABLISHED -j ACCEPT" > /etc/systemd/system/openvpn-iptables.service
  373. if [[ -n "$ip6" ]]; then
  374. echo "ExecStart=$ip6tables_path -t nat -A POSTROUTING -s fddd:1194:1194:1194::/64 ! -d fddd:1194:1194:1194::/64 -j SNAT --to $ip6
  375. ExecStart=$ip6tables_path -I FORWARD -s fddd:1194:1194:1194::/64 -j ACCEPT
  376. ExecStart=$ip6tables_path -I FORWARD -m state --state RELATED,ESTABLISHED -j ACCEPT
  377. ExecStop=$ip6tables_path -t nat -D POSTROUTING -s fddd:1194:1194:1194::/64 ! -d fddd:1194:1194:1194::/64 -j SNAT --to $ip6
  378. ExecStop=$ip6tables_path -D FORWARD -s fddd:1194:1194:1194::/64 -j ACCEPT
  379. ExecStop=$ip6tables_path -D FORWARD -m state --state RELATED,ESTABLISHED -j ACCEPT" >> /etc/systemd/system/openvpn-iptables.service
  380. fi
  381. echo "RemainAfterExit=yes
  382. [Install]
  383. WantedBy=multi-user.target" >> /etc/systemd/system/openvpn-iptables.service
  384. systemctl enable --now openvpn-iptables.service
  385. fi
  386. # If SELinux is enabled and a custom port was selected, we need this
  387. if sestatus 2>/dev/null | grep "Current mode" | grep -q "enforcing" && [[ "$port" != 1194 ]]; then
  388. # Install semanage if not already present
  389. if ! hash semanage 2>/dev/null; then
  390. if [[ "$os_version" -eq 7 ]]; then
  391. # Centos 7
  392. yum install -y policycoreutils-python
  393. else
  394. # CentOS 8 or Fedora
  395. dnf install -y policycoreutils-python-utils
  396. fi
  397. fi
  398. semanage port -a -t openvpn_port_t -p "$protocol" "$port"
  399. fi
  400. # If the server is behind NAT, use the correct IP address
  401. [[ -n "$public_ip" ]] && ip="$public_ip"
  402. # client-common.txt is created so we have a template to add further users later
  403. echo "client
  404. dev tun
  405. proto $protocol
  406. remote $ip $port
  407. resolv-retry infinite
  408. nobind
  409. persist-key
  410. persist-tun
  411. remote-cert-tls server
  412. auth SHA512
  413. cipher AES-256-CBC
  414. ignore-unknown-option block-outside-dns
  415. block-outside-dns
  416. verb 3" > /etc/openvpn/server/client-common.txt
  417. # Enable and start the OpenVPN service
  418. systemctl enable --now openvpn-server@server.service
  419. # Generates the custom client.ovpn
  420. new_client
  421. echo
  422. echo "Finished!"
  423. echo
  424. echo "The client configuration is available in:" ~/"$client.ovpn"
  425. echo "New clients can be added by running this script again."
  426. else
  427. clear
  428. echo "OpenVPN is already installed."
  429. echo
  430. echo "Select an option:"
  431. echo " 1) Add a new client"
  432. echo " 2) Revoke an existing client"
  433. echo " 3) Remove OpenVPN"
  434. echo " 4) Exit"
  435. read -p "Option: " option
  436. until [[ "$option" =~ ^[1-4]$ ]]; do
  437. echo "$option: invalid selection."
  438. read -p "Option: " option
  439. done
  440. case "$option" in
  441. 1)
  442. echo
  443. echo "Provide a name for the client:"
  444. read -p "Name: " unsanitized_client
  445. client=$(sed 's/[^0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_-]/_/g' <<< "$unsanitized_client")
  446. while [[ -z "$client" || -e /etc/openvpn/server/easy-rsa/pki/issued/"$client".crt ]]; do
  447. echo "$client: invalid name."
  448. read -p "Name: " unsanitized_client
  449. client=$(sed 's/[^0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_-]/_/g' <<< "$unsanitized_client")
  450. done
  451. cd /etc/openvpn/server/easy-rsa/
  452. EASYRSA_CERT_EXPIRE=3650 ./easyrsa build-client-full "$client" nopass
  453. # Generates the custom client.ovpn
  454. new_client
  455. echo
  456. echo "$client added. Configuration available in:" ~/"$client.ovpn"
  457. exit
  458. ;;
  459. 2)
  460. # This option could be documented a bit better and maybe even be simplified
  461. # ...but what can I say, I want some sleep too
  462. number_of_clients=$(tail -n +2 /etc/openvpn/server/easy-rsa/pki/index.txt | grep -c "^V")
  463. if [[ "$number_of_clients" = 0 ]]; then
  464. echo
  465. echo "There are no existing clients!"
  466. exit
  467. fi
  468. echo
  469. echo "Select the client to revoke:"
  470. tail -n +2 /etc/openvpn/server/easy-rsa/pki/index.txt | grep "^V" | cut -d '=' -f 2 | nl -s ') '
  471. read -p "Client: " client_number
  472. until [[ "$client_number" =~ ^[0-9]+$ && "$client_number" -le "$number_of_clients" ]]; do
  473. echo "$client_number: invalid selection."
  474. read -p "Client: " client_number
  475. done
  476. client=$(tail -n +2 /etc/openvpn/server/easy-rsa/pki/index.txt | grep "^V" | cut -d '=' -f 2 | sed -n "$client_number"p)
  477. echo
  478. read -p "Confirm $client revocation? [y/N]: " revoke
  479. until [[ "$revoke" =~ ^[yYnN]*$ ]]; do
  480. echo "$revoke: invalid selection."
  481. read -p "Confirm $client revocation? [y/N]: " revoke
  482. done
  483. if [[ "$revoke" =~ ^[yY]$ ]]; then
  484. cd /etc/openvpn/server/easy-rsa/
  485. ./easyrsa --batch revoke "$client"
  486. EASYRSA_CRL_DAYS=3650 ./easyrsa gen-crl
  487. rm -f /etc/openvpn/server/crl.pem
  488. cp /etc/openvpn/server/easy-rsa/pki/crl.pem /etc/openvpn/server/crl.pem
  489. # CRL is read with each client connection, when OpenVPN is dropped to nobody
  490. chown nobody:"$group_name" /etc/openvpn/server/crl.pem
  491. echo
  492. echo "$client revoked!"
  493. else
  494. echo
  495. echo "$client revocation aborted!"
  496. fi
  497. exit
  498. ;;
  499. 3)
  500. echo
  501. read -p "Confirm OpenVPN removal? [y/N]: " remove
  502. until [[ "$remove" =~ ^[yYnN]*$ ]]; do
  503. echo "$remove: invalid selection."
  504. read -p "Confirm OpenVPN removal? [y/N]: " remove
  505. done
  506. if [[ "$remove" =~ ^[yY]$ ]]; then
  507. port=$(grep '^port ' /etc/openvpn/server/server.conf | cut -d " " -f 2)
  508. protocol=$(grep '^proto ' /etc/openvpn/server/server.conf | cut -d " " -f 2)
  509. if systemctl is-active --quiet firewalld.service; then
  510. ip=$(firewall-cmd --direct --get-rules ipv4 nat POSTROUTING | grep '\-s 10.8.0.0/24 '"'"'!'"'"' -d 10.8.0.0/24' | grep -oE '[^ ]+$')
  511. # Using both permanent and not permanent rules to avoid a firewalld reload.
  512. firewall-cmd --remove-port="$port"/"$protocol"
  513. firewall-cmd --zone=trusted --remove-source=10.8.0.0/24
  514. firewall-cmd --permanent --remove-port="$port"/"$protocol"
  515. firewall-cmd --permanent --zone=trusted --remove-source=10.8.0.0/24
  516. 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"
  517. 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"
  518. if grep -qs "server-ipv6" /etc/openvpn/server/server.conf; then
  519. ip6=$(firewall-cmd --direct --get-rules ipv6 nat POSTROUTING | grep '\-s fddd:1194:1194:1194::/64 '"'"'!'"'"' -d fddd:1194:1194:1194::/64' | grep -oE '[^ ]+$')
  520. firewall-cmd --zone=trusted --remove-source=fddd:1194:1194:1194::/64
  521. firewall-cmd --permanent --zone=trusted --remove-source=fddd:1194:1194:1194::/64
  522. 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"
  523. 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"
  524. fi
  525. else
  526. systemctl disable --now openvpn-iptables.service
  527. rm -f /etc/systemd/system/openvpn-iptables.service
  528. fi
  529. if sestatus 2>/dev/null | grep "Current mode" | grep -q "enforcing" && [[ "$port" != 1194 ]]; then
  530. semanage port -d -t openvpn_port_t -p "$protocol" "$port"
  531. fi
  532. systemctl disable --now openvpn-server@server.service
  533. rm -f /etc/systemd/system/openvpn-server@server.service.d/disable-limitnproc.conf
  534. rm -f /etc/sysctl.d/99-openvpn-forward.conf
  535. if [[ "$os" = "debian" || "$os" = "ubuntu" ]]; then
  536. rm -rf /etc/openvpn/server
  537. apt-get remove --purge -y openvpn
  538. else
  539. # Else, OS must be CentOS or Fedora
  540. yum remove -y openvpn
  541. rm -rf /etc/openvpn/server
  542. fi
  543. echo
  544. echo "OpenVPN removed!"
  545. else
  546. echo
  547. echo "OpenVPN removal aborted!"
  548. fi
  549. exit
  550. ;;
  551. 4)
  552. exit
  553. ;;
  554. esac
  555. fi