๐ Install OpenVPN Server¶
OpenVPN is a full-featured SSL VPN (virtual private network).
It implements OSI layer 2 or 3 secure network extension using the SSL/TLS protocol.
It is an open source software and distributed under the GNU GPL.
A VPN allows you to connect securely to an insecure public network such as wifi network at the airport or hotel.
VPN is also required to access your corporate or enterprise or home server resources.
You can bypass geo-blocked site and increase your privacy or safety online.
๐ฅ Installation¶
๐ฆ Install OpenVPN¶
# download the installer
wget https://git.io/vpn -O openvpn-install.sh
# verify integrity against known checksum - abort if mismatch
EXPECTED="44bb99a8426eda139e7fe0e628eb72e0c01de86ced7dc5b11710c6ab72033203"
ACTUAL=$(sha256sum openvpn-install.sh | awk '{print $1}')
[ "${ACTUAL}" = "${EXPECTED}" ] || { echo "Checksum mismatch โ aborting"; rm openvpn-install.sh; exit 1; }
chmod +x openvpn-install.sh
sudo ./openvpn-install.sh
Welcome to this OpenVPN road warrior installer!
Which protocol should OpenVPN use?
1) UDP (recommended)
2) TCP
Protocol [1]:
What port should OpenVPN listen to?
Port [1194]:
Select a DNS server for the clients:
1) Current system resolvers
2) Google
3) 1.1.1.1
4) OpenDNS
5) Quad9
6) AdGuard
DNS server [1]:
Enter a name for the first client:
Name [client]:
OpenVPN installation is ready to begin.
Press any key to continue...
Security advices
Select all recommended options such as UDP, 1194 and Current system resolvers.
It's highly recommended to use port-forwarding to not directly expose the default vpn port: 1194.
โ๏ธ Configuration¶
Prepare and harden the OpenVPN server configuration
sudo tee /etc/openvpn/server/server.conf > /dev/null <<EOF
# define listening port, transport protocol, tunnel device type and subnet topology
port 1194
proto udp
dev tun
topology subnet
# set certificate authority, server certificate, private key and use modern ecdhe instead of legacy dh
ca /etc/openvpn/server/ca.crt
cert /etc/openvpn/server/server.crt
key /etc/openvpn/server/server.key
dh dh.pem
ecdh-curve prime256v1
# enable tls server mode, enforce minimum tls version, verify client cert type and protect control channel with tls-crypt
tls-server
tls-version-min 1.2
remote-cert-tls client
tls-crypt /etc/openvpn/server/tc.key
# define allowed data channel ciphers and hmac authentication algorithm
data-ciphers AES-256-GCM:AES-128-GCM:CHACHA20-POLY1305
auth SHA512
# define vpn subnet and persist client ip assignments
server 10.8.0.0 255.255.255.0
ifconfig-pool-persist /var/log/openvpn/ipp.txt
# push default route and dns settings to clients and prevent dns leaks on supported systems
push "redirect-gateway def1 bypass-dhcp"
push "dhcp-option DNS 1.1.1.1"
push "dhcp-option DNS 9.9.9.9"
push "block-outside-dns"
# maintain connection health and preserve key/tunnel across restarts
keepalive 10 120
persist-key
persist-tun
# enable status logging, set verbosity level and notify clients on server restart
status /var/log/openvpn/openvpn-status.log
verb 3
explicit-exit-notify 1
EOF
# restart openvpn
sudo systemctl restart openvpn-server@server.service
Note: Create openvpn users after this step.
Handle OpenVPN service
# view status of OpenVPN service
sudo systemctl status openvpn-server@server.service
# restart OpenVPN service
sudo systemctl restart openvpn-server@server.service
Enable IPv4 forwarding
# persistently enable IPv4 forwarding via sysctl.d
echo "net.ipv4.ip_forward=1" | sudo tee /etc/sysctl.d/99-openvpn-forward.conf > /dev/null
# reload all sysctl configuration files
sudo sysctl --system
Enable routing, NAT, and UFW rules for VPN internet access
# ๐ enable IPv4 forwarding and allow packet forwarding through UFW
# ACCEPT is required for full-tunnel VPN: all client traffic (HTTP, HTTPS, etc.)
# arrives on tun0 and must be forwarded out through the WAN interface to the internet
sudo sed -i 's/^#\?net\/ipv4\/ip_forward=1/net\/ipv4\/ip_forward=1/' /etc/ufw/sysctl.conf
sudo sed -i 's/^DEFAULT_FORWARD_POLICY="DROP"/DEFAULT_FORWARD_POLICY="ACCEPT"/' /etc/default/ufw
sudo ufw reload
# ๐ detect the current WAN interface
WAN_IF=$(ip route get 1.1.1.1 | awk '{for(i=1;i<=NF;i++) if($i=="dev"){print $(i+1); exit}}')
[ -n "${WAN_IF}" ] || { echo "Error: could not detect WAN interface"; exit 1; }
# ๐งฉ create a systemd unit that adds/removes the MASQUERADE rule after UFW is up (persists across reboots)
sudo tee /etc/systemd/system/openvpn-nat.service > /dev/null <<EOF
[Unit]
Description=Add NAT rule for OpenVPN subnet
After=ufw.service network-online.target
Requires=ufw.service
[Service]
Type=oneshot
ExecStart=/usr/sbin/iptables -t nat -A POSTROUTING -s 10.8.0.0/24 -o ${WAN_IF} -j MASQUERADE
ExecStop=/usr/sbin/iptables -t nat -D POSTROUTING -s 10.8.0.0/24 -o ${WAN_IF} -j MASQUERADE
RemainAfterExit=yes
[Install]
WantedBy=multi-user.target
EOF
#๐งน remove any old/legacy iptables service to avoid conflicts
sudo systemctl stop openvpn-iptables.service
sudo systemctl disable openvpn-iptables.service
sudo rm -f /etc/systemd/system/openvpn-iptables.service
sudo systemctl reset-failed
sudo systemctl daemon-reload
# โ enable and start the new NAT unit (persistent on boot)
sudo systemctl enable openvpn-nat.service
sudo systemctl start openvpn-nat.service
# ๐ open firewall for OpenVPN and SSH, then apply rules
sudo ufw allow 1194/udp # allow openvpn
sudo ufw allow 22/tcp # allow ssh
sudo ufw reload
# ๐ restart OpenVPN server to pick up any config changes
sudo systemctl restart openvpn-server@server.service
๐ค Create clients¶
# run from the directory where the script was originally downloaded
./openvpn-install.sh
OpenVPN is already installed.
Select an option:
1) Add a new client
2) Revoke an existing client
3) Remove OpenVPN
4) Exit
Option: 1
Provide a name for the client:
Name:
OpenVPN Client Configuration Updater
The generated client .ovpn file must be updated to use your domain.
Once updated, copy it to your device and import it into your OpenVPN client.
# ask user input
read -rp "Enter OVPN file path: " OVPN_FILE
read -rp "Enter server URL (dyndns.domain.fr): " URL
read -rp "Enter port (1194): " PORT
# validate inputs
[[ -z "$OVPN_FILE" || -z "$URL" || -z "$PORT" ]] && { echo "error: all variables must be defined"; exit 1; }
[[ ! -f "$OVPN_FILE" ]] && { echo "error: file does not exist: $OVPN_FILE"; exit 1; }
# create temp file for replacement block
TMP_BLOCK=$(mktemp)
cat > "$TMP_BLOCK" <<EOF
client
dev tun
proto udp
remote ${URL} ${PORT}
resolv-retry infinite
nobind
persist-key
persist-tun
remote-cert-tls server
tls-client
tls-version-min 1.2
data-ciphers AES-256-GCM:AES-128-GCM:CHACHA20-POLY1305
auth SHA512
auth-nocache
ignore-unknown-option block-outside-dns
block-outside-dns
ignore-unknown-option register-dns
register-dns
mssfix 1300
verb 3
EOF
# replace block between "client" and "verb 3"
awk -v newfile="$TMP_BLOCK" '
BEGIN {skip=0}
/^client$/ {
skip=1
while ((getline line < newfile) > 0) print line
close(newfile)
next
}
/^verb 3$/ {
skip=0
next
}
!skip { print }
' "$OVPN_FILE" > "${OVPN_FILE}.tmp"
mv "${OVPN_FILE}.tmp" "$OVPN_FILE"
rm -f "$TMP_BLOCK"
ignore-unknown-option block-outside-dns
block-outside-dns
ignore-unknown-option register-dns
register-dns
On Windows clients, these options force DNS through the VPN, register the VPNโs DNS servers, and block DNS queries outside the tunnel; without them, the VPN may connect but DNS can leak or fail.
mssfix 1300
Limits MSS to 1300 bytes to prevent fragmentation on low-MTU links like 4G, improving stability and reducing packet loss for TCP VPN connections.