## Summary - Add TLS 1.3 support with `--tls-version-min` and `--tls-ciphersuites` - Replace deprecated `ecdh-curve` with `tls-groups` - Remove traditional DH support (OpenVPN 2.7 defaults to ECDH) ## New options | Option | Default | |--------|---------| | `--tls-version-min` | `1.2` | | `--tls-ciphersuites` | `TLS_AES_256_GCM_SHA384:TLS_AES_128_GCM_SHA256:TLS_CHACHA20_POLY1305_SHA256` | | `--tls-groups` | `X25519:prime256v1:secp384r1:secp521r1` | ## Removed - `--dh-type`, `--dh-bits`, `--dh-curve` - DH parameter generation Closes https://github.com/angristan/openvpn-install/issues/1231 Closes https://github.com/angristan/openvpn-install/issues/637 Closes https://github.com/angristan/openvpn-install/issues/1362
openvpn-install
OpenVPN installer for Debian, Ubuntu, Fedora, openSUSE, CentOS, Amazon Linux, Arch Linux, Oracle Linux, Rocky Linux and AlmaLinux.
This script will let you setup and manage your own secure VPN server in just a few seconds.
What is this?
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.
Once set up, you will be able to generate client configuration files for every device you want to connect.
Each client will be able to route its internet traffic through the server, fully encrypted.
graph LR
A[Phone] -->|Encrypted| VPN
B[Laptop] -->|Encrypted| VPN
C[Computer] -->|Encrypted| VPN
VPN[OpenVPN Server]
VPN --> I[Internet]
Why OpenVPN?
OpenVPN was the de facto standard for open-source VPNs when this script was created. WireGuard came later and is simpler and faster for most use cases. Check out wireguard-install.
That said, OpenVPN still makes sense when you need:
- TCP support: works in restrictive environments where UDP is blocked (corporate networks, airports, hotels, etc.)
- Password-protected private keys: WireGuard configs store the private key in plain text
- Legacy compatibility: clients exist for pretty much every platform, including older systems
Features
- Installs and configures a ready-to-use OpenVPN server
- CLI interface for automation and scripting (non-interactive mode with JSON output)
- Certificate renewal for both client and server certificates
- List and monitor connected clients
- Uses official OpenVPN repositories when possible for the latest stable releases
- Firewall rules and forwarding managed seamlessly (native firewalld and nftables support, iptables fallback)
- Configurable VPN subnet (default:
10.8.0.0/24) - Configurable tunnel MTU (default:
1500) - If needed, the script can cleanly remove OpenVPN, including configuration and firewall rules
- Customisable encryption settings, enhanced default settings (see Security and Encryption below)
- Uses latest OpenVPN features when available (see Security and Encryption below)
- Variety of DNS resolvers to be pushed to the clients
- Choice to use a self-hosted resolver with Unbound (supports already existing Unbound installations)
- Choice between TCP and UDP
- NATed IPv6 support
- Unprivileged mode: run as
nobody/nogroup - Block DNS leaks on Windows 10
- Randomised server certificate name
- Choice to protect clients with a password (private key encryption)
- Option to allow multiple devices to use the same client profile simultaneously (disables persistent IP addresses)
- Many other little things!
Compatibility
The script supports these Linux distributions:
| Support | |
|---|---|
| AlmaLinux >= 8 | ✅ 🤖 |
| Amazon Linux 2023 | ✅ 🤖 |
| Arch Linux | ✅ 🤖 |
| CentOS Stream >= 8 | ✅ 🤖 |
| Debian >= 11 | ✅ 🤖 |
| Fedora >= 40 | ✅ 🤖 |
| openSUSE Leap >= 16 | ✅ 🤖 |
| openSUSE Tumbleweed | ✅ 🤖 |
| Oracle Linux >= 8 | ✅ 🤖 |
| Rocky Linux >= 8 | ✅ 🤖 |
| Ubuntu >= 18.04 | ✅ 🤖 |
To be noted:
- The script is regularly tested against the distributions marked with a 🤖 only.
- It's only tested on
amd64architecture.
- It's only tested on
- The script requires
systemd.
Usage
First, download the script on your server and make it executable:
curl -O https://raw.githubusercontent.com/angristan/openvpn-install/master/openvpn-install.sh
chmod +x openvpn-install.sh
You need to run the script as root and have the TUN module enabled.
Interactive Mode
The easiest way to get started is the interactive menu:
./openvpn-install.sh interactive
This will guide you through installation and client management.
In your home directory, you will have .ovpn files. These are the client configuration files. Download them from your server (using scp for example) and connect using your favorite OpenVPN client.
If you have any question, head to the FAQ first. And if you need help, you can open a discussion. Please search existing issues and discussions first.
CLI Mode
Warning
API compatibility is not guaranteed. Breaking changes may occur between versions. If you use this script programmatically (e.g., in automation or CI/CD), pin to a specific commit rather than using the master branch.
For automation and scripting, use the CLI interface:
# Install with defaults
./openvpn-install.sh install
# Add a client
./openvpn-install.sh client add alice
# List clients
./openvpn-install.sh client list
# Revoke a client
./openvpn-install.sh client revoke alice
Commands
openvpn-install <command> [options]
Commands:
install Install and configure OpenVPN server
uninstall Remove OpenVPN server
client Manage client certificates
server Server management
interactive Launch interactive menu
Global Options:
--verbose Show detailed output
--log <path> Log file path (default: openvpn-install.log)
--no-log Disable file logging
--no-color Disable colored output
-h, --help Show help
Run ./openvpn-install.sh <command> --help for command-specific options.
Client Management
# Add a new client
./openvpn-install.sh client add alice
# Add a password-protected client
./openvpn-install.sh client add bob --password
# Revoke a client
./openvpn-install.sh client revoke alice
# Renew a client certificate
./openvpn-install.sh client renew bob --cert-days 365
List all clients:
$ ./openvpn-install.sh client list
══ Client Certificates ══
[INFO] Found 3 client certificate(s)
Name Status Expiry Remaining
---- ------ ------ ---------
alice Valid 2035-01-15 3650 days
bob Valid 2035-01-15 3650 days
charlie Revoked 2035-01-15 unknown
JSON output for scripting:
$ ./openvpn-install.sh client list --format json | jq
{
"clients": [
{
"name": "alice",
"status": "valid",
"expiry": "2035-01-15",
"days_remaining": 3650
},
{
"name": "bob",
"status": "valid",
"expiry": "2035-01-15",
"days_remaining": 3650
},
{
"name": "charlie",
"status": "revoked",
"expiry": "2035-01-15",
"days_remaining": null
}
]
}
Server Management
# Renew server certificate
./openvpn-install.sh server renew
# Uninstall OpenVPN
./openvpn-install.sh uninstall
Show connected clients (data refreshes every 60 seconds):
$ ./openvpn-install.sh server status
══ Connected Clients ══
[INFO] Found 2 connected client(s)
Name Real Address VPN IP Connected Since Transfer
---- ------------ ------ --------------- --------
alice 203.0.113.45:52341 10.8.0.2 2025-01-15 14:32 ↓1.2M ↑500K
bob 198.51.100.22:41892 10.8.0.3 2025-01-15 09:15 ↓800K ↑200K
[INFO] Note: Data refreshes every 60 seconds.
Install Options
The install command supports many options for customization:
# Custom port and protocol
./openvpn-install.sh install --port 443 --protocol tcp
# Custom DNS provider
./openvpn-install.sh install --dns quad9
# Custom encryption settings
./openvpn-install.sh install --cipher AES-256-GCM --cert-type rsa --rsa-bits 4096
# Custom VPN subnet
./openvpn-install.sh install --subnet 10.9.0.0
# Skip initial client creation
./openvpn-install.sh install --no-client
# Full example with multiple options
./openvpn-install.sh install \
--port 443 \
--protocol tcp \
--dns cloudflare \
--cipher AES-256-GCM \
--client mydevice \
--client-cert-days 365
Network Options:
--endpoint <host>- Public IP or hostname for clients (default: auto-detected)--ip <addr>- Server listening IP (default: auto-detected)--ipv6- Enable IPv6 support (default: disabled)--subnet <x.x.x.0>- VPN subnet (default:10.8.0.0)--port <num>- OpenVPN port (default:1194)--port-random- Use random port (49152-65535)--protocol <udp|tcp>- Protocol (default:udp)--mtu <size>- Tunnel MTU (default:1500)
DNS Options:
--dns <provider>- DNS provider (default:cloudflare). Options:system,unbound,cloudflare,quad9,quad9-uncensored,fdn,dnswatch,opendns,google,yandex,adguard,nextdns,custom--dns-primary <ip>- Custom primary DNS (requires--dns custom)--dns-secondary <ip>- Custom secondary DNS (requires--dns custom)
Security Options:
--cipher <cipher>- Data cipher (default:AES-128-GCM). Options:AES-128-GCM,AES-192-GCM,AES-256-GCM,AES-128-CBC,AES-192-CBC,AES-256-CBC,CHACHA20-POLY1305--cert-type <ecdsa|rsa>- Certificate type (default:ecdsa)--cert-curve <curve>- ECDSA curve (default:prime256v1). Options:prime256v1,secp384r1,secp521r1--rsa-bits <2048|3072|4096>- RSA key size (default:2048)--hmac <alg>- HMAC algorithm (default:SHA256). Options:SHA256,SHA384,SHA512--tls-sig <mode>- TLS mode (default:crypt-v2). Options:crypt-v2,crypt,auth--tls-version-min <1.2|1.3>- Minimum TLS version (default:1.2)--tls-ciphersuites <list>- TLS 1.3 cipher suites, colon-separated (default:TLS_AES_256_GCM_SHA384:TLS_AES_128_GCM_SHA256:TLS_CHACHA20_POLY1305_SHA256)--tls-groups <list>- Key exchange groups, colon-separated (default:X25519:prime256v1:secp384r1:secp521r1)--server-cert-days <n>- Server cert validity in days (default:3650)
Client Options:
--client <name>- Initial client name (default:client)--client-password [pass]- Password-protect client key (default: no password)--client-cert-days <n>- Client cert validity in days (default:3650)--no-client- Skip initial client creation
Other Options:
--multi-client- Allow same cert on multiple devices (default: disabled)
Automation Examples
Batch client creation:
#!/bin/bash
for user in alice bob charlie; do
./openvpn-install.sh client add "$user"
done
Create clients from a file:
#!/bin/bash
while read -r user; do
./openvpn-install.sh client add "$user"
done < users.txt
JSON output for scripting:
# Get client list as JSON
./openvpn-install.sh client list --format json | jq '.clients[] | select(.status == "valid")'
# Get connected clients as JSON
./openvpn-install.sh server status --format json
Fork
This script is based on the great work of Nyr and its contributors.
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.
FAQ
More Q&A in FAQ.md.
Q: Which provider do you recommend?
A: I recommend these:
- Vultr: Worldwide locations, IPv6 support, starting at $5/month
- Hetzner: Germany, Finland and USA. IPv6, 20 TB of traffic, starting at 4.5€/month
- Digital Ocean: Worldwide locations, IPv6 support, starting at $4/month
Q: Which OpenVPN client do you recommend?
A: If possible, an official OpenVPN 2.4 client.
- Windows: The official OpenVPN community client.
- Linux: The
openvpnpackage from your distribution. There is an official APT repository for Debian/Ubuntu based distributions. - macOS: Tunnelblick, Viscosity, OpenVPN for Mac.
- Android: OpenVPN for Android.
- iOS: The official OpenVPN Connect client.
Q: Am I safe from the NSA by using your script?
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.
Q: Is there an OpenVPN documentation?
A: Yes, please head to the OpenVPN Manual, which references all the options.
More Q&A in FAQ.md.
Contributing
Discuss changes
Please open an issue before submitting a PR if you want to discuss a change, especially if it's a big one.
Security and Encryption
Note
This script was created in 2016 when OpenVPN's defaults were quite weak. Back then, customising encryption settings was essential for a secure setup. Since then, OpenVPN has significantly improved its defaults, but the script still offers customisation options.
OpenVPN 2.3 and earlier shipped with outdated defaults like Blowfish (BF-CBC), TLS 1.0, and SHA1. Each major release since has brought significant improvements:
- OpenVPN 2.4 (2016): Added ECDSA, ECDH, AES-GCM, NCP (cipher negotiation), and tls-crypt
- OpenVPN 2.5 (2020): Default cipher changed from BF-CBC to AES-256-GCM:AES-128-GCM, added ChaCha20-Poly1305, tls-crypt-v2, and TLS 1.3 support
- OpenVPN 2.6 (2023): TLS 1.2 minimum by default, compression blocked by default,
--peer-fingerprintfor PKI-less setups, and DCO kernel acceleration
If you want more information about an option mentioned below, head to the OpenVPN manual. It is very complete.
Certificate and PKI management is handled by Easy-RSA. Default parameters are in the vars.example file.
Compression
This script used to support LZ4 and LZO compression algorithms, but discouraged their use due to the VORACLE attack vulnerability.
OpenVPN 2.6+ defaults --allow-compression to no, blocking even server-pushed compression. Now that OpenVPN is removing compression support entirely, this script no longer supports it.
TLS version
Note
OpenVPN 2.6+ defaults to TLS 1.2 minimum. Prior versions accepted TLS 1.0 by default.
OpenVPN 2.5 and earlier accepted TLS 1.0 by default, which is nearly 20 years old.
This script defaults to tls-version-min 1.2 for compatibility with all OpenVPN 2.4+ clients. You can optionally set tls-version-min 1.3 for environments where all clients support TLS 1.3.
TLS 1.3 support was added in OpenVPN 2.5 and requires OpenSSL 1.1.1+. TLS 1.3 offers improved security and performance with a simplified handshake.
The script configures TLS 1.3 cipher suites via --tls-ciphersuites (separate from the TLS 1.2 --tls-cipher option). The default TLS 1.3 cipher suites are:
TLS_AES_256_GCM_SHA384TLS_AES_128_GCM_SHA256TLS_CHACHA20_POLY1305_SHA256
TLS 1.2 is supported since OpenVPN 2.3.3. TLS 1.3 is supported since OpenVPN 2.5.
Certificate
OpenVPN uses an RSA certificate with a 2048 bits key by default.
OpenVPN 2.4 added support for ECDSA. Elliptic curve cryptography is faster, lighter and more secure.
This script provides:
- ECDSA:
prime256v1/secp384r1/secp521r1curves - RSA:
2048/3072/4096bits keys
It defaults to ECDSA with prime256v1.
OpenVPN uses SHA-256 as the signature hash by default, and so does the script. It provides no other choice as of now.
Data channel
Note
The default data channel cipher changed in OpenVPN 2.5. Prior versions defaulted to
BF-CBC, while OpenVPN 2.5+ defaults toAES-256-GCM:AES-128-GCM. OpenVPN 2.6+ also includesCHACHA20-POLY1305in the default cipher list when available.
By default, OpenVPN 2.4 and earlier used BF-CBC as the data channel cipher. Blowfish is an old (1993) and weak algorithm. Even the official OpenVPN documentation admits it.
The default is BF-CBC, an abbreviation for Blowfish in Cipher Block Chaining mode.
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. 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.
OpenVPN's default cipher, BF-CBC, is affected by this attack.
Indeed, AES is today's standard. It's the fastest and more secure cipher available today. SEED and Camellia are not vulnerable to date but are slower than AES and relatively less trusted.
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.
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,2). Moreover, AES-256 is more vulnerable to Timing attacks.
AES-GCM is an AEAD cipher which means it simultaneously provides confidentiality, integrity, and authenticity assurances on the data.
ChaCha20-Poly1305 is another AEAD cipher that provides similar security to AES-GCM. It is particularly useful on devices without hardware AES acceleration (AES-NI), such as older CPUs and many ARM-based devices, where it can be significantly faster than AES.
The script supports the following ciphers:
AES-128-GCMAES-192-GCMAES-256-GCMAES-128-CBCAES-192-CBCAES-256-CBCCHACHA20-POLY1305(requires OpenVPN 2.5+)
And defaults to AES-128-GCM.
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 sets --cipher (fallback for non-NCP clients), --data-ciphers (modern OpenVPN 2.5+ naming), and --ncp-ciphers (legacy alias for OpenVPN 2.4 compatibility) to the cipher chosen above.
Control channel
OpenVPN 2.4 will negotiate the best cipher available by default (e.g ECDHE+AES-256-GCM)
TLS 1.2 ciphers (--tls-cipher)
The script proposes the following options, depending on the certificate:
- ECDSA:
TLS-ECDHE-ECDSA-WITH-AES-128-GCM-SHA256TLS-ECDHE-ECDSA-WITH-AES-256-GCM-SHA384TLS-ECDHE-ECDSA-WITH-CHACHA20-POLY1305-SHA256(requires OpenVPN 2.5+)
- RSA:
TLS-ECDHE-RSA-WITH-AES-128-GCM-SHA256TLS-ECDHE-RSA-WITH-AES-256-GCM-SHA384TLS-ECDHE-RSA-WITH-CHACHA20-POLY1305-SHA256(requires OpenVPN 2.5+)
It defaults to TLS-ECDHE-*-WITH-AES-128-GCM-SHA256.
TLS 1.3 ciphers (--tls-ciphersuites)
When TLS 1.3 is negotiated, a separate set of cipher suites is used. These are configured via --tls-ciphersuites and use OpenSSL naming conventions:
TLS_AES_256_GCM_SHA384TLS_AES_128_GCM_SHA256TLS_CHACHA20_POLY1305_SHA256
By default, all three cipher suites are enabled. TLS 1.3 cipher suites are simpler because they don't include the key exchange algorithm (which is negotiated separately via key shares).
Key exchange
OpenVPN historically defaulted to 2048-bit DH parameters for key exchange. This script used to offer both DH (with configurable key sizes) and ECDH as alternatives.
OpenVPN 2.4 added ECDH support, and OpenVPN 2.7 made dh none (ECDH) the default, as finite-field DH is being deprecated. Since ECDH is now universally supported and preferred, this script no longer offers traditional DH.
The script configures tls-groups with the following preference list:
X25519:prime256v1:secp384r1:secp521r1
- X25519: Fast, modern curve (Curve25519), widely supported
- prime256v1: NIST P-256, most compatible
- secp384r1: NIST P-384, higher security
- secp521r1: NIST P-521, highest security
You can customize this with --tls-groups.
HMAC digest algorithm
From the OpenVPN wiki, about --auth:
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.
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.
The script provides the following choices:
SHA256SHA384SHA512
It defaults to SHA256.
tls-auth, tls-crypt, and tls-crypt-v2
From the OpenVPN wiki, about tls-auth:
Add an additional layer of HMAC authentication on top of the TLS control channel to mitigate DoS attacks and attacks on the TLS stack.
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.
About tls-crypt:
Encrypt and authenticate all control channel packets with the key from keyfile. (See --tls-auth for more background.)
Encrypting (and authenticating) control channel packets:
- provides more privacy by hiding the certificate used for the TLS connection,
- makes it harder to identify OpenVPN traffic as such,
- provides "poor-man's" post-quantum security, against attackers who will never know the pre-shared key (i.e. no forward secrecy).
So both provide an additional layer of security and mitigate DoS attacks. They aren't used by default by OpenVPN.
tls-crypt is an OpenVPN 2.4 feature that provides encryption in addition to authentication (unlike tls-auth). It is more privacy-friendly.
tls-crypt-v2 is an OpenVPN 2.5 feature that builds on tls-crypt by using per-client keys instead of a shared key. Each client receives a unique key derived from a server key. This provides:
- Better security: If a client key is compromised, other clients are not affected
- Easier key management: Client keys can be revoked individually without regenerating the server key
- Scalability: Better suited for large deployments with many clients
The script supports all three options:
tls-crypt-v2(default): Per-client keys for better securitytls-crypt: Shared key for all clients, compatible with OpenVPN 2.4+tls-auth: HMAC authentication only (no encryption), compatible with older clients
Certificate type verification (remote-cert-tls)
The server is configured with remote-cert-tls client, which requires connecting peers to have a certificate with the "TLS Web Client Authentication" extended key usage. This prevents a server certificate from being used to impersonate a client.
Similarly, clients are configured with remote-cert-tls server to ensure they only connect to servers presenting valid server certificates. This protects against an attacker with a valid client certificate setting up a rogue server.
Data Channel Offload (DCO)
Data Channel Offload (DCO) is a kernel acceleration feature that significantly improves OpenVPN performance by keeping data channel encryption/decryption in kernel space, eliminating costly context switches between user and kernel space for each packet.
DCO was merged into the Linux kernel 6.16 (April 2025).
Requirements:
- OpenVPN 2.6.0 or later
- Linux kernel 6.16+ (built-in) or
ovpn-dcokernel module - UDP protocol (TCP is not supported)
- AEAD cipher (
AES-128-GCM,AES-256-GCM, orCHACHA20-POLY1305)
The script's default settings (AES-128-GCM, UDP) are DCO-compatible. When DCO is available and the configuration is compatible, OpenVPN will automatically use it for improved performance.
Note: DCO must be supported on both the server and the client for full acceleration. Client support is available in OpenVPN 2.6+ (Linux, Windows, FreeBSD) and OpenVPN Connect 3.4+ (Windows). macOS does not currently support DCO, but clients can still connect to DCO-enabled servers with partial performance benefits on the server-side.
The script will display the DCO availability status during installation.
Say thanks
You can say thanks if you want!
Credits & Licence
Many thanks to the contributors and Nyr's original work.
This project is under the MIT Licence