├── .editorconfig ├── .github ├── FUNDING.yml ├── dependabot.yml ├── issue_template.md ├── linters │ └── .markdown-lint.yml ├── pull_request_template.md └── workflows │ ├── lint.yml │ └── test.yml ├── FAQ.md ├── LICENSE ├── README.md └── openvpn-install.sh /.editorconfig: -------------------------------------------------------------------------------- 1 | [*.sh] 2 | indent_style = tab 3 | indent_size = 4 4 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | ko_fi: stanislas 2 | custom: https://coindrop.to/stanislas 3 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: "github-actions" 4 | directory: "/" 5 | schedule: 6 | interval: "monthly" 7 | -------------------------------------------------------------------------------- /.github/issue_template.md: -------------------------------------------------------------------------------- 1 | <!--- 2 | ❗️ Please read ❗️ 3 | ➡️ If you need help with OpenVPN itself, please use the community forums (https://forums.openvpn.net/) or Stack Overflow (https://stackoverflow.com/questions/tagged/openvpn) 4 | ➡️ For the script, prefer opening a discussion thread for help: https://github.com/angristan/openvpn-install/discussions 5 | 💡 It helps keep the issue tracker clean and focused on bugs and feature requests. 6 | 7 | 🙏 Please include as much information as possible, and make sure you're running the latest version of the script. 8 | ✍️ Please state the Linux distribution you're using and its version, as well as the OpenVPN version. 9 | ✋ For feature requests, remember that this script is meant to be simple and easy to use. If you want to add a lot of options, it's better to fork the project. 10 | ---> 11 | -------------------------------------------------------------------------------- /.github/linters/.markdown-lint.yml: -------------------------------------------------------------------------------- 1 | { "MD013": null, "MD045": null, "MD040": null, "MD036": null } 2 | -------------------------------------------------------------------------------- /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | <!--- 2 | ❗️ Please read ❗️ 3 | ➡️ Please make sure you've followed the guidelines: https://github.com/angristan/openvpn-install#contributing 4 | ✅ Please make sure your changes are tested and working 5 | 🗣️ Please avoid large PRs, and discuss changes in a GitHub issue first 6 | ✋ If the changes are too big and not in line with the project, they will probably be rejected. Remember that this script is meant to be simple and easy to use. 7 | ---> 8 | -------------------------------------------------------------------------------- /.github/workflows/lint.yml: -------------------------------------------------------------------------------- 1 | on: [push, pull_request, workflow_dispatch] 2 | 3 | name: Lint 4 | 5 | jobs: 6 | super-linter: 7 | runs-on: ubuntu-latest 8 | steps: 9 | - name: Checkout Code 10 | uses: actions/checkout@v4 11 | - name: Lint Code Base 12 | uses: github/super-linter@v4.1.0 13 | env: 14 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 15 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | on: 2 | push: 3 | branches: 4 | - master 5 | - ci 6 | workflow_dispatch: 7 | 8 | name: Test 9 | jobs: 10 | install: 11 | runs-on: ubuntu-latest 12 | if: github.repository == 'angristan/openvpn-install' && github.actor == 'angristan' 13 | strategy: 14 | matrix: 15 | os-image: 16 | - debian-11-x64 17 | - debian-12-x64 18 | - ubuntu-22-04-x64 19 | - ubuntu-24-04-x64 20 | - fedora-40-x64 21 | - fedora-41-x64 22 | # - centos-stream-9-x64 # yum oomkill 23 | steps: 24 | - uses: actions/checkout@v4 25 | 26 | - name: Setup doctl 27 | uses: digitalocean/action-doctl@v2 28 | with: 29 | token: ${{ secrets.DIGITALOCEAN_ACCESS_TOKEN }} 30 | 31 | - name: Create server 32 | run: doctl compute droplet create openvpn-action-$GITHUB_RUN_ID-$GITHUB_RUN_NUMBER-${{ matrix.os-image }} --size s-1vcpu-1gb --image ${{ matrix.os-image }} --region lon1 --enable-ipv6 --ssh-keys be:66:76:61:a8:71:93:aa:e3:19:ba:d8:0d:d2:2d:d4 --wait 33 | 34 | - name: Get server ID 35 | run: echo ::set-output name=value::$(doctl compute droplet list -o json | jq -r '.[] | select(.name == "'openvpn-action-$GITHUB_RUN_ID-$GITHUB_RUN_NUMBER-${{ matrix.os-image }}'").id') 36 | id: server_id 37 | 38 | - name: Move server to dedicated project 39 | run: doctl projects resources assign ${{ secrets.DIGITALOCEAN_PROJECT_ID }} --resource=do:droplet:${{ steps.server_id.outputs.value }} 40 | 41 | - name: Wait for server to boot 42 | run: sleep 90 43 | 44 | - name: Get server IP 45 | run: echo ::set-output name=value::$(doctl compute droplet list -o json | jq -r '.[] | select(.name == "'openvpn-action-$GITHUB_RUN_ID-$GITHUB_RUN_NUMBER-${{ matrix.os-image }}'").networks.v4 | .[] | select(.type == "'public'").ip_address') 46 | id: server_ip 47 | 48 | - name: Get server OS 49 | run: echo ::set-output name=value::$(echo ${{ matrix.os-image }} | cut -d '-' -f1) 50 | id: server_os 51 | 52 | - name: Setup remote server (Debian/Ubuntu) 53 | if: steps.server_os.outputs.value == 'debian' || steps.server_os.outputs.value == 'ubuntu' 54 | uses: appleboy/ssh-action@v0.1.6 55 | with: 56 | host: ${{ steps.server_ip.outputs.value }} 57 | username: root 58 | key: ${{ secrets.SSH_KEY }} 59 | script: set -x && apt-get update && apt-get -o DPkg::Lock::Timeout=120 install -y git 60 | 61 | - name: Setup remote server (Fedora) 62 | if: steps.server_os.outputs.value == 'fedora' 63 | uses: appleboy/ssh-action@v0.1.6 64 | with: 65 | host: ${{ steps.server_ip.outputs.value }} 66 | username: root 67 | key: ${{ secrets.SSH_KEY }} 68 | script: set -x && dnf install -y git 69 | 70 | - name: Setup remote server (CentOS) 71 | if: steps.server_os.outputs.value == 'centos' 72 | uses: appleboy/ssh-action@v0.1.6 73 | with: 74 | host: ${{ steps.server_ip.outputs.value }} 75 | username: root 76 | key: ${{ secrets.SSH_KEY }} 77 | script: set -x && yum install -y git 78 | 79 | - name: Download repo and checkout current commit 80 | uses: appleboy/ssh-action@v0.1.6 81 | with: 82 | host: ${{ steps.server_ip.outputs.value }} 83 | username: root 84 | key: ${{ secrets.SSH_KEY }} 85 | script: set -x && git clone https://github.com/angristan/openvpn-install.git && cd openvpn-install && git checkout ${{ github.sha }} 86 | 87 | - name: Run openvpn-install.sh in headless mode 88 | uses: appleboy/ssh-action@v0.1.6 89 | with: 90 | host: ${{ steps.server_ip.outputs.value }} 91 | username: root 92 | key: ${{ secrets.SSH_KEY }} 93 | script: 'set -x && AUTO_INSTALL=y bash -x ~/openvpn-install/openvpn-install.sh && ps aux | grep openvpn | grep -v grep > /dev/null 2>&1 && echo "Success: OpenVPN is running" && exit 0 || echo "Failure: OpenVPN is not running" && exit 1' 94 | 95 | - name: Delete server 96 | run: doctl compute droplet delete -f openvpn-action-$GITHUB_RUN_ID-$GITHUB_RUN_NUMBER-${{ matrix.os-image }} 97 | if: always() 98 | -------------------------------------------------------------------------------- /FAQ.md: -------------------------------------------------------------------------------- 1 | # FAQ 2 | 3 | **Q:** The script has been updated since I installed OpenVPN. How do I update? 4 | 5 | **A:** You can't. Managing updates and new features from the script would require way too much work. Your only solution is to uninstall OpenVPN and reinstall with the updated script. 6 | 7 | You can, of course, it's even recommended, update the `openvpn` package with your package manager. 8 | 9 | --- 10 | 11 | **Q:** How do I check for DNS leaks? 12 | 13 | **A:** Go to [browserleaks.com](https://browserleaks.com/dns) or [ipleak.net](https://ipleak.net/) (both perform IPv4 and IPv6 check) with your browser. Your IP should not show up (test without and without the VPN). The DNS servers should be the ones you selected during the setup, not your IP address nor your ISP's DNS servers' addresses. 14 | 15 | --- 16 | 17 | **Q:** How do I fix DNS leaks? 18 | 19 | **A:** On Windows 10 DNS leaks are blocked by default with the `block-outside-dns` option. 20 | On Linux you need to add these lines to your `.ovpn` file based on your Distribution. 21 | 22 | Debian 9, 10 and Ubuntu 16.04, 18.04 23 | 24 | ``` 25 | script-security 2 26 | up /etc/openvpn/update-resolv-conf 27 | down /etc/openvpn/update-resolv-conf 28 | ``` 29 | 30 | Centos 6, 7 31 | 32 | ``` 33 | script-security 2 34 | up /usr/share/doc/openvpn-2.4.8/contrib/pull-resolv-conf/client.up 35 | down /usr/share/doc/openvpn-2.4.8/contrib/pull-resolv-conf/client.down 36 | ``` 37 | 38 | Centos 8, Fedora 30, 31 39 | 40 | ``` 41 | script-security 2 42 | up /usr/share/doc/openvpn/contrib/pull-resolv-conf/client.up 43 | down /usr/share/doc/openvpn/contrib/pull-resolv-conf/client.down 44 | ``` 45 | 46 | Arch Linux 47 | 48 | ``` 49 | script-security 2 50 | up /usr/share/openvpn/contrib/pull-resolv-conf/client.up 51 | down /usr/share/openvpn/contrib/pull-resolv-conf/client.down 52 | ``` 53 | 54 | --- 55 | 56 | **Q:** Can I use an OpenVPN 2.3 client? 57 | 58 | **A:** Yes. I really recommend using an up-to-date client, but if you really need it, choose the following options: 59 | 60 | - No compression or LZ0 61 | - RSA certificate 62 | - DH Key 63 | - AES CBC 64 | - tls-auth 65 | 66 | If your client is <2.3.3, remove `tls-version-min 1.2` from your `/etc/openvpn/server.conf` and `.ovpn` files. 67 | 68 | --- 69 | 70 | **Q:** IPv6 is not working on my Hetzner VM 71 | 72 | **A:** This an issue on their side. See <https://angristan.xyz/fix-ipv6-hetzner-cloud/> 73 | 74 | --- 75 | 76 | **Q:** DNS is not working on my Linux client 77 | 78 | **A:** See "How do I fix DNS leaks?" question 79 | 80 | --- 81 | 82 | **Q:** What syctl and iptables changes are made by the script? 83 | 84 | **A:** Iptables rules are saved at `/etc/iptables/add-openvpn-rules.sh` and `/etc/iptables/rm-openvpn-rules.sh`. They are managed by the service `/etc/systemd/system/iptables-openvpn.service` 85 | 86 | Sysctl options are at `/etc/sysctl.d/20-openvpn.conf` 87 | 88 | --- 89 | 90 | **Q:** How can I access other clients connected to the same OpenVPN server? 91 | 92 | **A:** Add `client-to-client` to your `server.conf` 93 | 94 | --- 95 | 96 | **Q:** My router can't connect 97 | 98 | **A:** 99 | 100 | - `Options error: No closing quotation (") in config.ovpn:46` : 101 | 102 | type `yes` when asked to customize encryption settings and choose `tls-auth` 103 | 104 | - `Options error: Unrecognized option or missing parameter(s) in config.ovpn:36: tls-version-min (2.3.2)` : 105 | 106 | see question "Can I use an OpenVPN 2.3 client?" 107 | 108 | --- 109 | 110 | **Q:** How can I access computers the OpenVPN server's remote LAN? 111 | 112 | **A:** Add a route with the subnet of the remote network to `/etc/openvpn/server.conf` and restart openvpn. Example: `push "route 192.168.1.0 255.255.255.0"` if the server's LAN is `192.168.1.0/24` 113 | 114 | --- 115 | 116 | **Q:** How can I add multiple users in one go? 117 | 118 | **A:** Here is a sample bash script to achieve this: 119 | 120 | ```sh 121 | userlist=(user1 user2 user3) 122 | 123 | for i in ${userlist[@]};do 124 | MENU_OPTION=1 CLIENT=$i PASS=1 ./openvpn-install.sh 125 | done 126 | ``` 127 | 128 | From a list in a text file: 129 | 130 | ```sh 131 | while read USER 132 | do MENU_OPTION="1" CLIENT="$USER" PASS="1" ./openvpn-install.sh 133 | done < users.txt 134 | ``` 135 | 136 | --- 137 | 138 | **Q:** How do I change the default `.ovpn` file created for future clients? 139 | 140 | **A:** You can edit the template out of which `.ovpn` files are created by editing `/etc/openvpn/client-template.txt` 141 | 142 | --- 143 | 144 | **Q:** For my clients - I want to set my internal network to pass through the VPN and the rest to go through my internet? 145 | 146 | **A:** You would need to edit the `.ovpn` file. You can edit the template out of which those files are created by editing `/etc/openvpn/client-template.txt` file and adding 147 | 148 | ```sh 149 | route-nopull 150 | route 10.0.0.0 255.0.0.0 151 | ``` 152 | 153 | So for example - here it would route all traffic of `10.0.0.0/8` to the vpn. And the rest through the internet. 154 | 155 | --- 156 | 157 | **Q:** I have enabled IPv6 and my VPN client gets an IPv6 address. Why do I reach the websites or other dual-stacked destionations via IPv4 only? 158 | 159 | **A:** This is because inside the tunnel you don't get a publicly routable IPv6 address, instead you get an ULA (Unlique Local Lan) address. Operating systems don't prefer this all the time. You can fix this in your operating system policies as it's unrelated to the VPN itself: 160 | 161 | Windows (commands needs to run cmd.exe as Administrator): 162 | 163 | ``` 164 | netsh interface ipv6 add prefixpolicy fd00::/8 3 1 165 | ``` 166 | 167 | Linux: 168 | 169 | edit `/etc/gai.conf` and uncomment the following line and also change its value to `1`: 170 | 171 | ``` 172 | label fc00::/7 1 173 | ``` 174 | 175 | This will not work properly unless you add you your VPN server `server.conf` one or two lines to push at least 1 (one) IPv6 DNS server. Most providers have IPv6 servers as well, add two more lines of `push "dhcp-option DNS <IPv6>"` 176 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2013 Nyr 4 | Copyright (c) 2016 Stanislas Lange (angristan) 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy of 7 | this software and associated documentation files (the "Software"), to deal in 8 | the Software without restriction, including without limitation the rights to 9 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 10 | the Software, and to permit persons to whom the Software is furnished to do so, 11 | subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 18 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 19 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 20 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 21 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # openvpn-install 2 | 3 |  4 |  5 | [](https://saythanks.io/to/angristan) 6 | 7 | OpenVPN installer for Debian, Ubuntu, Fedora, CentOS, Arch Linux, Oracle Linux, Rocky Linux and AlmaLinux. 8 | 9 | This script will let you setup your own secure VPN server in just a few seconds. 10 | 11 | You can also check out [wireguard-install](https://github.com/angristan/wireguard-install), a simple installer for a simpler, safer, faster and more modern VPN protocol. 12 | 13 | ## What is this? 14 | 15 | This script is meant to be run on your own server, whether it's a VPS or a dedicated server, or even a computer at home. 16 | 17 | Once set up, you will be able to generate client configuration files for every device you want to connect. 18 | 19 | Each client will be able to route its internet traffic through the server, fully encrypted. 20 | 21 | ```mermaid 22 | graph LR 23 | A[Phone] -->|Encrypted| VPN 24 | B[Laptop] -->|Encrypted| VPN 25 | C[Computer] -->|Encrypted| VPN 26 | 27 | VPN[OpenVPN Server] 28 | 29 | VPN --> I[Internet] 30 | ``` 31 | 32 | ## Usage 33 | 34 | First, get the script and make it executable: 35 | 36 | ```bash 37 | curl -O https://raw.githubusercontent.com/angristan/openvpn-install/master/openvpn-install.sh 38 | chmod +x openvpn-install.sh 39 | ``` 40 | 41 | Then run it: 42 | 43 | ```sh 44 | ./openvpn-install.sh 45 | ``` 46 | 47 | You need to run the script as root and have the TUN module enabled. 48 | 49 | The first time you run it, you'll have to follow the assistant and answer a few questions to setup your VPN server. 50 | 51 | When OpenVPN is installed, you can run the script again, and you will get the choice to: 52 | 53 | - Add a client 54 | - Remove a client 55 | - Uninstall OpenVPN 56 | 57 | In your home directory, you will have `.ovpn` files. These are the client configuration files. Download them from your server and connect using your favorite OpenVPN client. 58 | 59 | If you have any question, head to the [FAQ](#faq) first. And if you need help, you can open a [discussion](https://github.com/angristan/openvpn-install/discussions). Please search existing issues and dicussions first. 60 | 61 | ### Headless install 62 | 63 | It's also possible to run the script headless, e.g. without waiting for user input, in an automated manner. 64 | 65 | Example usage: 66 | 67 | ```bash 68 | AUTO_INSTALL=y ./openvpn-install.sh 69 | 70 | # or 71 | 72 | export AUTO_INSTALL=y 73 | ./openvpn-install.sh 74 | ``` 75 | 76 | A default set of variables will then be set, by passing the need for user input. 77 | 78 | If you want to customise your installation, you can export them or specify them on the same line, as shown above. 79 | 80 | - `APPROVE_INSTALL=y` 81 | - `APPROVE_IP=y` 82 | - `IPV6_SUPPORT=n` 83 | - `PORT_CHOICE=1` 84 | - `PROTOCOL_CHOICE=1` 85 | - `DNS=1` 86 | - `COMPRESSION_ENABLED=n` 87 | - `CUSTOMIZE_ENC=n` 88 | - `CLIENT=clientname` 89 | - `PASS=1` 90 | 91 | If the server is behind NAT, you can specify its endpoint with the `ENDPOINT` variable. If the endpoint is the public IP address which it is behind, you can use `ENDPOINT=$(curl -4 ifconfig.co)` (the script will default to this). The endpoint can be an IPv4 or a domain. 92 | 93 | Other variables can be set depending on your choice (encryption, compression). You can search for them in the `installQuestions()` function of the script. 94 | 95 | Password-protected clients are not supported by the headless installation method since user input is expected by Easy-RSA. 96 | 97 | The headless install is more-or-less idempotent, in that it has been made safe to run multiple times with the same parameters, e.g. by a state provisioner like Ansible/Terraform/Salt/Chef/Puppet. It will only install and regenerate the Easy-RSA PKI if it doesn't already exist, and it will only install OpenVPN and other upstream dependencies if OpenVPN isn't already installed. It will recreate all local config and re-generate the client file on each headless run. 98 | 99 | ### Headless User Addition 100 | 101 | It's also possible to automate the addition of a new user. Here, the key is to provide the (string) value of the `MENU_OPTION` variable along with the remaining mandatory variables before invoking the script. 102 | 103 | The following Bash script adds a new user `foo` to an existing OpenVPN configuration 104 | 105 | ```bash 106 | #!/bin/bash 107 | export MENU_OPTION="1" 108 | export CLIENT="foo" 109 | export PASS="1" 110 | ./openvpn-install.sh 111 | ``` 112 | 113 | ## Features 114 | 115 | - Installs and configures a ready-to-use OpenVPN server 116 | - Iptables rules and forwarding managed in a seamless way 117 | - If needed, the script can cleanly remove OpenVPN, including configuration and iptables rules 118 | - Customisable encryption settings, enhanced default settings (see [Security and Encryption](#security-and-encryption) below) 119 | - OpenVPN 2.4 features, mainly encryption improvements (see [Security and Encryption](#security-and-encryption) below) 120 | - Variety of DNS resolvers to be pushed to the clients 121 | - Choice to use a self-hosted resolver with Unbound (supports already existing Unbound installations) 122 | - Choice between TCP and UDP 123 | - NATed IPv6 support 124 | - Compression disabled by default to prevent VORACLE. LZ4 (v1/v2) and LZ0 algorithms available otherwise. 125 | - Unprivileged mode: run as `nobody`/`nogroup` 126 | - Block DNS leaks on Windows 10 127 | - Randomised server certificate name 128 | - Choice to protect clients with a password (private key encryption) 129 | - Many other little things! 130 | 131 | ## Compatibility 132 | 133 | The script supports these Linux distributions: 134 | 135 | | | Support | 136 | | ---------------------- | ------- | 137 | | AlmaLinux 8 | ✅ | 138 | | Amazon Linux 2 | ✅ | 139 | | Amazon Linux >= 2023.6 | ✅ | 140 | | Arch Linux | ✅ | 141 | | CentOS 7 | ✅ | 142 | | CentOS Stream >= 8 | ✅ 🤖 | 143 | | Debian >= 10 | ✅ 🤖 | 144 | | Fedora >= 35 | ✅ 🤖 | 145 | | Oracle Linux 8 | ✅ | 146 | | Rocky Linux 8 | ✅ | 147 | | Ubuntu >= 18.04 | ✅ 🤖 | 148 | 149 | To be noted: 150 | 151 | - The script is regularly tested against the distributions marked with a 🤖 only. 152 | - It's only tested on `amd64` architecture. 153 | - It should work on older versions such as Debian 8+, Ubuntu 16.04+ and previous Fedora releases. But versions not in the table above are not officially supported. 154 | - It should also support versions between the LTS versions, but these are not tested. 155 | - The script requires `systemd`. 156 | 157 | ## Fork 158 | 159 | This script is based on the great work of [Nyr and its contributors](https://github.com/Nyr/openvpn-install). 160 | 161 | Since 2016, the two scripts have diverged and are not alike anymore, especially under the hood. The main goal of the script was enhanced security. But since then, the script has been completely rewritten and a lot a features have been added. The script is only compatible with recent distributions though, so if you need to use a very old server or client, I advise using Nyr's script. 162 | 163 | ## FAQ 164 | 165 | More Q&A in [FAQ.md](FAQ.md). 166 | 167 | **Q:** Which provider do you recommend? 168 | 169 | **A:** I recommend these: 170 | 171 | - [Vultr](https://www.vultr.com/?ref=8948982-8H): Worldwide locations, IPv6 support, starting at \$5/month 172 | - [Hetzner](https://hetzner.cloud/?ref=ywtlvZsjgeDq): Germany, Finland and USA. IPv6, 20 TB of traffic, starting at 4.5€/month 173 | - [Digital Ocean](https://m.do.co/c/ed0ba143fe53): Worldwide locations, IPv6 support, starting at \$4/month 174 | 175 | --- 176 | 177 | **Q:** Which OpenVPN client do you recommend? 178 | 179 | **A:** If possible, an official OpenVPN 2.4 client. 180 | 181 | - Windows: [The official OpenVPN community client](https://openvpn.net/index.php/download/community-downloads.html). 182 | - Linux: The `openvpn` package from your distribution. There is an [official APT repository](https://community.openvpn.net/openvpn/wiki/OpenvpnSoftwareRepos) for Debian/Ubuntu based distributions. 183 | - macOS: [Tunnelblick](https://tunnelblick.net/), [Viscosity](https://www.sparklabs.com/viscosity/), [OpenVPN for Mac](https://openvpn.net/client-connect-vpn-for-mac-os/). 184 | - Android: [OpenVPN for Android](https://play.google.com/store/apps/details?id=de.blinkt.openvpn). 185 | - iOS: [The official OpenVPN Connect client](https://itunes.apple.com/us/app/openvpn-connect/id590379981). 186 | 187 | --- 188 | 189 | **Q:** Am I safe from the NSA by using your script? 190 | 191 | **A:** Please review your threat models. Even if this script has security in mind and uses state-of-the-art encryption, you shouldn't be using a VPN if you want to hide from the NSA. 192 | 193 | --- 194 | 195 | **Q:** Is there an OpenVPN documentation? 196 | 197 | **A:** Yes, please head to the [OpenVPN Manual](https://community.openvpn.net/openvpn/wiki/Openvpn24ManPage), which references all the options. 198 | 199 | --- 200 | 201 | More Q&A in [FAQ.md](FAQ.md). 202 | 203 | ## One-stop solutions for public cloud 204 | 205 | Solutions that provision a ready to use OpenVPN server based on this script in one go are available for: 206 | 207 | - AWS using Terraform at [`openvpn-terraform-install`](https://github.com/dumrauf/openvpn-terraform-install) 208 | - Terraform AWS module [`openvpn-ephemeral`](https://registry.terraform.io/modules/paulmarsicloud/openvpn-ephemeral/aws/latest) 209 | 210 | ## Contributing 211 | 212 | ## Discuss changes 213 | 214 | Please open an issue before submitting a PR if you want to discuss a change, especially if it's a big one. 215 | 216 | ### Code formatting 217 | 218 | We use [shellcheck](https://github.com/koalaman/shellcheck) and [shfmt](https://github.com/mvdan/sh) to enforce bash styling guidelines and good practices. They are executed for each commit / PR with GitHub Actions, so you can check the configuration [here](https://github.com/angristan/openvpn-install/blob/master/.github/workflows/push.yml). 219 | 220 | ## Security and Encryption 221 | 222 | > **Warning** 223 | > This has not been updated for OpenVPN 2.5 and later. 224 | 225 | OpenVPN's default settings are pretty weak regarding encryption. This script aims to improve that. 226 | 227 | OpenVPN 2.4 was a great update regarding encryption. It added support for ECDSA, ECDH, AES GCM, NCP and tls-crypt. 228 | 229 | If you want more information about an option mentioned below, head to the [OpenVPN manual](https://community.openvpn.net/openvpn/wiki/Openvpn24ManPage). It is very complete. 230 | 231 | Most of OpenVPN's encryption-related stuff is managed by [Easy-RSA](https://github.com/OpenVPN/easy-rsa). Defaults parameters are in the [vars.example](https://github.com/OpenVPN/easy-rsa/blob/v3.0.7/easyrsa3/vars.example) file. 232 | 233 | ### Compression 234 | 235 | By default, OpenVPN doesn't enable compression. This script provides support for LZ0 and LZ4 (v1/v2) algorithms, the latter being more efficient. 236 | 237 | However, it is discouraged to use compression since the [VORACLE attack](https://protonvpn.com/blog/voracle-attack/) makes use of it. 238 | 239 | ### TLS version 240 | 241 | OpenVPN accepts TLS 1.0 by default, which is nearly [20 years old](https://en.wikipedia.org/wiki/Transport_Layer_Security#TLS_1.0). 242 | 243 | With `tls-version-min 1.2` we enforce TLS 1.2, which the best protocol available currently for OpenVPN. 244 | 245 | TLS 1.2 is supported since OpenVPN 2.3.3. 246 | 247 | ### Certificate 248 | 249 | OpenVPN uses an RSA certificate with a 2048 bits key by default. 250 | 251 | OpenVPN 2.4 added support for ECDSA. Elliptic curve cryptography is faster, lighter and more secure. 252 | 253 | This script provides: 254 | 255 | - ECDSA: `prime256v1`/`secp384r1`/`secp521r1` curves 256 | - RSA: `2048`/`3072`/`4096` bits keys 257 | 258 | It defaults to ECDSA with `prime256v1`. 259 | 260 | OpenVPN uses `SHA-256` as the signature hash by default, and so does the script. It provides no other choice as of now. 261 | 262 | ### Data channel 263 | 264 | By default, OpenVPN uses `BF-CBC` as the data channel cipher. Blowfish is an old (1993) and weak algorithm. Even the official OpenVPN documentation admits it. 265 | 266 | > The default is BF-CBC, an abbreviation for Blowfish in Cipher Block Chaining mode. 267 | > 268 | > Using BF-CBC is no longer recommended, because of its 64-bit block size. This small block size allows attacks based on collisions, as demonstrated by SWEET32. See <https://community.openvpn.net/openvpn/wiki/SWEET32> for details. 269 | > Security researchers at INRIA published an attack on 64-bit block ciphers, such as 3DES and Blowfish. They show that they are able to recover plaintext when the same data is sent often enough, and show how they can use cross-site scripting vulnerabilities to send data of interest often enough. This works over HTTPS, but also works for HTTP-over-OpenVPN. See <https://sweet32.info/> for a much better and more elaborate explanation. 270 | > 271 | > OpenVPN's default cipher, BF-CBC, is affected by this attack. 272 | 273 | Indeed, AES is today's standard. It's the fastest and more secure cipher available today. [SEED](https://en.wikipedia.org/wiki/SEED) and [Camellia](<https://en.wikipedia.org/wiki/Camellia_(cipher)>) are not vulnerable to date but are slower than AES and relatively less trusted. 274 | 275 | > Of the currently supported ciphers, OpenVPN currently recommends using AES-256-CBC or AES-128-CBC. OpenVPN 2.4 and newer will also support GCM. For 2.4+, we recommend using AES-256-GCM or AES-128-GCM. 276 | 277 | AES-256 is 40% slower than AES-128, and there isn't any real reason to use a 256 bits key over a 128 bits key with AES. (Source: [1](http://security.stackexchange.com/questions/14068/why-most-people-use-256-bit-encryption-instead-of-128-bit),[2](http://security.stackexchange.com/questions/6141/amount-of-simple-operations-that-is-safely-out-of-reach-for-all-humanity/6149#6149)). Moreover, AES-256 is more vulnerable to [Timing attacks](https://en.wikipedia.org/wiki/Timing_attack). 278 | 279 | AES-GCM is an [AEAD cipher](https://en.wikipedia.org/wiki/Authenticated_encryption) which means it simultaneously provides confidentiality, integrity, and authenticity assurances on the data. 280 | 281 | The script supports the following ciphers: 282 | 283 | - `AES-128-GCM` 284 | - `AES-192-GCM` 285 | - `AES-256-GCM` 286 | - `AES-128-CBC` 287 | - `AES-192-CBC` 288 | - `AES-256-CBC` 289 | 290 | And defaults to `AES-128-GCM`. 291 | 292 | OpenVPN 2.4 added a feature called "NCP": _Negotiable Crypto Parameters_. It means you can provide a cipher suite like with HTTPS. It is set to `AES-256-GCM:AES-128-GCM` by default and overrides the `--cipher` parameter when used with an OpenVPN 2.4 client. For the sake of simplicity, the script set both the `--cipher` and `--ncp-cipher` to the cipher chosen above. 293 | 294 | ### Control channel 295 | 296 | OpenVPN 2.4 will negotiate the best cipher available by default (e.g ECDHE+AES-256-GCM) 297 | 298 | The script proposes the following options, depending on the certificate: 299 | 300 | - ECDSA: 301 | - `TLS-ECDHE-ECDSA-WITH-AES-128-GCM-SHA256` 302 | - `TLS-ECDHE-ECDSA-WITH-AES-256-GCM-SHA384` 303 | - RSA: 304 | - `TLS-ECDHE-RSA-WITH-AES-128-GCM-SHA256` 305 | - `TLS-ECDHE-RSA-WITH-AES-256-GCM-SHA384` 306 | 307 | It defaults to `TLS-ECDHE-*-WITH-AES-128-GCM-SHA256`. 308 | 309 | ### Diffie-Hellman key exchange 310 | 311 | OpenVPN uses a 2048 bits DH key by default. 312 | 313 | OpenVPN 2.4 added support for ECDH keys. Elliptic curve cryptography is faster, lighter and more secure. 314 | 315 | Also, generating a classic DH keys can take a long, looong time. ECDH keys are ephemeral: they are generated on-the-fly. 316 | 317 | The script provides the following options: 318 | 319 | - ECDH: `prime256v1`/`secp384r1`/`secp521r1` curves 320 | - DH: `2048`/`3072`/`4096` bits keys 321 | 322 | It defaults to `prime256v1`. 323 | 324 | ### HMAC digest algorithm 325 | 326 | From the OpenVPN wiki, about `--auth`: 327 | 328 | > Authenticate data channel packets and (if enabled) tls-auth control channel packets with HMAC using message digest algorithm alg. (The default is SHA1 ). HMAC is a commonly used message authentication algorithm (MAC) that uses a data string, a secure hash algorithm, and a key, to produce a digital signature. 329 | > 330 | > If an AEAD cipher mode (e.g. GCM) is chosen, the specified --auth algorithm is ignored for the data channel, and the authentication method of the AEAD cipher is used instead. Note that alg still specifies the digest used for tls-auth. 331 | 332 | The script provides the following choices: 333 | 334 | - `SHA256` 335 | - `SHA384` 336 | - `SHA512` 337 | 338 | It defaults to `SHA256`. 339 | 340 | ### `tls-auth` and `tls-crypt` 341 | 342 | From the OpenVPN wiki, about `tls-auth`: 343 | 344 | > Add an additional layer of HMAC authentication on top of the TLS control channel to mitigate DoS attacks and attacks on the TLS stack. 345 | > 346 | > In a nutshell, --tls-auth enables a kind of "HMAC firewall" on OpenVPN's TCP/UDP port, where TLS control channel packets bearing an incorrect HMAC signature can be dropped immediately without response. 347 | 348 | About `tls-crypt`: 349 | 350 | > Encrypt and authenticate all control channel packets with the key from keyfile. (See --tls-auth for more background.) 351 | > 352 | > Encrypting (and authenticating) control channel packets: 353 | > 354 | > - provides more privacy by hiding the certificate used for the TLS connection, 355 | > - makes it harder to identify OpenVPN traffic as such, 356 | > - provides "poor-man's" post-quantum security, against attackers who will never know the pre-shared key (i.e. no forward secrecy). 357 | 358 | So both provide an additional layer of security and mitigate DoS attacks. They aren't used by default by OpenVPN. 359 | 360 | `tls-crypt` is an OpenVPN 2.4 feature that provides encryption in addition to authentication (unlike `tls-auth`). It is more privacy-friendly. 361 | 362 | The script supports both and uses `tls-crypt` by default. 363 | 364 | ## Say thanks 365 | 366 | You can [say thanks](https://saythanks.io/to/angristan) if you want! 367 | 368 | ## Credits & Licence 369 | 370 | Many thanks to the [contributors](https://github.com/Angristan/OpenVPN-install/graphs/contributors) and Nyr's original work. 371 | 372 | This project is under the [MIT Licence](https://raw.githubusercontent.com/Angristan/openvpn-install/master/LICENSE) 373 | 374 | ## Star History 375 | 376 | [](https://star-history.com/#angristan/openvpn-install&Date) 377 | -------------------------------------------------------------------------------- /openvpn-install.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # shellcheck disable=SC1091,SC2164,SC2034,SC1072,SC1073,SC1009 3 | 4 | # Secure OpenVPN server installer for Debian, Ubuntu, CentOS, Amazon Linux 2, Fedora, Oracle Linux 8, Arch Linux, Rocky Linux and AlmaLinux. 5 | # https://github.com/angristan/openvpn-install 6 | 7 | function isRoot() { 8 | if [ "$EUID" -ne 0 ]; then 9 | return 1 10 | fi 11 | } 12 | 13 | function tunAvailable() { 14 | if [ ! -e /dev/net/tun ]; then 15 | return 1 16 | fi 17 | } 18 | 19 | function checkOS() { 20 | if [[ -e /etc/debian_version ]]; then 21 | OS="debian" 22 | source /etc/os-release 23 | 24 | if [[ $ID == "debian" || $ID == "raspbian" ]]; then 25 | if [[ $VERSION_ID -lt 9 ]]; then 26 | echo "⚠️ Your version of Debian is not supported." 27 | echo "" 28 | echo "However, if you're using Debian >= 9 or unstable/testing, you can continue at your own risk." 29 | echo "" 30 | until [[ $CONTINUE =~ (y|n) ]]; do 31 | read -rp "Continue? [y/n]: " -e CONTINUE 32 | done 33 | if [[ $CONTINUE == "n" ]]; then 34 | exit 1 35 | fi 36 | fi 37 | elif [[ $ID == "ubuntu" ]]; then 38 | OS="ubuntu" 39 | MAJOR_UBUNTU_VERSION=$(echo "$VERSION_ID" | cut -d '.' -f1) 40 | if [[ $MAJOR_UBUNTU_VERSION -lt 16 ]]; then 41 | echo "⚠️ Your version of Ubuntu is not supported." 42 | echo "" 43 | echo "However, if you're using Ubuntu >= 16.04 or beta, you can continue at your own risk." 44 | echo "" 45 | until [[ $CONTINUE =~ (y|n) ]]; do 46 | read -rp "Continue? [y/n]: " -e CONTINUE 47 | done 48 | if [[ $CONTINUE == "n" ]]; then 49 | exit 1 50 | fi 51 | fi 52 | fi 53 | elif [[ -e /etc/system-release ]]; then 54 | source /etc/os-release 55 | if [[ $ID == "fedora" || $ID_LIKE == "fedora" ]]; then 56 | OS="fedora" 57 | fi 58 | if [[ $ID == "centos" || $ID == "rocky" || $ID == "almalinux" ]]; then 59 | OS="centos" 60 | if [[ ${VERSION_ID%.*} -lt 7 ]]; then 61 | echo "⚠️ Your version of CentOS is not supported." 62 | echo "" 63 | echo "The script only supports CentOS 7 and CentOS 8." 64 | echo "" 65 | exit 1 66 | fi 67 | fi 68 | if [[ $ID == "ol" ]]; then 69 | OS="oracle" 70 | if [[ ! $VERSION_ID =~ (8) ]]; then 71 | echo "Your version of Oracle Linux is not supported." 72 | echo "" 73 | echo "The script only supports Oracle Linux 8." 74 | exit 1 75 | fi 76 | fi 77 | if [[ $ID == "amzn" ]]; then 78 | if [[ $VERSION_ID == "2" ]]; then 79 | OS="amzn" 80 | elif [[ "$(echo "$PRETTY_NAME" | cut -c 1-18)" == "Amazon Linux 2023." ]] && [[ "$(echo "$PRETTY_NAME" | cut -c 19)" -ge 6 ]]; then 81 | OS="amzn2023" 82 | else 83 | echo "⚠️ Your version of Amazon Linux is not supported." 84 | echo "" 85 | echo "The script only supports Amazon Linux 2 or Amazon Linux 2023.6+" 86 | echo "" 87 | exit 1 88 | fi 89 | fi 90 | elif [[ -e /etc/arch-release ]]; then 91 | OS=arch 92 | else 93 | echo "It looks like you aren't running this installer on a Debian, Ubuntu, Fedora, CentOS, Amazon Linux 2, Oracle Linux 8 or Arch Linux system." 94 | exit 1 95 | fi 96 | } 97 | 98 | function initialCheck() { 99 | if ! isRoot; then 100 | echo "Sorry, you need to run this script as root." 101 | exit 1 102 | fi 103 | if ! tunAvailable; then 104 | echo "TUN is not available." 105 | exit 1 106 | fi 107 | checkOS 108 | } 109 | 110 | function installUnbound() { 111 | # If Unbound isn't installed, install it 112 | if [[ ! -e /etc/unbound/unbound.conf ]]; then 113 | 114 | if [[ $OS =~ (debian|ubuntu) ]]; then 115 | apt-get install -y unbound 116 | 117 | # Configuration 118 | echo 'interface: 10.8.0.1 119 | access-control: 10.8.0.1/24 allow 120 | hide-identity: yes 121 | hide-version: yes 122 | use-caps-for-id: yes 123 | prefetch: yes' >>/etc/unbound/unbound.conf 124 | 125 | elif [[ $OS =~ (centos|amzn|oracle) ]]; then 126 | yum install -y unbound 127 | 128 | # Configuration 129 | sed -i 's|# interface: 0.0.0.0$|interface: 10.8.0.1|' /etc/unbound/unbound.conf 130 | sed -i 's|# access-control: 127.0.0.0/8 allow|access-control: 10.8.0.1/24 allow|' /etc/unbound/unbound.conf 131 | sed -i 's|# hide-identity: no|hide-identity: yes|' /etc/unbound/unbound.conf 132 | sed -i 's|# hide-version: no|hide-version: yes|' /etc/unbound/unbound.conf 133 | sed -i 's|use-caps-for-id: no|use-caps-for-id: yes|' /etc/unbound/unbound.conf 134 | 135 | elif [[ $OS == "fedora" ]]; then 136 | dnf install -y unbound 137 | 138 | # Configuration 139 | sed -i 's|# interface: 0.0.0.0$|interface: 10.8.0.1|' /etc/unbound/unbound.conf 140 | sed -i 's|# access-control: 127.0.0.0/8 allow|access-control: 10.8.0.1/24 allow|' /etc/unbound/unbound.conf 141 | sed -i 's|# hide-identity: no|hide-identity: yes|' /etc/unbound/unbound.conf 142 | sed -i 's|# hide-version: no|hide-version: yes|' /etc/unbound/unbound.conf 143 | sed -i 's|# use-caps-for-id: no|use-caps-for-id: yes|' /etc/unbound/unbound.conf 144 | 145 | elif [[ $OS == "arch" ]]; then 146 | pacman -Syu --noconfirm unbound 147 | 148 | # Get root servers list 149 | curl -o /etc/unbound/root.hints https://www.internic.net/domain/named.cache 150 | 151 | if [[ ! -f /etc/unbound/unbound.conf.old ]]; then 152 | mv /etc/unbound/unbound.conf /etc/unbound/unbound.conf.old 153 | fi 154 | 155 | echo 'server: 156 | use-syslog: yes 157 | do-daemonize: no 158 | username: "unbound" 159 | directory: "/etc/unbound" 160 | trust-anchor-file: trusted-key.key 161 | root-hints: root.hints 162 | interface: 10.8.0.1 163 | access-control: 10.8.0.1/24 allow 164 | port: 53 165 | num-threads: 2 166 | use-caps-for-id: yes 167 | harden-glue: yes 168 | hide-identity: yes 169 | hide-version: yes 170 | qname-minimisation: yes 171 | prefetch: yes' >/etc/unbound/unbound.conf 172 | fi 173 | 174 | # IPv6 DNS for all OS 175 | if [[ $IPV6_SUPPORT == 'y' ]]; then 176 | echo 'interface: fd42:42:42:42::1 177 | access-control: fd42:42:42:42::/112 allow' >>/etc/unbound/unbound.conf 178 | fi 179 | 180 | if [[ ! $OS =~ (fedora|centos|amzn|oracle) ]]; then 181 | # DNS Rebinding fix 182 | echo "private-address: 10.0.0.0/8 183 | private-address: fd42:42:42:42::/112 184 | private-address: 172.16.0.0/12 185 | private-address: 192.168.0.0/16 186 | private-address: 169.254.0.0/16 187 | private-address: fd00::/8 188 | private-address: fe80::/10 189 | private-address: 127.0.0.0/8 190 | private-address: ::ffff:0:0/96" >>/etc/unbound/unbound.conf 191 | fi 192 | else # Unbound is already installed 193 | echo 'include: /etc/unbound/openvpn.conf' >>/etc/unbound/unbound.conf 194 | 195 | # Add Unbound 'server' for the OpenVPN subnet 196 | echo 'server: 197 | interface: 10.8.0.1 198 | access-control: 10.8.0.1/24 allow 199 | hide-identity: yes 200 | hide-version: yes 201 | use-caps-for-id: yes 202 | prefetch: yes 203 | private-address: 10.0.0.0/8 204 | private-address: fd42:42:42:42::/112 205 | private-address: 172.16.0.0/12 206 | private-address: 192.168.0.0/16 207 | private-address: 169.254.0.0/16 208 | private-address: fd00::/8 209 | private-address: fe80::/10 210 | private-address: 127.0.0.0/8 211 | private-address: ::ffff:0:0/96' >/etc/unbound/openvpn.conf 212 | if [[ $IPV6_SUPPORT == 'y' ]]; then 213 | echo 'interface: fd42:42:42:42::1 214 | access-control: fd42:42:42:42::/112 allow' >>/etc/unbound/openvpn.conf 215 | fi 216 | fi 217 | 218 | systemctl enable unbound 219 | systemctl restart unbound 220 | } 221 | 222 | function resolvePublicIP() { 223 | # IP version flags, we'll use as default the IPv4 224 | CURL_IP_VERSION_FLAG="-4" 225 | DIG_IP_VERSION_FLAG="-4" 226 | 227 | # Behind NAT, we'll default to the publicly reachable IPv4/IPv6. 228 | if [[ $IPV6_SUPPORT == "y" ]]; then 229 | CURL_IP_VERSION_FLAG="" 230 | DIG_IP_VERSION_FLAG="-6" 231 | fi 232 | 233 | # If there is no public ip yet, we'll try to solve it using: https://api.seeip.org 234 | if [[ -z $PUBLIC_IP ]]; then 235 | PUBLIC_IP=$(curl -f -m 5 -sS --retry 2 --retry-connrefused "$CURL_IP_VERSION_FLAG" https://api.seeip.org 2>/dev/null) 236 | fi 237 | 238 | # If there is no public ip yet, we'll try to solve it using: https://ifconfig.me 239 | if [[ -z $PUBLIC_IP ]]; then 240 | PUBLIC_IP=$(curl -f -m 5 -sS --retry 2 --retry-connrefused "$CURL_IP_VERSION_FLAG" https://ifconfig.me 2>/dev/null) 241 | fi 242 | 243 | # If there is no public ip yet, we'll try to solve it using: https://api.ipify.org 244 | if [[ -z $PUBLIC_IP ]]; then 245 | PUBLIC_IP=$(curl -f -m 5 -sS --retry 2 --retry-connrefused "$CURL_IP_VERSION_FLAG" https://api.ipify.org 2>/dev/null) 246 | fi 247 | 248 | # If there is no public ip yet, we'll try to solve it using: ns1.google.com 249 | if [[ -z $PUBLIC_IP ]]; then 250 | PUBLIC_IP=$(dig $DIG_IP_VERSION_FLAG TXT +short o-o.myaddr.l.google.com @ns1.google.com | tr -d '"') 251 | fi 252 | 253 | if [[ -z $PUBLIC_IP ]]; then 254 | echo >&2 echo "Couldn't solve the public IP" 255 | exit 1 256 | fi 257 | 258 | echo "$PUBLIC_IP" 259 | } 260 | 261 | function installQuestions() { 262 | echo "Welcome to the OpenVPN installer!" 263 | echo "The git repository is available at: https://github.com/angristan/openvpn-install" 264 | echo "" 265 | 266 | echo "I need to ask you a few questions before starting the setup." 267 | echo "You can leave the default options and just press enter if you are okay with them." 268 | echo "" 269 | echo "I need to know the IPv4 address of the network interface you want OpenVPN listening to." 270 | echo "Unless your server is behind NAT, it should be your public IPv4 address." 271 | 272 | # Detect public IPv4 address and pre-fill for the user 273 | IP=$(ip -4 addr | sed -ne 's|^.* inet \([^/]*\)/.* scope global.*$|\1|p' | head -1) 274 | 275 | if [[ -z $IP ]]; then 276 | # Detect public IPv6 address 277 | IP=$(ip -6 addr | sed -ne 's|^.* inet6 \([^/]*\)/.* scope global.*$|\1|p' | head -1) 278 | fi 279 | APPROVE_IP=${APPROVE_IP:-n} 280 | if [[ $APPROVE_IP =~ n ]]; then 281 | read -rp "IP address: " -e -i "$IP" IP 282 | fi 283 | # If $IP is a private IP address, the server must be behind NAT 284 | if echo "$IP" | grep -qE '^(10\.|172\.1[6789]\.|172\.2[0-9]\.|172\.3[01]\.|192\.168)'; then 285 | echo "" 286 | echo "It seems this server is behind NAT. What is its public IPv4 address or hostname?" 287 | echo "We need it for the clients to connect to the server." 288 | 289 | if [[ -z $ENDPOINT ]]; then 290 | DEFAULT_ENDPOINT=$(resolvePublicIP) 291 | fi 292 | 293 | until [[ $ENDPOINT != "" ]]; do 294 | read -rp "Public IPv4 address or hostname: " -e -i "$DEFAULT_ENDPOINT" ENDPOINT 295 | done 296 | fi 297 | 298 | echo "" 299 | echo "Checking for IPv6 connectivity..." 300 | echo "" 301 | # "ping6" and "ping -6" availability varies depending on the distribution 302 | if type ping6 >/dev/null 2>&1; then 303 | PING6="ping6 -c3 ipv6.google.com > /dev/null 2>&1" 304 | else 305 | PING6="ping -6 -c3 ipv6.google.com > /dev/null 2>&1" 306 | fi 307 | if eval "$PING6"; then 308 | echo "Your host appears to have IPv6 connectivity." 309 | SUGGESTION="y" 310 | else 311 | echo "Your host does not appear to have IPv6 connectivity." 312 | SUGGESTION="n" 313 | fi 314 | echo "" 315 | # Ask the user if they want to enable IPv6 regardless its availability. 316 | until [[ $IPV6_SUPPORT =~ (y|n) ]]; do 317 | read -rp "Do you want to enable IPv6 support (NAT)? [y/n]: " -e -i $SUGGESTION IPV6_SUPPORT 318 | done 319 | echo "" 320 | echo "What port do you want OpenVPN to listen to?" 321 | echo " 1) Default: 1194" 322 | echo " 2) Custom" 323 | echo " 3) Random [49152-65535]" 324 | until [[ $PORT_CHOICE =~ ^[1-3]$ ]]; do 325 | read -rp "Port choice [1-3]: " -e -i 1 PORT_CHOICE 326 | done 327 | case $PORT_CHOICE in 328 | 1) 329 | PORT="1194" 330 | ;; 331 | 2) 332 | until [[ $PORT =~ ^[0-9]+$ ]] && [ "$PORT" -ge 1 ] && [ "$PORT" -le 65535 ]; do 333 | read -rp "Custom port [1-65535]: " -e -i 1194 PORT 334 | done 335 | ;; 336 | 3) 337 | # Generate random number within private ports range 338 | PORT=$(shuf -i49152-65535 -n1) 339 | echo "Random Port: $PORT" 340 | ;; 341 | esac 342 | echo "" 343 | echo "What protocol do you want OpenVPN to use?" 344 | echo "UDP is faster. Unless it is not available, you shouldn't use TCP." 345 | echo " 1) UDP" 346 | echo " 2) TCP" 347 | until [[ $PROTOCOL_CHOICE =~ ^[1-2]$ ]]; do 348 | read -rp "Protocol [1-2]: " -e -i 1 PROTOCOL_CHOICE 349 | done 350 | case $PROTOCOL_CHOICE in 351 | 1) 352 | PROTOCOL="udp" 353 | ;; 354 | 2) 355 | PROTOCOL="tcp" 356 | ;; 357 | esac 358 | echo "" 359 | echo "What DNS resolvers do you want to use with the VPN?" 360 | echo " 1) Current system resolvers (from /etc/resolv.conf)" 361 | echo " 2) Self-hosted DNS Resolver (Unbound)" 362 | echo " 3) Cloudflare (Anycast: worldwide)" 363 | echo " 4) Quad9 (Anycast: worldwide)" 364 | echo " 5) Quad9 uncensored (Anycast: worldwide)" 365 | echo " 6) FDN (France)" 366 | echo " 7) DNS.WATCH (Germany)" 367 | echo " 8) OpenDNS (Anycast: worldwide)" 368 | echo " 9) Google (Anycast: worldwide)" 369 | echo " 10) Yandex Basic (Russia)" 370 | echo " 11) AdGuard DNS (Anycast: worldwide)" 371 | echo " 12) NextDNS (Anycast: worldwide)" 372 | echo " 13) Custom" 373 | until [[ $DNS =~ ^[0-9]+$ ]] && [ "$DNS" -ge 1 ] && [ "$DNS" -le 13 ]; do 374 | read -rp "DNS [1-12]: " -e -i 11 DNS 375 | if [[ $DNS == 2 ]] && [[ -e /etc/unbound/unbound.conf ]]; then 376 | echo "" 377 | echo "Unbound is already installed." 378 | echo "You can allow the script to configure it in order to use it from your OpenVPN clients" 379 | echo "We will simply add a second server to /etc/unbound/unbound.conf for the OpenVPN subnet." 380 | echo "No changes are made to the current configuration." 381 | echo "" 382 | 383 | until [[ $CONTINUE =~ (y|n) ]]; do 384 | read -rp "Apply configuration changes to Unbound? [y/n]: " -e CONTINUE 385 | done 386 | if [[ $CONTINUE == "n" ]]; then 387 | # Break the loop and cleanup 388 | unset DNS 389 | unset CONTINUE 390 | fi 391 | elif [[ $DNS == "13" ]]; then 392 | until [[ $DNS1 =~ ^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$ ]]; do 393 | read -rp "Primary DNS: " -e DNS1 394 | done 395 | until [[ $DNS2 =~ ^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$ ]]; do 396 | read -rp "Secondary DNS (optional): " -e DNS2 397 | if [[ $DNS2 == "" ]]; then 398 | break 399 | fi 400 | done 401 | fi 402 | done 403 | echo "" 404 | echo "Do you want to use compression? It is not recommended since the VORACLE attack makes use of it." 405 | until [[ $COMPRESSION_ENABLED =~ (y|n) ]]; do 406 | read -rp"Enable compression? [y/n]: " -e -i n COMPRESSION_ENABLED 407 | done 408 | if [[ $COMPRESSION_ENABLED == "y" ]]; then 409 | echo "Choose which compression algorithm you want to use: (they are ordered by efficiency)" 410 | echo " 1) LZ4-v2" 411 | echo " 2) LZ4" 412 | echo " 3) LZ0" 413 | until [[ $COMPRESSION_CHOICE =~ ^[1-3]$ ]]; do 414 | read -rp"Compression algorithm [1-3]: " -e -i 1 COMPRESSION_CHOICE 415 | done 416 | case $COMPRESSION_CHOICE in 417 | 1) 418 | COMPRESSION_ALG="lz4-v2" 419 | ;; 420 | 2) 421 | COMPRESSION_ALG="lz4" 422 | ;; 423 | 3) 424 | COMPRESSION_ALG="lzo" 425 | ;; 426 | esac 427 | fi 428 | echo "" 429 | echo "Do you want to customize encryption settings?" 430 | echo "Unless you know what you're doing, you should stick with the default parameters provided by the script." 431 | echo "Note that whatever you choose, all the choices presented in the script are safe (unlike OpenVPN's defaults)." 432 | echo "See https://github.com/angristan/openvpn-install#security-and-encryption to learn more." 433 | echo "" 434 | until [[ $CUSTOMIZE_ENC =~ (y|n) ]]; do 435 | read -rp "Customize encryption settings? [y/n]: " -e -i n CUSTOMIZE_ENC 436 | done 437 | if [[ $CUSTOMIZE_ENC == "n" ]]; then 438 | # Use default, sane and fast parameters 439 | CIPHER="AES-128-GCM" 440 | CERT_TYPE="1" # ECDSA 441 | CERT_CURVE="prime256v1" 442 | CC_CIPHER="TLS-ECDHE-ECDSA-WITH-AES-128-GCM-SHA256" 443 | DH_TYPE="1" # ECDH 444 | DH_CURVE="prime256v1" 445 | HMAC_ALG="SHA256" 446 | TLS_SIG="1" # tls-crypt 447 | else 448 | echo "" 449 | echo "Choose which cipher you want to use for the data channel:" 450 | echo " 1) AES-128-GCM (recommended)" 451 | echo " 2) AES-192-GCM" 452 | echo " 3) AES-256-GCM" 453 | echo " 4) AES-128-CBC" 454 | echo " 5) AES-192-CBC" 455 | echo " 6) AES-256-CBC" 456 | until [[ $CIPHER_CHOICE =~ ^[1-6]$ ]]; do 457 | read -rp "Cipher [1-6]: " -e -i 1 CIPHER_CHOICE 458 | done 459 | case $CIPHER_CHOICE in 460 | 1) 461 | CIPHER="AES-128-GCM" 462 | ;; 463 | 2) 464 | CIPHER="AES-192-GCM" 465 | ;; 466 | 3) 467 | CIPHER="AES-256-GCM" 468 | ;; 469 | 4) 470 | CIPHER="AES-128-CBC" 471 | ;; 472 | 5) 473 | CIPHER="AES-192-CBC" 474 | ;; 475 | 6) 476 | CIPHER="AES-256-CBC" 477 | ;; 478 | esac 479 | echo "" 480 | echo "Choose what kind of certificate you want to use:" 481 | echo " 1) ECDSA (recommended)" 482 | echo " 2) RSA" 483 | until [[ $CERT_TYPE =~ ^[1-2]$ ]]; do 484 | read -rp"Certificate key type [1-2]: " -e -i 1 CERT_TYPE 485 | done 486 | case $CERT_TYPE in 487 | 1) 488 | echo "" 489 | echo "Choose which curve you want to use for the certificate's key:" 490 | echo " 1) prime256v1 (recommended)" 491 | echo " 2) secp384r1" 492 | echo " 3) secp521r1" 493 | until [[ $CERT_CURVE_CHOICE =~ ^[1-3]$ ]]; do 494 | read -rp"Curve [1-3]: " -e -i 1 CERT_CURVE_CHOICE 495 | done 496 | case $CERT_CURVE_CHOICE in 497 | 1) 498 | CERT_CURVE="prime256v1" 499 | ;; 500 | 2) 501 | CERT_CURVE="secp384r1" 502 | ;; 503 | 3) 504 | CERT_CURVE="secp521r1" 505 | ;; 506 | esac 507 | ;; 508 | 2) 509 | echo "" 510 | echo "Choose which size you want to use for the certificate's RSA key:" 511 | echo " 1) 2048 bits (recommended)" 512 | echo " 2) 3072 bits" 513 | echo " 3) 4096 bits" 514 | until [[ $RSA_KEY_SIZE_CHOICE =~ ^[1-3]$ ]]; do 515 | read -rp "RSA key size [1-3]: " -e -i 1 RSA_KEY_SIZE_CHOICE 516 | done 517 | case $RSA_KEY_SIZE_CHOICE in 518 | 1) 519 | RSA_KEY_SIZE="2048" 520 | ;; 521 | 2) 522 | RSA_KEY_SIZE="3072" 523 | ;; 524 | 3) 525 | RSA_KEY_SIZE="4096" 526 | ;; 527 | esac 528 | ;; 529 | esac 530 | echo "" 531 | echo "Choose which cipher you want to use for the control channel:" 532 | case $CERT_TYPE in 533 | 1) 534 | echo " 1) ECDHE-ECDSA-AES-128-GCM-SHA256 (recommended)" 535 | echo " 2) ECDHE-ECDSA-AES-256-GCM-SHA384" 536 | until [[ $CC_CIPHER_CHOICE =~ ^[1-2]$ ]]; do 537 | read -rp"Control channel cipher [1-2]: " -e -i 1 CC_CIPHER_CHOICE 538 | done 539 | case $CC_CIPHER_CHOICE in 540 | 1) 541 | CC_CIPHER="TLS-ECDHE-ECDSA-WITH-AES-128-GCM-SHA256" 542 | ;; 543 | 2) 544 | CC_CIPHER="TLS-ECDHE-ECDSA-WITH-AES-256-GCM-SHA384" 545 | ;; 546 | esac 547 | ;; 548 | 2) 549 | echo " 1) ECDHE-RSA-AES-128-GCM-SHA256 (recommended)" 550 | echo " 2) ECDHE-RSA-AES-256-GCM-SHA384" 551 | until [[ $CC_CIPHER_CHOICE =~ ^[1-2]$ ]]; do 552 | read -rp"Control channel cipher [1-2]: " -e -i 1 CC_CIPHER_CHOICE 553 | done 554 | case $CC_CIPHER_CHOICE in 555 | 1) 556 | CC_CIPHER="TLS-ECDHE-RSA-WITH-AES-128-GCM-SHA256" 557 | ;; 558 | 2) 559 | CC_CIPHER="TLS-ECDHE-RSA-WITH-AES-256-GCM-SHA384" 560 | ;; 561 | esac 562 | ;; 563 | esac 564 | echo "" 565 | echo "Choose what kind of Diffie-Hellman key you want to use:" 566 | echo " 1) ECDH (recommended)" 567 | echo " 2) DH" 568 | until [[ $DH_TYPE =~ [1-2] ]]; do 569 | read -rp"DH key type [1-2]: " -e -i 1 DH_TYPE 570 | done 571 | case $DH_TYPE in 572 | 1) 573 | echo "" 574 | echo "Choose which curve you want to use for the ECDH key:" 575 | echo " 1) prime256v1 (recommended)" 576 | echo " 2) secp384r1" 577 | echo " 3) secp521r1" 578 | while [[ $DH_CURVE_CHOICE != "1" && $DH_CURVE_CHOICE != "2" && $DH_CURVE_CHOICE != "3" ]]; do 579 | read -rp"Curve [1-3]: " -e -i 1 DH_CURVE_CHOICE 580 | done 581 | case $DH_CURVE_CHOICE in 582 | 1) 583 | DH_CURVE="prime256v1" 584 | ;; 585 | 2) 586 | DH_CURVE="secp384r1" 587 | ;; 588 | 3) 589 | DH_CURVE="secp521r1" 590 | ;; 591 | esac 592 | ;; 593 | 2) 594 | echo "" 595 | echo "Choose what size of Diffie-Hellman key you want to use:" 596 | echo " 1) 2048 bits (recommended)" 597 | echo " 2) 3072 bits" 598 | echo " 3) 4096 bits" 599 | until [[ $DH_KEY_SIZE_CHOICE =~ ^[1-3]$ ]]; do 600 | read -rp "DH key size [1-3]: " -e -i 1 DH_KEY_SIZE_CHOICE 601 | done 602 | case $DH_KEY_SIZE_CHOICE in 603 | 1) 604 | DH_KEY_SIZE="2048" 605 | ;; 606 | 2) 607 | DH_KEY_SIZE="3072" 608 | ;; 609 | 3) 610 | DH_KEY_SIZE="4096" 611 | ;; 612 | esac 613 | ;; 614 | esac 615 | echo "" 616 | # The "auth" options behaves differently with AEAD ciphers 617 | if [[ $CIPHER =~ CBC$ ]]; then 618 | echo "The digest algorithm authenticates data channel packets and tls-auth packets from the control channel." 619 | elif [[ $CIPHER =~ GCM$ ]]; then 620 | echo "The digest algorithm authenticates tls-auth packets from the control channel." 621 | fi 622 | echo "Which digest algorithm do you want to use for HMAC?" 623 | echo " 1) SHA-256 (recommended)" 624 | echo " 2) SHA-384" 625 | echo " 3) SHA-512" 626 | until [[ $HMAC_ALG_CHOICE =~ ^[1-3]$ ]]; do 627 | read -rp "Digest algorithm [1-3]: " -e -i 1 HMAC_ALG_CHOICE 628 | done 629 | case $HMAC_ALG_CHOICE in 630 | 1) 631 | HMAC_ALG="SHA256" 632 | ;; 633 | 2) 634 | HMAC_ALG="SHA384" 635 | ;; 636 | 3) 637 | HMAC_ALG="SHA512" 638 | ;; 639 | esac 640 | echo "" 641 | echo "You can add an additional layer of security to the control channel with tls-auth and tls-crypt" 642 | echo "tls-auth authenticates the packets, while tls-crypt authenticate and encrypt them." 643 | echo " 1) tls-crypt (recommended)" 644 | echo " 2) tls-auth" 645 | until [[ $TLS_SIG =~ [1-2] ]]; do 646 | read -rp "Control channel additional security mechanism [1-2]: " -e -i 1 TLS_SIG 647 | done 648 | fi 649 | echo "" 650 | echo "Okay, that was all I needed. We are ready to setup your OpenVPN server now." 651 | echo "You will be able to generate a client at the end of the installation." 652 | APPROVE_INSTALL=${APPROVE_INSTALL:-n} 653 | if [[ $APPROVE_INSTALL =~ n ]]; then 654 | read -n1 -r -p "Press any key to continue..." 655 | fi 656 | } 657 | 658 | function installOpenVPN() { 659 | if [[ $AUTO_INSTALL == "y" ]]; then 660 | # Set default choices so that no questions will be asked. 661 | APPROVE_INSTALL=${APPROVE_INSTALL:-y} 662 | APPROVE_IP=${APPROVE_IP:-y} 663 | IPV6_SUPPORT=${IPV6_SUPPORT:-n} 664 | PORT_CHOICE=${PORT_CHOICE:-1} 665 | PROTOCOL_CHOICE=${PROTOCOL_CHOICE:-1} 666 | DNS=${DNS:-1} 667 | COMPRESSION_ENABLED=${COMPRESSION_ENABLED:-n} 668 | CUSTOMIZE_ENC=${CUSTOMIZE_ENC:-n} 669 | CLIENT=${CLIENT:-client} 670 | PASS=${PASS:-1} 671 | CONTINUE=${CONTINUE:-y} 672 | 673 | if [[ -z $ENDPOINT ]]; then 674 | ENDPOINT=$(resolvePublicIP) 675 | fi 676 | fi 677 | 678 | # Run setup questions first, and set other variables if auto-install 679 | installQuestions 680 | 681 | # Get the "public" interface from the default route 682 | NIC=$(ip -4 route ls | grep default | grep -Po '(?<=dev )(\S+)' | head -1) 683 | if [[ -z $NIC ]] && [[ $IPV6_SUPPORT == 'y' ]]; then 684 | NIC=$(ip -6 route show default | sed -ne 's/^default .* dev \([^ ]*\) .*$/\1/p') 685 | fi 686 | 687 | # $NIC can not be empty for script rm-openvpn-rules.sh 688 | if [[ -z $NIC ]]; then 689 | echo 690 | echo "Could not detect public interface." 691 | echo "This needs for setup MASQUERADE." 692 | until [[ $CONTINUE =~ (y|n) ]]; do 693 | read -rp "Continue? [y/n]: " -e CONTINUE 694 | done 695 | if [[ $CONTINUE == "n" ]]; then 696 | exit 1 697 | fi 698 | fi 699 | 700 | # If OpenVPN isn't installed yet, install it. This script is more-or-less 701 | # idempotent on multiple runs, but will only install OpenVPN from upstream 702 | # the first time. 703 | if [[ ! -e /etc/openvpn/server.conf ]]; then 704 | if [[ $OS =~ (debian|ubuntu) ]]; then 705 | apt-get update 706 | apt-get -y install ca-certificates gnupg 707 | # We add the OpenVPN repo to get the latest version. 708 | if [[ $VERSION_ID == "16.04" ]]; then 709 | echo "deb http://build.openvpn.net/debian/openvpn/stable xenial main" >/etc/apt/sources.list.d/openvpn.list 710 | wget -O - https://swupdate.openvpn.net/repos/repo-public.gpg | apt-key add - 711 | apt-get update 712 | fi 713 | # Ubuntu > 16.04 and Debian > 8 have OpenVPN >= 2.4 without the need of a third party repository. 714 | apt-get install -y openvpn iptables openssl wget ca-certificates curl 715 | elif [[ $OS == 'centos' ]]; then 716 | yum install -y epel-release 717 | yum install -y openvpn iptables openssl wget ca-certificates curl tar 'policycoreutils-python*' 718 | elif [[ $OS == 'oracle' ]]; then 719 | yum install -y oracle-epel-release-el8 720 | yum-config-manager --enable ol8_developer_EPEL 721 | yum install -y openvpn iptables openssl wget ca-certificates curl tar policycoreutils-python-utils 722 | elif [[ $OS == 'amzn' ]]; then 723 | amazon-linux-extras install -y epel 724 | yum install -y openvpn iptables openssl wget ca-certificates curl 725 | elif [[ $OS == 'amzn2023' ]]; then 726 | dnf install -y openvpn iptables openssl wget ca-certificates 727 | elif [[ $OS == 'fedora' ]]; then 728 | dnf install -y openvpn iptables openssl wget ca-certificates curl policycoreutils-python-utils 729 | elif [[ $OS == 'arch' ]]; then 730 | # Install required dependencies and upgrade the system 731 | pacman --needed --noconfirm -Syu openvpn iptables openssl wget ca-certificates curl 732 | fi 733 | # An old version of easy-rsa was available by default in some openvpn packages 734 | if [[ -d /etc/openvpn/easy-rsa/ ]]; then 735 | rm -rf /etc/openvpn/easy-rsa/ 736 | fi 737 | fi 738 | 739 | # Find out if the machine uses nogroup or nobody for the permissionless group 740 | if grep -qs "^nogroup:" /etc/group; then 741 | NOGROUP=nogroup 742 | else 743 | NOGROUP=nobody 744 | fi 745 | 746 | # Install the latest version of easy-rsa from source, if not already installed. 747 | if [[ ! -d /etc/openvpn/easy-rsa/ ]]; then 748 | local version="3.1.2" 749 | wget -O ~/easy-rsa.tgz https://github.com/OpenVPN/easy-rsa/releases/download/v${version}/EasyRSA-${version}.tgz 750 | mkdir -p /etc/openvpn/easy-rsa 751 | tar xzf ~/easy-rsa.tgz --strip-components=1 --no-same-owner --directory /etc/openvpn/easy-rsa 752 | rm -f ~/easy-rsa.tgz 753 | 754 | cd /etc/openvpn/easy-rsa/ || return 755 | case $CERT_TYPE in 756 | 1) 757 | echo "set_var EASYRSA_ALGO ec" >vars 758 | echo "set_var EASYRSA_CURVE $CERT_CURVE" >>vars 759 | ;; 760 | 2) 761 | echo "set_var EASYRSA_KEY_SIZE $RSA_KEY_SIZE" >vars 762 | ;; 763 | esac 764 | 765 | # Generate a random, alphanumeric identifier of 16 characters for CN and one for server name 766 | SERVER_CN="cn_$(head /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 16 | head -n 1)" 767 | echo "$SERVER_CN" >SERVER_CN_GENERATED 768 | SERVER_NAME="server_$(head /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 16 | head -n 1)" 769 | echo "$SERVER_NAME" >SERVER_NAME_GENERATED 770 | 771 | # Create the PKI, set up the CA, the DH params and the server certificate 772 | ./easyrsa init-pki 773 | EASYRSA_CA_EXPIRE=3650 ./easyrsa --batch --req-cn="$SERVER_CN" build-ca nopass 774 | 775 | if [[ $DH_TYPE == "2" ]]; then 776 | # ECDH keys are generated on-the-fly so we don't need to generate them beforehand 777 | openssl dhparam -out dh.pem $DH_KEY_SIZE 778 | fi 779 | 780 | EASYRSA_CERT_EXPIRE=3650 ./easyrsa --batch build-server-full "$SERVER_NAME" nopass 781 | EASYRSA_CRL_DAYS=3650 ./easyrsa gen-crl 782 | 783 | case $TLS_SIG in 784 | 1) 785 | # Generate tls-crypt key 786 | openvpn --genkey --secret /etc/openvpn/tls-crypt.key 787 | ;; 788 | 2) 789 | # Generate tls-auth key 790 | openvpn --genkey --secret /etc/openvpn/tls-auth.key 791 | ;; 792 | esac 793 | else 794 | # If easy-rsa is already installed, grab the generated SERVER_NAME 795 | # for client configs 796 | cd /etc/openvpn/easy-rsa/ || return 797 | SERVER_NAME=$(cat SERVER_NAME_GENERATED) 798 | fi 799 | 800 | # Move all the generated files 801 | cp pki/ca.crt pki/private/ca.key "pki/issued/$SERVER_NAME.crt" "pki/private/$SERVER_NAME.key" /etc/openvpn/easy-rsa/pki/crl.pem /etc/openvpn 802 | if [[ $DH_TYPE == "2" ]]; then 803 | cp dh.pem /etc/openvpn 804 | fi 805 | 806 | # Make cert revocation list readable for non-root 807 | chmod 644 /etc/openvpn/crl.pem 808 | 809 | # Generate server.conf 810 | echo "port $PORT" >/etc/openvpn/server.conf 811 | if [[ $IPV6_SUPPORT == 'n' ]]; then 812 | echo "proto $PROTOCOL" >>/etc/openvpn/server.conf 813 | elif [[ $IPV6_SUPPORT == 'y' ]]; then 814 | echo "proto ${PROTOCOL}6" >>/etc/openvpn/server.conf 815 | fi 816 | 817 | echo "dev tun 818 | user nobody 819 | group $NOGROUP 820 | persist-key 821 | persist-tun 822 | keepalive 10 120 823 | topology subnet 824 | server 10.8.0.0 255.255.255.0 825 | ifconfig-pool-persist ipp.txt" >>/etc/openvpn/server.conf 826 | 827 | # DNS resolvers 828 | case $DNS in 829 | 1) # Current system resolvers 830 | # Locate the proper resolv.conf 831 | # Needed for systems running systemd-resolved 832 | if grep -q "127.0.0.53" "/etc/resolv.conf"; then 833 | RESOLVCONF='/run/systemd/resolve/resolv.conf' 834 | else 835 | RESOLVCONF='/etc/resolv.conf' 836 | fi 837 | # Obtain the resolvers from resolv.conf and use them for OpenVPN 838 | sed -ne 's/^nameserver[[:space:]]\+\([^[:space:]]\+\).*$/\1/p' $RESOLVCONF | while read -r line; do 839 | # Copy, if it's a IPv4 |or| if IPv6 is enabled, IPv4/IPv6 does not matter 840 | if [[ $line =~ ^[0-9.]*$ ]] || [[ $IPV6_SUPPORT == 'y' ]]; then 841 | echo "push \"dhcp-option DNS $line\"" >>/etc/openvpn/server.conf 842 | fi 843 | done 844 | ;; 845 | 2) # Self-hosted DNS resolver (Unbound) 846 | echo 'push "dhcp-option DNS 10.8.0.1"' >>/etc/openvpn/server.conf 847 | if [[ $IPV6_SUPPORT == 'y' ]]; then 848 | echo 'push "dhcp-option DNS fd42:42:42:42::1"' >>/etc/openvpn/server.conf 849 | fi 850 | ;; 851 | 3) # Cloudflare 852 | echo 'push "dhcp-option DNS 1.0.0.1"' >>/etc/openvpn/server.conf 853 | echo 'push "dhcp-option DNS 1.1.1.1"' >>/etc/openvpn/server.conf 854 | ;; 855 | 4) # Quad9 856 | echo 'push "dhcp-option DNS 9.9.9.9"' >>/etc/openvpn/server.conf 857 | echo 'push "dhcp-option DNS 149.112.112.112"' >>/etc/openvpn/server.conf 858 | ;; 859 | 5) # Quad9 uncensored 860 | echo 'push "dhcp-option DNS 9.9.9.10"' >>/etc/openvpn/server.conf 861 | echo 'push "dhcp-option DNS 149.112.112.10"' >>/etc/openvpn/server.conf 862 | ;; 863 | 6) # FDN 864 | echo 'push "dhcp-option DNS 80.67.169.40"' >>/etc/openvpn/server.conf 865 | echo 'push "dhcp-option DNS 80.67.169.12"' >>/etc/openvpn/server.conf 866 | ;; 867 | 7) # DNS.WATCH 868 | echo 'push "dhcp-option DNS 84.200.69.80"' >>/etc/openvpn/server.conf 869 | echo 'push "dhcp-option DNS 84.200.70.40"' >>/etc/openvpn/server.conf 870 | ;; 871 | 8) # OpenDNS 872 | echo 'push "dhcp-option DNS 208.67.222.222"' >>/etc/openvpn/server.conf 873 | echo 'push "dhcp-option DNS 208.67.220.220"' >>/etc/openvpn/server.conf 874 | ;; 875 | 9) # Google 876 | echo 'push "dhcp-option DNS 8.8.8.8"' >>/etc/openvpn/server.conf 877 | echo 'push "dhcp-option DNS 8.8.4.4"' >>/etc/openvpn/server.conf 878 | ;; 879 | 10) # Yandex Basic 880 | echo 'push "dhcp-option DNS 77.88.8.8"' >>/etc/openvpn/server.conf 881 | echo 'push "dhcp-option DNS 77.88.8.1"' >>/etc/openvpn/server.conf 882 | ;; 883 | 11) # AdGuard DNS 884 | echo 'push "dhcp-option DNS 94.140.14.14"' >>/etc/openvpn/server.conf 885 | echo 'push "dhcp-option DNS 94.140.15.15"' >>/etc/openvpn/server.conf 886 | ;; 887 | 12) # NextDNS 888 | echo 'push "dhcp-option DNS 45.90.28.167"' >>/etc/openvpn/server.conf 889 | echo 'push "dhcp-option DNS 45.90.30.167"' >>/etc/openvpn/server.conf 890 | ;; 891 | 13) # Custom DNS 892 | echo "push \"dhcp-option DNS $DNS1\"" >>/etc/openvpn/server.conf 893 | if [[ $DNS2 != "" ]]; then 894 | echo "push \"dhcp-option DNS $DNS2\"" >>/etc/openvpn/server.conf 895 | fi 896 | ;; 897 | esac 898 | echo 'push "redirect-gateway def1 bypass-dhcp"' >>/etc/openvpn/server.conf 899 | 900 | # IPv6 network settings if needed 901 | if [[ $IPV6_SUPPORT == 'y' ]]; then 902 | echo 'server-ipv6 fd42:42:42:42::/112 903 | tun-ipv6 904 | push tun-ipv6 905 | push "route-ipv6 2000::/3" 906 | push "redirect-gateway ipv6"' >>/etc/openvpn/server.conf 907 | fi 908 | 909 | if [[ $COMPRESSION_ENABLED == "y" ]]; then 910 | echo "compress $COMPRESSION_ALG" >>/etc/openvpn/server.conf 911 | fi 912 | 913 | if [[ $DH_TYPE == "1" ]]; then 914 | echo "dh none" >>/etc/openvpn/server.conf 915 | echo "ecdh-curve $DH_CURVE" >>/etc/openvpn/server.conf 916 | elif [[ $DH_TYPE == "2" ]]; then 917 | echo "dh dh.pem" >>/etc/openvpn/server.conf 918 | fi 919 | 920 | case $TLS_SIG in 921 | 1) 922 | echo "tls-crypt tls-crypt.key" >>/etc/openvpn/server.conf 923 | ;; 924 | 2) 925 | echo "tls-auth tls-auth.key 0" >>/etc/openvpn/server.conf 926 | ;; 927 | esac 928 | 929 | echo "crl-verify crl.pem 930 | ca ca.crt 931 | cert $SERVER_NAME.crt 932 | key $SERVER_NAME.key 933 | auth $HMAC_ALG 934 | cipher $CIPHER 935 | ncp-ciphers $CIPHER 936 | tls-server 937 | tls-version-min 1.2 938 | tls-cipher $CC_CIPHER 939 | client-config-dir /etc/openvpn/ccd 940 | status /var/log/openvpn/status.log 941 | verb 3" >>/etc/openvpn/server.conf 942 | 943 | # Create client-config-dir dir 944 | mkdir -p /etc/openvpn/ccd 945 | # Create log dir 946 | mkdir -p /var/log/openvpn 947 | 948 | # Enable routing 949 | echo 'net.ipv4.ip_forward=1' >/etc/sysctl.d/99-openvpn.conf 950 | if [[ $IPV6_SUPPORT == 'y' ]]; then 951 | echo 'net.ipv6.conf.all.forwarding=1' >>/etc/sysctl.d/99-openvpn.conf 952 | fi 953 | # Apply sysctl rules 954 | sysctl --system 955 | 956 | # If SELinux is enabled and a custom port was selected, we need this 957 | if hash sestatus 2>/dev/null; then 958 | if sestatus | grep "Current mode" | grep -qs "enforcing"; then 959 | if [[ $PORT != '1194' ]]; then 960 | semanage port -a -t openvpn_port_t -p "$PROTOCOL" "$PORT" 961 | fi 962 | fi 963 | fi 964 | 965 | # Finally, restart and enable OpenVPN 966 | if [[ $OS == 'arch' || $OS == 'fedora' || $OS == 'centos' || $OS == 'oracle' || $OS == 'amzn2023' ]]; then 967 | # Don't modify package-provided service 968 | cp /usr/lib/systemd/system/openvpn-server@.service /etc/systemd/system/openvpn-server@.service 969 | 970 | # Workaround to fix OpenVPN service on OpenVZ 971 | sed -i 's|LimitNPROC|#LimitNPROC|' /etc/systemd/system/openvpn-server@.service 972 | # Another workaround to keep using /etc/openvpn/ 973 | sed -i 's|/etc/openvpn/server|/etc/openvpn|' /etc/systemd/system/openvpn-server@.service 974 | 975 | systemctl daemon-reload 976 | systemctl enable openvpn-server@server 977 | systemctl restart openvpn-server@server 978 | elif [[ $OS == "ubuntu" ]] && [[ $VERSION_ID == "16.04" ]]; then 979 | # On Ubuntu 16.04, we use the package from the OpenVPN repo 980 | # This package uses a sysvinit service 981 | systemctl enable openvpn 982 | systemctl start openvpn 983 | else 984 | # Don't modify package-provided service 985 | cp /lib/systemd/system/openvpn\@.service /etc/systemd/system/openvpn\@.service 986 | 987 | # Workaround to fix OpenVPN service on OpenVZ 988 | sed -i 's|LimitNPROC|#LimitNPROC|' /etc/systemd/system/openvpn\@.service 989 | # Another workaround to keep using /etc/openvpn/ 990 | sed -i 's|/etc/openvpn/server|/etc/openvpn|' /etc/systemd/system/openvpn\@.service 991 | 992 | systemctl daemon-reload 993 | systemctl enable openvpn@server 994 | systemctl restart openvpn@server 995 | fi 996 | 997 | if [[ $DNS == 2 ]]; then 998 | installUnbound 999 | fi 1000 | 1001 | # Add iptables rules in two scripts 1002 | mkdir -p /etc/iptables 1003 | 1004 | # Script to add rules 1005 | echo "#!/bin/sh 1006 | iptables -t nat -I POSTROUTING 1 -s 10.8.0.0/24 -o $NIC -j MASQUERADE 1007 | iptables -I INPUT 1 -i tun0 -j ACCEPT 1008 | iptables -I FORWARD 1 -i $NIC -o tun0 -j ACCEPT 1009 | iptables -I FORWARD 1 -i tun0 -o $NIC -j ACCEPT 1010 | iptables -I INPUT 1 -i $NIC -p $PROTOCOL --dport $PORT -j ACCEPT" >/etc/iptables/add-openvpn-rules.sh 1011 | 1012 | if [[ $IPV6_SUPPORT == 'y' ]]; then 1013 | echo "ip6tables -t nat -I POSTROUTING 1 -s fd42:42:42:42::/112 -o $NIC -j MASQUERADE 1014 | ip6tables -I INPUT 1 -i tun0 -j ACCEPT 1015 | ip6tables -I FORWARD 1 -i $NIC -o tun0 -j ACCEPT 1016 | ip6tables -I FORWARD 1 -i tun0 -o $NIC -j ACCEPT 1017 | ip6tables -I INPUT 1 -i $NIC -p $PROTOCOL --dport $PORT -j ACCEPT" >>/etc/iptables/add-openvpn-rules.sh 1018 | fi 1019 | 1020 | # Script to remove rules 1021 | echo "#!/bin/sh 1022 | iptables -t nat -D POSTROUTING -s 10.8.0.0/24 -o $NIC -j MASQUERADE 1023 | iptables -D INPUT -i tun0 -j ACCEPT 1024 | iptables -D FORWARD -i $NIC -o tun0 -j ACCEPT 1025 | iptables -D FORWARD -i tun0 -o $NIC -j ACCEPT 1026 | iptables -D INPUT -i $NIC -p $PROTOCOL --dport $PORT -j ACCEPT" >/etc/iptables/rm-openvpn-rules.sh 1027 | 1028 | if [[ $IPV6_SUPPORT == 'y' ]]; then 1029 | echo "ip6tables -t nat -D POSTROUTING -s fd42:42:42:42::/112 -o $NIC -j MASQUERADE 1030 | ip6tables -D INPUT -i tun0 -j ACCEPT 1031 | ip6tables -D FORWARD -i $NIC -o tun0 -j ACCEPT 1032 | ip6tables -D FORWARD -i tun0 -o $NIC -j ACCEPT 1033 | ip6tables -D INPUT -i $NIC -p $PROTOCOL --dport $PORT -j ACCEPT" >>/etc/iptables/rm-openvpn-rules.sh 1034 | fi 1035 | 1036 | chmod +x /etc/iptables/add-openvpn-rules.sh 1037 | chmod +x /etc/iptables/rm-openvpn-rules.sh 1038 | 1039 | # Handle the rules via a systemd script 1040 | echo "[Unit] 1041 | Description=iptables rules for OpenVPN 1042 | Before=network-online.target 1043 | Wants=network-online.target 1044 | 1045 | [Service] 1046 | Type=oneshot 1047 | ExecStart=/etc/iptables/add-openvpn-rules.sh 1048 | ExecStop=/etc/iptables/rm-openvpn-rules.sh 1049 | RemainAfterExit=yes 1050 | 1051 | [Install] 1052 | WantedBy=multi-user.target" >/etc/systemd/system/iptables-openvpn.service 1053 | 1054 | # Enable service and apply rules 1055 | systemctl daemon-reload 1056 | systemctl enable iptables-openvpn 1057 | systemctl start iptables-openvpn 1058 | 1059 | # If the server is behind a NAT, use the correct IP address for the clients to connect to 1060 | if [[ $ENDPOINT != "" ]]; then 1061 | IP=$ENDPOINT 1062 | fi 1063 | 1064 | # client-template.txt is created so we have a template to add further users later 1065 | echo "client" >/etc/openvpn/client-template.txt 1066 | if [[ $PROTOCOL == 'udp' ]]; then 1067 | echo "proto udp" >>/etc/openvpn/client-template.txt 1068 | echo "explicit-exit-notify" >>/etc/openvpn/client-template.txt 1069 | elif [[ $PROTOCOL == 'tcp' ]]; then 1070 | echo "proto tcp-client" >>/etc/openvpn/client-template.txt 1071 | fi 1072 | echo "remote $IP $PORT 1073 | dev tun 1074 | resolv-retry infinite 1075 | nobind 1076 | persist-key 1077 | persist-tun 1078 | remote-cert-tls server 1079 | verify-x509-name $SERVER_NAME name 1080 | auth $HMAC_ALG 1081 | auth-nocache 1082 | cipher $CIPHER 1083 | tls-client 1084 | tls-version-min 1.2 1085 | tls-cipher $CC_CIPHER 1086 | ignore-unknown-option block-outside-dns 1087 | setenv opt block-outside-dns # Prevent Windows 10 DNS leak 1088 | verb 3" >>/etc/openvpn/client-template.txt 1089 | 1090 | if [[ $COMPRESSION_ENABLED == "y" ]]; then 1091 | echo "compress $COMPRESSION_ALG" >>/etc/openvpn/client-template.txt 1092 | fi 1093 | 1094 | # Generate the custom client.ovpn 1095 | newClient 1096 | echo "If you want to add more clients, you simply need to run this script another time!" 1097 | } 1098 | 1099 | function newClient() { 1100 | echo "" 1101 | echo "Tell me a name for the client." 1102 | echo "The name must consist of alphanumeric character. It may also include an underscore or a dash." 1103 | 1104 | until [[ $CLIENT =~ ^[a-zA-Z0-9_-]+$ ]]; do 1105 | read -rp "Client name: " -e CLIENT 1106 | done 1107 | 1108 | echo "" 1109 | echo "Do you want to protect the configuration file with a password?" 1110 | echo "(e.g. encrypt the private key with a password)" 1111 | echo " 1) Add a passwordless client" 1112 | echo " 2) Use a password for the client" 1113 | 1114 | until [[ $PASS =~ ^[1-2]$ ]]; do 1115 | read -rp "Select an option [1-2]: " -e -i 1 PASS 1116 | done 1117 | 1118 | CLIENTEXISTS=$(tail -n +2 /etc/openvpn/easy-rsa/pki/index.txt | grep -c -E "/CN=$CLIENT\quot;) 1119 | if [[ $CLIENTEXISTS == '1' ]]; then 1120 | echo "" 1121 | echo "The specified client CN was already found in easy-rsa, please choose another name." 1122 | exit 1123 | else 1124 | cd /etc/openvpn/easy-rsa/ || return 1125 | case $PASS in 1126 | 1) 1127 | EASYRSA_CERT_EXPIRE=3650 ./easyrsa --batch build-client-full "$CLIENT" nopass 1128 | ;; 1129 | 2) 1130 | echo "⚠️ You will be asked for the client password below ⚠️" 1131 | EASYRSA_CERT_EXPIRE=3650 ./easyrsa --batch build-client-full "$CLIENT" 1132 | ;; 1133 | esac 1134 | echo "Client $CLIENT added." 1135 | fi 1136 | 1137 | # Home directory of the user, where the client configuration will be written 1138 | if [ -e "/home/${CLIENT}" ]; then 1139 | # if $1 is a user name 1140 | homeDir="/home/${CLIENT}" 1141 | elif [ "${SUDO_USER}" ]; then 1142 | # if not, use SUDO_USER 1143 | if [ "${SUDO_USER}" == "root" ]; then 1144 | # If running sudo as root 1145 | homeDir="/root" 1146 | else 1147 | homeDir="/home/${SUDO_USER}" 1148 | fi 1149 | else 1150 | # if not SUDO_USER, use /root 1151 | homeDir="/root" 1152 | fi 1153 | 1154 | # Determine if we use tls-auth or tls-crypt 1155 | if grep -qs "^tls-crypt" /etc/openvpn/server.conf; then 1156 | TLS_SIG="1" 1157 | elif grep -qs "^tls-auth" /etc/openvpn/server.conf; then 1158 | TLS_SIG="2" 1159 | fi 1160 | 1161 | # Generates the custom client.ovpn 1162 | cp /etc/openvpn/client-template.txt "$homeDir/$CLIENT.ovpn" 1163 | { 1164 | echo "<ca>" 1165 | cat "/etc/openvpn/easy-rsa/pki/ca.crt" 1166 | echo "</ca>" 1167 | 1168 | echo "<cert>" 1169 | awk '/BEGIN/,/END CERTIFICATE/' "/etc/openvpn/easy-rsa/pki/issued/$CLIENT.crt" 1170 | echo "</cert>" 1171 | 1172 | echo "<key>" 1173 | cat "/etc/openvpn/easy-rsa/pki/private/$CLIENT.key" 1174 | echo "</key>" 1175 | 1176 | case $TLS_SIG in 1177 | 1) 1178 | echo "<tls-crypt>" 1179 | cat /etc/openvpn/tls-crypt.key 1180 | echo "</tls-crypt>" 1181 | ;; 1182 | 2) 1183 | echo "key-direction 1" 1184 | echo "<tls-auth>" 1185 | cat /etc/openvpn/tls-auth.key 1186 | echo "</tls-auth>" 1187 | ;; 1188 | esac 1189 | } >>"$homeDir/$CLIENT.ovpn" 1190 | 1191 | echo "" 1192 | echo "The configuration file has been written to $homeDir/$CLIENT.ovpn." 1193 | echo "Download the .ovpn file and import it in your OpenVPN client." 1194 | 1195 | exit 0 1196 | } 1197 | 1198 | function revokeClient() { 1199 | NUMBEROFCLIENTS=$(tail -n +2 /etc/openvpn/easy-rsa/pki/index.txt | grep -c "^V") 1200 | if [[ $NUMBEROFCLIENTS == '0' ]]; then 1201 | echo "" 1202 | echo "You have no existing clients!" 1203 | exit 1 1204 | fi 1205 | 1206 | echo "" 1207 | echo "Select the existing client certificate you want to revoke" 1208 | tail -n +2 /etc/openvpn/easy-rsa/pki/index.txt | grep "^V" | cut -d '=' -f 2 | nl -s ') ' 1209 | until [[ $CLIENTNUMBER -ge 1 && $CLIENTNUMBER -le $NUMBEROFCLIENTS ]]; do 1210 | if [[ $CLIENTNUMBER == '1' ]]; then 1211 | read -rp "Select one client [1]: " CLIENTNUMBER 1212 | else 1213 | read -rp "Select one client [1-$NUMBEROFCLIENTS]: " CLIENTNUMBER 1214 | fi 1215 | done 1216 | CLIENT=$(tail -n +2 /etc/openvpn/easy-rsa/pki/index.txt | grep "^V" | cut -d '=' -f 2 | sed -n "$CLIENTNUMBER"p) 1217 | cd /etc/openvpn/easy-rsa/ || return 1218 | ./easyrsa --batch revoke "$CLIENT" 1219 | EASYRSA_CRL_DAYS=3650 ./easyrsa gen-crl 1220 | rm -f /etc/openvpn/crl.pem 1221 | cp /etc/openvpn/easy-rsa/pki/crl.pem /etc/openvpn/crl.pem 1222 | chmod 644 /etc/openvpn/crl.pem 1223 | find /home/ -maxdepth 2 -name "$CLIENT.ovpn" -delete 1224 | rm -f "/root/$CLIENT.ovpn" 1225 | sed -i "/^$CLIENT,.*/d" /etc/openvpn/ipp.txt 1226 | cp /etc/openvpn/easy-rsa/pki/index.txt{,.bk} 1227 | 1228 | echo "" 1229 | echo "Certificate for client $CLIENT revoked." 1230 | } 1231 | 1232 | function removeUnbound() { 1233 | # Remove OpenVPN-related config 1234 | sed -i '/include: \/etc\/unbound\/openvpn.conf/d' /etc/unbound/unbound.conf 1235 | rm /etc/unbound/openvpn.conf 1236 | 1237 | until [[ $REMOVE_UNBOUND =~ (y|n) ]]; do 1238 | echo "" 1239 | echo "If you were already using Unbound before installing OpenVPN, I removed the configuration related to OpenVPN." 1240 | read -rp "Do you want to completely remove Unbound? [y/n]: " -e REMOVE_UNBOUND 1241 | done 1242 | 1243 | if [[ $REMOVE_UNBOUND == 'y' ]]; then 1244 | # Stop Unbound 1245 | systemctl stop unbound 1246 | 1247 | if [[ $OS =~ (debian|ubuntu) ]]; then 1248 | apt-get remove --purge -y unbound 1249 | elif [[ $OS == 'arch' ]]; then 1250 | pacman --noconfirm -R unbound 1251 | elif [[ $OS =~ (centos|amzn|oracle) ]]; then 1252 | yum remove -y unbound 1253 | elif [[ $OS == 'fedora' ]]; then 1254 | dnf remove -y unbound 1255 | fi 1256 | 1257 | rm -rf /etc/unbound/ 1258 | 1259 | echo "" 1260 | echo "Unbound removed!" 1261 | else 1262 | systemctl restart unbound 1263 | echo "" 1264 | echo "Unbound wasn't removed." 1265 | fi 1266 | } 1267 | 1268 | function removeOpenVPN() { 1269 | echo "" 1270 | read -rp "Do you really want to remove OpenVPN? [y/n]: " -e -i n REMOVE 1271 | if [[ $REMOVE == 'y' ]]; then 1272 | # Get OpenVPN port from the configuration 1273 | PORT=$(grep '^port ' /etc/openvpn/server.conf | cut -d " " -f 2) 1274 | PROTOCOL=$(grep '^proto ' /etc/openvpn/server.conf | cut -d " " -f 2) 1275 | 1276 | # Stop OpenVPN 1277 | if [[ $OS =~ (fedora|arch|centos|oracle) ]]; then 1278 | systemctl disable openvpn-server@server 1279 | systemctl stop openvpn-server@server 1280 | # Remove customised service 1281 | rm /etc/systemd/system/openvpn-server@.service 1282 | elif [[ $OS == "ubuntu" ]] && [[ $VERSION_ID == "16.04" ]]; then 1283 | systemctl disable openvpn 1284 | systemctl stop openvpn 1285 | else 1286 | systemctl disable openvpn@server 1287 | systemctl stop openvpn@server 1288 | # Remove customised service 1289 | rm /etc/systemd/system/openvpn\@.service 1290 | fi 1291 | 1292 | # Remove the iptables rules related to the script 1293 | systemctl stop iptables-openvpn 1294 | # Cleanup 1295 | systemctl disable iptables-openvpn 1296 | rm /etc/systemd/system/iptables-openvpn.service 1297 | systemctl daemon-reload 1298 | rm /etc/iptables/add-openvpn-rules.sh 1299 | rm /etc/iptables/rm-openvpn-rules.sh 1300 | 1301 | # SELinux 1302 | if hash sestatus 2>/dev/null; then 1303 | if sestatus | grep "Current mode" | grep -qs "enforcing"; then 1304 | if [[ $PORT != '1194' ]]; then 1305 | semanage port -d -t openvpn_port_t -p "$PROTOCOL" "$PORT" 1306 | fi 1307 | fi 1308 | fi 1309 | 1310 | if [[ $OS =~ (debian|ubuntu) ]]; then 1311 | apt-get remove --purge -y openvpn 1312 | if [[ -e /etc/apt/sources.list.d/openvpn.list ]]; then 1313 | rm /etc/apt/sources.list.d/openvpn.list 1314 | apt-get update 1315 | fi 1316 | elif [[ $OS == 'arch' ]]; then 1317 | pacman --noconfirm -R openvpn 1318 | elif [[ $OS =~ (centos|amzn|oracle) ]]; then 1319 | yum remove -y openvpn 1320 | elif [[ $OS == 'fedora' ]]; then 1321 | dnf remove -y openvpn 1322 | fi 1323 | 1324 | # Cleanup 1325 | find /home/ -maxdepth 2 -name "*.ovpn" -delete 1326 | find /root/ -maxdepth 1 -name "*.ovpn" -delete 1327 | rm -rf /etc/openvpn 1328 | rm -rf /usr/share/doc/openvpn* 1329 | rm -f /etc/sysctl.d/99-openvpn.conf 1330 | rm -rf /var/log/openvpn 1331 | 1332 | # Unbound 1333 | if [[ -e /etc/unbound/openvpn.conf ]]; then 1334 | removeUnbound 1335 | fi 1336 | echo "" 1337 | echo "OpenVPN removed!" 1338 | else 1339 | echo "" 1340 | echo "Removal aborted!" 1341 | fi 1342 | } 1343 | 1344 | function manageMenu() { 1345 | echo "Welcome to OpenVPN-install!" 1346 | echo "The git repository is available at: https://github.com/angristan/openvpn-install" 1347 | echo "" 1348 | echo "It looks like OpenVPN is already installed." 1349 | echo "" 1350 | echo "What do you want to do?" 1351 | echo " 1) Add a new user" 1352 | echo " 2) Revoke existing user" 1353 | echo " 3) Remove OpenVPN" 1354 | echo " 4) Exit" 1355 | until [[ $MENU_OPTION =~ ^[1-4]$ ]]; do 1356 | read -rp "Select an option [1-4]: " MENU_OPTION 1357 | done 1358 | 1359 | case $MENU_OPTION in 1360 | 1) 1361 | newClient 1362 | ;; 1363 | 2) 1364 | revokeClient 1365 | ;; 1366 | 3) 1367 | removeOpenVPN 1368 | ;; 1369 | 4) 1370 | exit 0 1371 | ;; 1372 | esac 1373 | } 1374 | 1375 | # Check for root, TUN, OS... 1376 | initialCheck 1377 | 1378 | # Check if OpenVPN is already installed 1379 | if [[ -e /etc/openvpn/server.conf && $AUTO_INSTALL != "y" ]]; then 1380 | manageMenu 1381 | else 1382 | installOpenVPN 1383 | fi 1384 | --------------------------------------------------------------------------------