The project's README from github.com/angristan/openvpn-install. As one markdown file: README.md.
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.
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.
Internet routing, access between VPN clients, and access to selected server-side networks can be configured independently. By default, internet routing is enabled and the other paths are disabled.
flowchart LR
A[Phone] -->|Encrypted| VPN
B[Laptop] -->|Encrypted| VPN
C[Computer] -->|Encrypted| VPN
VPN[OpenVPN Server]
VPN -->|Internet routing<br/>Default: enabled| I[Internet]
VPN -.->|Explicit CIDRs only<br/>Default: disabled| LAN[Home LAN or cloud VPC]
VPN -.->|Client-to-client access<br/>Default: disabled| PEERS[Other VPN clients]
The solid destination path is enabled by default. Dashed destination paths are opt-in.
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:
10.8.0.0/24, IPv6: default fd42:42:42:42::/112)1500)nobody/nogroupThe 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:
amd64 architecture.systemd.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.
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.
[!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 (immediately disconnects if connected)
./openvpn-install.sh client revoke alice
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.
# 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
}
]
}
# 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.
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-ipv4 10.9.0.0
# Home VPN: access the home LAN without routing internet through the VPN
./openvpn-install.sh install --no-route-internet --local-network 192.168.1.0/24
# Allow VPN clients to access each other
./openvpn-install.sh install --client-to-client
# Enable dual-stack (IPv4 + IPv6) for clients
./openvpn-install.sh install --client-ipv4 --client-ipv6
# IPv6-only clients (no IPv4)
./openvpn-install.sh install --no-client-ipv4 --client-ipv6
# IPv6 endpoint (server listens on IPv6, clients connect via IPv6)
./openvpn-install.sh install --endpoint-type 6 --endpoint 2001:db8::1
# Custom IPv6 subnet for dual-stack setup
./openvpn-install.sh install --client-ipv6 --subnet-ipv6 fd00:1234:5678::
# 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)--endpoint-type <4|6> - Endpoint IP version (default: 4)--ip <addr> - Server listening IP (default: auto-detected)--client-ipv4 - Enable IPv4 for VPN clients (default: enabled)--no-client-ipv4 - Disable IPv4 for VPN clients--client-ipv6 - Enable IPv6 for VPN clients (default: disabled)--no-client-ipv6 - Disable IPv6 for VPN clients--subnet-ipv4 <x.x.x.0> - IPv4 VPN subnet (default: 10.8.0.0)--subnet-ipv6 <prefix> - IPv6 VPN subnet (default: fd42:42:42:42::)--route-internet / --no-route-internet - Enable or disable routing client internet traffic through the VPN (default: enabled)--client-to-client / --no-client-to-client - Allow or isolate communication between VPN clients (default: isolated)--local-network <CIDR> - Allow access to a server-side network and add destination-scoped NAT. Repeat for multiple networks (default: none)--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)Server-side network access is mainly intended for VPN servers installed at home. In interactive mode, the installer suggests directly connected private IPv4 and IPv6 networks as one editable, comma-separated list after you enable LAN access. Review and confirm the list because it can include cloud VPC or container networks. No network is exposed unless you opt in. Non-interactive installs require an explicit --local-network for each network. LAN devices see connections as coming from the VPN server because destination-scoped NAT is enabled.
Local networks must use network-aligned IPv4 or IPv6 CIDRs and must not overlap the VPN pools. Client-side and server-side LANs that overlap can still cause routing conflicts.
DNS Options:
DNS settings are pushed only when internet routing through the VPN is enabled.
--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--auth-mode <mode> - Authentication mode (default: pki). Options: pki (CA-based), fingerprint (peer-fingerprint, requires OpenVPN 2.6+)--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 creationOther Options:
--multi-client - Allow same cert on multiple devices (default: disabled)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
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.
More Q&A in FAQ.md.
Q: Which provider do you recommend?
A: I recommend these:
Q: Which OpenVPN client do you recommend?
A: If possible, an official OpenVPN 2.4 client.
openvpn package from your distribution. There is an official APT repository for Debian/Ubuntu based distributions.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.
Please open an issue before submitting a PR if you want to discuss a change, especially if it's a big one.
[!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:
--peer-fingerprint for PKI-less setups, and DCO kernel accelerationIf 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.
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.
[!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_SHA256TLS 1.2 is supported since OpenVPN 2.3.3. TLS 1.3 is supported since OpenVPN 2.5.
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