โก A production-ready OpenVPN deployment script featuring automated installation, dual-stack IPv4/IPv6 support, hardened security defaults, and an integrated Unbound recursive DNS resolver.
๐ OpenVPN Road Warrior Installer enables you to deploy a secure, production-ready OpenVPN server in under a minuteโeven with no prior VPN administration experience.
Designed to be minimal, non-intrusive, and security-focused, the script automates the entire deployment process, including PKI generation, firewall configuration, routing, DNS integration, and client provisioning, allowing you to bring a fully functional VPN server online with minimal effort.
| ๐ง Distribution | โ๏ธ Minimum Version | ๐ฆ Repository Channel |
|---|---|---|
| Ubuntu | 22.04 LTS | Official OpenVPN APT |
| Debian | 11 (Bullseye) | Official OpenVPN APT |
| AlmaLinux | 8 | Copr @OpenVPN/openvpn-release-2.6 |
| Rocky Linux | 8 | Copr @OpenVPN/openvpn-release-2.6 |
| CentOS / Stream | 8 | Copr @OpenVPN/openvpn-release-2.6 |
| Oracle Linux | 8 | Copr @OpenVPN/openvpn-release-2.6 |
| Fedora | Latest Stable | Distribution Native |
[!NOTE] โ ๏ธ Debian Testing and Debian Unstable (Sid) are currently not supported to maintain installation predictability.
root or sudo)/dev/net/tun)Choose one of the installation options below to begin the interactive setup:
This version is maintained by alsyundawy and includes all the features listed in this repository (e.g., dual-stack IPv4/IPv6, extended DNS options, security hardening, colorized output, and enhanced client management).
Using wget:
wget https://raw.githubusercontent.com/alsyundawy/OpenVPN-Install/refs/heads/master/openvpn-install.sh \
-O openvpn-install.sh && sudo bash openvpn-install.sh
Using curl:
curl -O https://raw.githubusercontent.com/alsyundawy/OpenVPN-Install/refs/heads/master/openvpn-install.sh \
&& sudo bash openvpn-install.sh
This runs the original script (openvpn-install-nyr.sh) by Nyr.
Using wget:
wget https://raw.githubusercontent.com/alsyundawy/OpenVPN-Install/refs/heads/master/openvpn-install-nyr.sh \
-O openvpn-install-nyr.sh && sudo bash openvpn-install-nyr.sh
Using curl:
curl -O https://raw.githubusercontent.com/alsyundawy/OpenVPN-Install/refs/heads/master/openvpn-install-nyr.sh \
&& sudo bash openvpn-install-nyr.sh
๐ The script will guide you through:
1194).๐พ Upon completion, the installer saves a client configuration file (.ovpn)
directly to the script directory.
Once the installation completes, the installer automatically generates a client configuration profile (.ovpn) in the same directory where the installation script was executed.
The generated .ovpn file contains everything required to establish a secure VPN connection, including the server configuration, certificates, cryptographic parameters, and client settings.
Simply download one of the recommended OpenVPN clients below, import the generated .ovpn profile, and connect securely to your VPN server.
[!TIP]
๐ก The generated
.ovpnprofile is fully compatible with:
- ๐ช OpenVPN Connect
- ๐ช OpenVPN GUI
- ๐ Tunnelblick
- ๐ Viscosity
- ๐ง OpenVPN 3 Linux
- ๐ง NetworkManager OpenVPN
- ๐ง KDE Plasma NetworkManager
- ๐ MikroTik RouterOS v7 (.ovpn Import)
Official download
https://openvpn.net/client/
Supported operating systems
.ovpn importGitHub
https://github.com/OpenVPN/openvpn-gui
Recommended for users who prefer a lightweight native Windows client.
Features
.ovpn using OpenVPN Connect.ovpn profile..ovpn.[!TIP] You can also drag and drop the
.ovpnfile directly into OpenVPN Connect on Windows.
.ovpn using OpenVPN GUI.ovpn file.Alternatively, copy the .ovpn file into:
C:\Users\<username>\OpenVPN\config\
or
C:\Program Files\OpenVPN\config\
The profile will automatically appear inside OpenVPN GUI after restarting or rescanning the configuration directory.
Download
https://openvpn.net/client/
Supported versions
Website
https://tunnelblick.net/
Tunnelblick is the most popular free OpenVPN client for macOS and is fully compatible with standard .ovpn profiles.
Features
Website
https://www.sparklabs.com/viscosity/
Features
.ovpn using OpenVPN Connect.ovpn..ovpn using Tunnelblick.ovpn..ovpn using ViscosityPreferences.Connections.+.Import Connection โ From File.....ovpn profile.Download
https://openvpn.net/client/
The following desktop environments support importing .ovpn files using NetworkManager.
Install
sudo apt update
sudo apt install network-manager-openvpn network-manager-openvpn-gnome
Import: Settings โ Network โ VPN โ + โ Import from File โ Select your .ovpn profile โ Connect
Install
sudo apt update
sudo apt install plasma-nm network-manager-openvpn
Import: System Settings โ Network โ Connections โ Add VPN โ Import VPN Connection โ Select .ovpn
nmcli connection import type openvpn file client.ovpn
List imported connections
nmcli connection show
Connect
nmcli connection up client
The imported profile is stored as a NetworkManager connection, allowing you to manage it from your desktop environment.
Install OpenVPN
Debian / Ubuntu
sudo apt update
sudo apt install openvpn
Fedora
sudo dnf install openvpn
RHEL / AlmaLinux / Rocky Linux
sudo dnf install openvpn
Connect
sudo openvpn --config client.ovpn
Disconnect: press CTRL + C
https://www.sparklabs.com/viscosity/
Supports Linux and provides an easy graphical interface for importing .ovpn files.
.ovpn on MikroTik RouterOSStarting with RouterOS v7.12, MikroTik supports importing an OpenVPN client configuration directly from a standard .ovpn file. This greatly simplifies deployment by automatically importing supported VPN parameters, certificates, and authentication settings. For the best compatibility and latest OpenVPN improvements, use the latest stable RouterOS v7 release.
[!IMPORTANT]
โ RouterOS v7.12 or later is required for
.ovpnimport.โญ The latest stable RouterOS v7 release is strongly recommended.
Before importing your VPN profile, make sure you have:
.ovpn profile[!TIP]
TLS certificate validation depends on the routerโs system clock. Always enable NTP before connecting to an OpenVPN server.
Open Files and drag and drop your generated client.ovpn into the router.
Open PPP โ OVPN โ Import, choose client.ovpn, enter Username and Password, then click Import.
RouterOS will automatically import supported configuration from the profile, including certificates, remote server settings, ciphers, authentication parameters, and TLS authentication when present. Supported parameters depend on the RouterOS version.
Navigate to Interfaces โ OVPN Client. A new interface (e.g. ovpn-client) should appear. Enable it if necessary.
Upload client.ovpn to the router, then import it:
/interface/ovpn-client/import-ovpn-configuration \
file-name=client.ovpn \
ovpn-user=myuser \
ovpn-password=mypassword \
skip-cert-import=no
If the client private key is protected:
/interface/ovpn-client/import-ovpn-configuration \
file-name=client.ovpn \
ovpn-user=myuser \
ovpn-password=mypassword \
key-passphrase=myPrivateKeyPassword
List interfaces
/interface/ovpn-client/print
Enable
/interface/ovpn-client/enable 0
Replace 0 with your interface number if different.
/interface/ovpn-client/monitor 0
Example output
status: connected
uptime: 00:25:42
local-address: 172.16.200.2
remote-address: 172.16.200.1
Show details
/interface/ovpn-client/print detail
A connected interface displays the R flag.
Automatically install the default route
/interface/ovpn-client
set 0 add-default-route=yes
Use DNS servers provided by the VPN
/interface/ovpn-client
set 0 use-peer-dns=yes
Verify routing
/ip/route/print
Ping Cloudflare DNS
/tool/ping 1.1.1.1
Ping Google DNS
/tool/ping 8.8.8.8
Check default routes
/ip/route/print
View DNS configuration
/ip/dns/print
verify-server-certificate=yes)..ovpn files because they may contain certificates and private keys.RouterOS implements its own OpenVPN client and does not support every OpenVPN directive.
Current notable limitations include:
.ovpn profiles.For the latest supported directives and client capabilities, consult the official MikroTik OpenVPN documentation.
[!NOTE]
This installer generates standard OpenVPN client profiles designed to work with current RouterOS v7
.ovpnimport functionality. If your VPN profile uses unsupported directives, RouterOS may ignore them or require manual adjustment according to the official MikroTik documentation.
After successfully connecting to your VPN, verify that your traffic is actually routed through the encrypted tunnel.
curl ifconfig.me
or
curl https://icanhazip.com
curl ifconfig.me
or
Invoke-RestMethod https://icanhazip.com
The returned public IP address should be your VPN serverโs public IP address, not your local ISPโs address.
Visit one of the following websites:
Verify:
Visit https://dnsleaktest.com or https://browserleaks.com/dns
Expected result
If your VPN server supports IPv6, verify that IPv6 traffic is also routed through the VPN.
Visit https://test-ipv6.com
Expected
Check your routing table.
ip route
IPv6
ip -6 route
netstat -rn
route print
The default route should point to the VPN tunnel when full-tunnel mode is enabled.
Linux / macOS
dig openvpn.net
or
nslookup openvpn.net
Windows
nslookup openvpn.net
DNS queries should succeed using the DNS server provided by your VPN configuration.
ip addr
Look for tun0 or tun1
ifconfig
Look for utun
ipconfig
Look for an OpenVPN TAP Adapter or OpenVPN Data Channel Offload Adapter depending on the installed client.
Possible causes
Solution
.ovpn profile if necessary.Possible causes
Recommended checks
Possible causes
Solution
.ovpnPossible causes
Solution
Possible causes
Recommended actions
.ovpn profile for every user and every device..ovpn files publicly.https://openvpn.net/community-resources/
https://openvpn.net/connect-docs/
https://forums.openvpn.net/
If you encounter a bug or have a feature request, please open an issue on GitHub.
https://github.com/alsyundawy/OpenVPN-Install/issues
If this project has helped you, please consider:
Your support helps improve this project for the entire OpenVPN community.
[!TIP]
Always download VPN client software from the official vendor, keep your
.ovpnprofile private, and periodically verify your public IP address, DNS servers, and routing after connecting to ensure all traffic is passing through the VPN tunnel as expected.
ffdhe2048 Diffie-Hellman
parameters (safe and instant generation), SHA-512 authentication, and
tls-crypt payload encryption keys.use-caps-for-id), and strict caching rules.firewalld or
iptables/nftables services. Direct rules are audited before
insertion/removal to prevent duplicates and routing table pollution.semanage.EXIT/INT/TERM signal trap
for clean exit handling with automatic temporary file cleanup..ovpn generation and CRL updates use atomic
temp-file-then-move patterns to guarantee consistency under concurrent access.systemctl daemon-reload
post-cleanup.๐ The script offers 36 pre-configured resolvers alongside system defaults and custom inputs:
Local Unbound (Local caching resolver with DNSSEC)Google Public DNS (Standard & IPv6)Cloudflare DNS (Standard, Security-filtered, or Family-filtered)Quad9 DNS (Secure, Unsecured, or ECS-supported)OpenDNS (Home or FamilyShield)AliDNS, DNSPod, 114DNS, Baidu DNS, OneDNS, DNSPaiCleanBrowsing (Security, Adult, or Family filters)Verisign, DNS.WATCH, Yandex (Basic, Safe, or Family)Level3/Lumen, Neustar (Default, Threat, or Family)Oracle Dyn, Alternate DNS, Comodo Secure DNS, Freenom Worldโก The script presents 37 DNS choices during setup:
| # | Provider | Primary | Notes |
|---|---|---|---|
| 1 | Local Unbound | 172.16.200.1 |
DNSSEC + DNS rebind protection |
| 2 | Current system resolvers | โ | Parsed from /etc/resolv.conf |
| 3 | 8.8.8.8 |
IPv4 + IPv6 | |
| 4 | Cloudflare Standard | 1.1.1.1 |
IPv4 + IPv6 |
| 5 | Cloudflare Security | 1.1.1.2 |
Malware filtering |
| 6 | Cloudflare Family | 1.1.1.3 |
Adult content filtering |
| 7 | Quad9 Secure | 9.9.9.9 |
Threat blocking |
| 8 | Quad9 Unsecured | 9.9.9.10 |
No filtering |
| 9 | Quad9 ECS | 9.9.9.11 |
ECS-enabled |
| 10 | OpenDNS Home | 208.67.222.222 |
IPv4 + IPv6 |
| 11 | OpenDNS FamilyShield | 208.67.222.123 |
Family filter |
| 12 | AdGuard Default | 94.140.14.14 |
Ad blocking + IPv6 |
| 13 | AdGuard Family | 94.140.14.15 |
Family filter |
| 14 | AdGuard Non-Filtering | 94.140.14.140 |
No filtering |
| 15 | AliDNS | 223.5.5.5 |
IPv4 + IPv6 |
| 16 | DNSPod | 119.29.29.29 |
โ |
| 17 | 114DNS | 114.114.114.114 |
โ |
| 18 | Baidu DNS | 180.76.76.76 |
โ |
| 19 | OneDNS | 117.50.10.10 |
โ |
| 20 | DNSPai | 101.226.4.6 |
โ |
| 21 | CleanBrowsing Security | 185.228.168.9 |
IPv4 + IPv6 |
| 22 | CleanBrowsing Adult | 185.228.168.10 |
IPv4 + IPv6 |
| 23 | CleanBrowsing Family | 185.228.168.168 |
IPv4 + IPv6 |
| 24 | Verisign | 64.6.64.6 |
โ |
| 25 | DNS.WATCH | 84.200.69.80 |
IPv4 + IPv6 |
| 26 | Yandex Basic | 77.88.8.8 |
IPv4 + IPv6 |
| 27 | Yandex Safe | 77.88.8.88 |
Malware filtering |
| 28 | Yandex Family | 77.88.8.7 |
Family filter |
| 29 | Level3 / Lumen | 209.244.0.3 |
โ |
| 30 | Neustar Default | 156.154.70.1 |
IPv4 + IPv6 |
| 31 | Neustar Threat Protection | 156.154.70.5 |
IPv4 + IPv6 |
| 32 | Neustar Family Secure | 156.154.70.3 |
โ |
| 33 | Oracle Dyn | 216.146.35.35 |
โ |
| 34 | Alternate DNS | 198.101.242.72 |
โ |
| 35 | Comodo Secure DNS | 8.26.56.26 |
โ |
| 36 | Freenom World DNS | 80.80.80.80 |
โ |
| 37 | Custom resolvers | User-defined | IPv4 and/or IPv6 |
[!TIP] Option 1 (Local Unbound) is recommended for maximum privacy โ it resolves DNS recursively on the server itself with DNSSEC validation and 0x20 encoding anti-spoofing.
๐ง Run the script again at any time to access the administrative menu:
sudo bash openvpn-install.sh
OpenVPN is already installed.
Select an option:
1) Add a new client
2) Renew client configuration
3) Revoke an existing client
4) List client certificates
5) List connected clients
6) Remove OpenVPN
7) Exit
| ๐ Menu Option | ๐ ๏ธ Action Description |
|---|---|
| Add a new client | Validates name uniqueness, signs a new key pair, and generates the .ovpn profile atomically. |
| Renew client configuration | Regenerates the .ovpn file for an existing client without changing the certificate or key. |
| Revoke an existing client | Revokes the certificate with [y/N] confirmation, performs atomic CRL replacement, and removes the .ovpn file. |
| List client certificates | Displays all active (non-revoked) client certificate names from the PKI index. |
| List connected clients | Reads the OpenVPN status log or falls back to ss to show active VPN sessions. |
| Remove OpenVPN | Gracefully removes firewall rules (IPv4+IPv6 SNAT), SELinux labels, Unbound config, systemd services, PKI, and calls daemon-reload. |
umask 077
and enforces chmod 600 on private keys and client profiles.nobody and the nogroup/nobody system group after
initialization.block-outside-dns policies to client
devices to prevent DNS leakages outside the encrypted tunnel.crl.pem) is owned and
accessible specifically to the unprivileged OpenVPN daemon so dynamic
revocation checks function without root.! -d destination guard to prevent masquerading VPN-to-VPN traffic, with
correct regex matching for rule idempotency.SIGINT, SIGTERM, and EXIT are trapped for clean
installer exit โ no orphaned processes, partial configurations, or broken
terminal color states..ovpn Generation: Client config files are written to a temp
file first (mktemp + chmod 600) then moved atomically to the final path
to prevent partial writes..ovpn
file to prevent re-use of revoked credentials.cp + mv -f to guarantee
the live crl.pem is never in an inconsistent state during rotation.systemctl daemon-reload is called after
removing unit files to flush stale systemd cache entries.ip -o -6 addr show scope global)
finds no global IPv6 address (IPv6 not yet bound, link-local only, or scoped
differently), the installer now offers a manual IPv6 entry option so dual-stack
can still be enabled instead of silently falling back to IPv4-only.EXIT/INT/TERM) to reset
terminal colors and clean up tracked temporary files via _TMP_FILES array
on any exit path โ no orphaned temp files or broken color states.mktemp),
validates it as a valid gzip tarball (tar -tzf) before extraction, preventing
corrupt or partial archive installations.curl fallback for EasyRSA download now uses -fsSL (follow redirects,
silent, SSL-verified, show errors) for stricter HTTP safety..ovpn generation โ client config is written to a mktemp
file with chmod 600 then moved atomically to prevent partial writes or
insecure intermediate states.cp + mv -f pattern ensures crl.pem is
never inconsistent during rotation, preventing VPN service disruption.127.0.0.1, ::1) when parsing
system resolvers.[y/N]
confirmation before revoking, preventing accidental revocations.systemctl daemon-reload
after removing unit files to flush stale systemd cache entries.semanage port -d during uninstall now uses
|| true to prevent abort when the port label was never set.|| exit 1 on cd calls with || die so trap cleanup
always executes on early directory-change failures.COLOR_WHITE and COLOR_DIM variables (ShellCheck SC2034).append_line_if_missing now validates file existence and uses grep --
for end-of-options safety; annotated as intentionally unused (SC2317).! -d guard
for SNAT rules to properly match rules containing destination negation..ovpn file upon certificate revocation.\r) characters
from redirect headers for reliable version tag extraction.resolv.conf fallback logic in push_dns for edge-case
system resolver configurations.\033[1;9x) with
dedicated log helpers: log_header, log_subheader, log_prompt,
log_info, log_ok, log_warn, log_error.SIGINT/SIGTERM/EXIT trap for clean exit handling during
installation.list_clients โ displays all active client certificates from PKI index.list_connected โ shows active VPN sessions via status log or ss.renew_client โ regenerates .ovpn bundle without modifying the
certificate or key.10.8.0.0/24 to
172.16.200.0/24.is_valid_ipv4 for
numbers with leading zeroes.firewalld_direct_rule_exists pattern matching to handle
priority prefix.resolv.conf system resolver
parsing.\r) characters when parsing EasyRSA
download headers.generate_client_config for client
.ovpn bundle generation.mv to prevent VPN
dropouts..ovpn files to prevent writing to pre-existing
insecure files.systemctl is-active instead of pgrep for reliable Unbound
checks./etc/os-release parsing without polluting shell state
excessively.umask 077 and explicit chmod
operations.ip -o for more stable address enumeration.installOpenVPNRepo() function for official repository setup.installUnbound() function with per-distro package management.cd calls guarded with || exit.$().[[ ]] for compound conditions.push_dns() helper.hide-identity, hide-version, harden-glue,
harden-dnssec-stripped.use-caps-for-id (0x20 encoding) anti-spoofing.โ If this project helps secure your network, please support the continued maintenance of the installer:
๐ This project is licensed under the terms of the MIT License.