This page covers the configuration steps needed to set up OpenVPN in bridge mode after the initial installation.
sudo cp /etc/openvpn/server/server.conf /etc/openvpn/server/server.conf.backup
sudo nano /etc/openvpn/server/server.conf
Make these changes:
Comment out or remove these lines (add # at the beginning):
#server 10.8.0.0 255.255.255.0
#push "redirect-gateway def1 bypass-dhcp"
#push "dhcp-option DNS 176.103.130.130"
#push "dhcp-option DNS 176.103.130.131"
Add these lines (adjust IP addresses for your network):
# Bridge mode configuration
dev tap0
dev-type tap
server-bridge 10.11.12.2 255.255.255.0 10.11.12.200 10.11.12.210
# Bridge scripts
up "/etc/openvpn/bridge_start.sh"
down "/etc/openvpn/bridge_stop.sh"
# Additional bridge settings
script-security 2
server-bridge 10.11.12.2 255.255.255.0 10.11.12.200 10.11.12.210
server-bridge 172.16.100.134 255.255.255.0 172.16.100.200 172.16.100.210
Modern OpenVPN installations may require data-ciphers instead of ncp-ciphers:
# Add or update these lines in your server configuration
cipher AES-256-CBC
data-ciphers AES-256-CBC
# For compatibility, you might also use:
# data-ciphers AES-256-CBC:AES-256-GCM
# cipher AES-256-CBC
Note: If you encounter “Cannot negotiate cipher” errors, ensure both server and client use data-ciphers AES-256-CBC and cipher AES-256-CBC.
dev tap0: Creates a TAP (Layer 2) interface instead of TUN (Layer 3)dev-type tap: Explicitly specifies TAP modeserver-bridge: Defines the bridge configuration:
10.11.12.2: Server IP address (your Raspberry Pi’s IP)255.255.255.0: Subnet mask10.11.12.200: Start of VPN client IP range10.11.12.210: End of VPN client IP rangeup/down: Scripts to run when the VPN starts/stopsscript-security 2: Allows execution of bridge scriptsThe bridge script creates a network bridge that connects your physical network interface with the VPN’s TAP interface.
sudo wget -O /etc/openvpn/bridge_start.sh https://raw.githubusercontent.com/linuxdevel/openvpn/main/bridge_start.sh
sudo wget -O /etc/openvpn/bridge_stop.sh https://raw.githubusercontent.com/linuxdevel/openvpn/main/bridge_stop.sh
sudo chmod +x /etc/openvpn/bridge_start.sh
sudo chmod +x /etc/openvpn/bridge_stop.sh
sudo nano /etc/openvpn/bridge_start.sh
# Define physical ethernet interface to be bridged
eth="eth0" # Your network interface name
eth_ip="10.11.12.2" # Your Raspberry Pi's IP
eth_netmask="255.255.255.0" # Your network mask
eth_broadcast="10.11.12.255" # Your broadcast address
eth_gateway="10.11.12.1" # Your router's IP
eth_mac="e4:5f:01:75:0b:9e" # Your Pi's MAC address
eth="eth0"
eth_ip="10.11.12.2"
eth_netmask="255.255.255.0"
eth_broadcast="10.11.12.255"
eth_gateway="10.11.12.1"
eth_mac="aa:bb:cc:dd:ee:ff" # Replace with your actual MAC
eth="eth0"
eth_ip="172.16.100.134"
eth_netmask="255.255.255.0"
eth_broadcast="172.16.100.255"
eth_gateway="172.16.100.1"
eth_mac="aa:bb:cc:dd:ee:ff" # Replace with your actual MAC
Get your interface name:
ip link show
Get your MAC address:
ip link show eth0 | grep ether
Get your current network settings:
ip addr show eth0
ip route show default
sudo /etc/openvpn/bridge_start.sh
brctl show
ip addr show br0
sudo /etc/openvpn/bridge_stop.sh
sudo systemctl start openvpn-server@server
sudo systemctl status openvpn-server@server
sudo journalctl -u openvpn-server@server -f
brctl show
ip addr show br0
ip addr show tap0
ping google.com
ping 10.11.12.1 # Your router
Important: The client template file is automatically installed at /etc/openvpn/client-template.txt during the initial OpenVPN setup. You need to modify this template before creating any client configurations, as it’s used to generate each user’s .ovpn file.
sudo nano /etc/openvpn/client-template.txt
Make these essential changes for bridge mode:
Change the device setting:
# Find the line that says 'dev tun' or 'dev tap' and change it to:
dev tap0
Update the remote server setting:
# Find the line starting with 'remote' and change it to your server:
remote myvpn-63864.duckdns.org 11194
# OR use your public IP if not using Dynamic DNS:
# remote YOUR_PUBLIC_IP 11194
Update cipher configuration:
# Find the line starting with 'cipher' and change it to:
data-ciphers AES-256-CBC
sudo ./openvpn-install.sh
# Choose option 1 to add a client
The generated .ovpn files will automatically include your bridge mode settings.
If you already have client configurations that need to be updated:
scp pi@10.11.12.2:~/client-name.ovpn ./
Edit each existing client configuration file:
Open the .ovpn file in a text editor and make the same changes as above:
Change device setting:
# Change from 'dev tun' to 'dev tap0'
dev tap0
Update remote server:
remote myvpn-63864.duckdns.org 11194
Update cipher configuration:
# Change 'cipher' to 'data-ciphers'
data-ciphers AES-256-CBC
Add device type for bridge mode:
# Add this line for bridge mode:
dev-type tap
# Route only specific networks through VPN
route 10.11.12.0 255.255.255.0
dhcp-option DNS 8.8.8.8
dhcp-option DNS 8.8.4.4
Windows: Use OpenVPN GUI or OpenVPN Connect
macOS: Use Tunnelblick or OpenVPN Connect
Linux: Use NetworkManager or command line OpenVPN
Android/iOS: Use OpenVPN Connect app
http://10.11.12.1 or http://192.168.1.1Standard Configuration:
Custom Port with Different Networks:
DNS Recommendation: Set up a DNS record like myvpn-63864.duckdns.org pointing to your public IP for easier client configuration.
Linksys: Advanced → Security → Firewall → Port Forwarding
Netgear: Dynamic DNS → Port Forwarding / Port Triggering
TP-Link: Advanced → NAT Forwarding → Port Forwarding
ASUS: Adaptive QoS → Traditional QoS → Port Forwarding
D-Link: Advanced → Port Forwarding
Dynamic DNS allows you to access your VPN using a domain name like myvpn-63864.duckdns.org instead of remembering your changing public IP address.
Most residential internet connections have dynamic (changing) IP addresses. Without Dynamic DNS:
Recommended: DuckDNS (Free and Simple)
myvpn-63864 (full domain: myvpn-63864.duckdns.org)Alternatives:
Option A: Router Configuration (Recommended)
Most modern routers support Dynamic DNS natively:
http://10.11.12.1 (or your router's IP)
Service Provider: DuckDNS (or Custom/Other)
Hostname: myvpn-63864.duckdns.org
Username: nouser (DuckDNS doesn't use username)
Password: your_duckdns_token
Option B: Raspberry Pi Configuration
If your router doesn’t support Dynamic DNS, configure it on the Raspberry Pi:
sudo apt update
sudo apt install ddclient curl -y
sudo nano /usr/local/bin/duckdns-update.sh
#!/bin/bash
# DuckDNS Dynamic IP Update Script
DOMAIN="myvpn-63864"
TOKEN="your_duckdns_token_here"
# Get current public IP
CURRENT_IP=$(curl -s ifconfig.me)
# Update DuckDNS
curl -s "https://www.duckdns.org/update?domains=$DOMAIN&token=$TOKEN&ip=$CURRENT_IP"
# Log the update
echo "$(date): Updated $DOMAIN.duckdns.org to $CURRENT_IP" >> /var/log/duckdns.log
sudo chmod +x /usr/local/bin/duckdns-update.sh
sudo /usr/local/bin/duckdns-update.sh
sudo crontab -e
Add this line to update every 5 minutes:
*/5 * * * * /usr/local/bin/duckdns-update.sh >/dev/null 2>&1
Option C: Alternative No-IP Setup
If using No-IP instead of DuckDNS:
cd /usr/local/src
sudo wget http://www.no-ip.com/client/linux/noip-duc-linux.tar.gz
sudo tar xzf noip-duc-linux.tar.gz
cd noip-2.1.9-1
sudo make install
sudo /usr/local/bin/noip2 -C
Enter your No-IP credentials and hostname
sudo systemctl enable noip2
sudo systemctl start noip2
curl ifconfig.me
nslookup myvpn-63864.duckdns.org
dig myvpn-63864.duckdns.org
Once Dynamic DNS is working, update your client configurations:
sudo nano /etc/openvpn/client-template.txt
Update the remote line:
remote myvpn-63864.duckdns.org 11194
Common Issues:
# Wait a few minutes after initial setup
# Check provider status page
# Verify token/credentials
# Check router logs
# Verify internet connectivity
# Manual update via provider website
# Check script permissions
sudo chmod +x /usr/local/bin/duckdns-update.sh
# Check cron service
sudo systemctl status cron
# View cron logs
sudo journalctl -u cron
Multiple Domains: Set up different subdomains for different services:
vpn.yourdomain.duckdns.org - OpenVPNssh.yourdomain.duckdns.org - SSH accessweb.yourdomain.duckdns.org - Web servicesCustom Domain: Use your own domain with CloudFlare:
Backup Providers: Set up multiple Dynamic DNS providers for redundancy
After completing all configuration steps, verify:
If any step fails, refer to the Troubleshooting Guide for solutions.
It’s important to monitor your certificates and renew them before they expire to avoid service interruption.
# Check server certificate expiry date
sudo openssl x509 -in /etc/openvpn/easy-rsa/pki/issued/server.crt -noout -dates
# Alternative: Check with more details
sudo openssl x509 -in /etc/openvpn/easy-rsa/pki/issued/server.crt -noout -text | grep -A 2 Validity
# Check specific client certificate expiry
sudo openssl x509 -in /etc/openvpn/easy-rsa/pki/issued/CLIENT_NAME.crt -noout -dates
# List all client certificates with expiry dates
for cert in /etc/openvpn/easy-rsa/pki/issued/*.crt; do
if [[ "$cert" != *"server.crt"* ]] && [[ "$cert" != *"ca.crt"* ]]; then
echo "Certificate: $(basename "$cert")"
sudo openssl x509 -in "$cert" -noout -dates
echo "---"
fi
done
# Check CA certificate expiry (most critical)
sudo openssl x509 -in /etc/openvpn/easy-rsa/pki/ca.crt -noout -dates
⚠️ Warning: Regenerating the server certificate will temporarily interrupt VPN service and require updating all client configurations.
sudo systemctl stop openvpn-server@server
sudo cp /etc/openvpn/easy-rsa/pki/issued/server.crt /etc/openvpn/easy-rsa/pki/issued/server.crt.backup
sudo cp /etc/openvpn/easy-rsa/pki/private/server.key /etc/openvpn/easy-rsa/pki/private/server.key.backup
cd /etc/openvpn/easy-rsa/
sudo ./easyrsa --batch revoke server
# Generate new server certificate with 10-year expiry
sudo EASYRSA_CERT_EXPIRE=3650 ./easyrsa --batch build-server-full server nopass
sudo cp pki/issued/server.crt /etc/openvpn/
sudo cp pki/private/server.key /etc/openvpn/
sudo EASYRSA_CRL_DAYS=3650 ./easyrsa gen-crl
sudo cp pki/crl.pem /etc/openvpn/
sudo chmod 644 /etc/openvpn/crl.pem
sudo systemctl start openvpn-server@server
sudo systemctl status openvpn-server@server
sudo openssl x509 -in /etc/openvpn/server.crt -noout -dates
Client certificate regeneration is simpler and doesn’t affect other clients or require service restart.
cd /etc/openvpn/easy-rsa/
sudo ./easyrsa --batch revoke CLIENT_NAME
sudo EASYRSA_CRL_DAYS=3650 ./easyrsa gen-crl
sudo cp pki/crl.pem /etc/openvpn/
sudo chmod 644 /etc/openvpn/crl.pem
# For passwordless certificate
sudo EASYRSA_CERT_EXPIRE=3650 ./easyrsa --batch build-client-full CLIENT_NAME nopass
# For password-protected certificate
sudo EASYRSA_CERT_EXPIRE=3650 ./easyrsa --batch build-client-full CLIENT_NAME
Generate new client configuration file:
You can either run the original Angristan script again to create a new client configuration:
sudo ./openvpn-install.sh
# Choose option 1 to add a new client
Or manually create the configuration file:
# Copy template and customize
sudo cp /etc/openvpn/client-template.txt /root/CLIENT_NAME.ovpn
# Add certificates to the configuration file
{
echo "<ca>"
sudo cat /etc/openvpn/easy-rsa/pki/ca.crt
echo "</ca>"
echo "<cert>"
sudo openssl x509 -in /etc/openvpn/easy-rsa/pki/issued/CLIENT_NAME.crt
echo "</cert>"
echo "<key>"
sudo cat /etc/openvpn/easy-rsa/pki/private/CLIENT_NAME.key
echo "</key>"
echo "<tls-crypt>"
sudo cat /etc/openvpn/tls-crypt.key
echo "</tls-crypt>"
} >> /root/CLIENT_NAME.ovpn
# Edit the .ovpn file to change from tun to tap
sudo sed -i 's/dev tun/dev tap/' /root/CLIENT_NAME.ovpn
echo "dev-type tap" | sudo tee -a /root/CLIENT_NAME.ovpn
For advanced users, consider creating a script to monitor certificate expiry:
#!/bin/bash
# Certificate monitoring script
# Place in /usr/local/bin/check-openvpn-certs.sh
CERT_DIR="/etc/openvpn/easy-rsa/pki"
WARN_DAYS=90
echo "Checking OpenVPN certificate expiry dates..."
# Check CA certificate
ca_expiry=$(openssl x509 -in "$CERT_DIR/ca.crt" -noout -enddate | cut -d= -f2)
ca_expiry_epoch=$(date -d "$ca_expiry" +%s)
current_epoch=$(date +%s)
days_until_ca_expiry=$(( (ca_expiry_epoch - current_epoch) / 86400 ))
echo "CA Certificate expires in $days_until_ca_expiry days ($ca_expiry)"
if [ $days_until_ca_expiry -lt $WARN_DAYS ]; then
echo "WARNING: CA certificate expires in less than $WARN_DAYS days!"
fi
# Check server certificate
server_expiry=$(openssl x509 -in "$CERT_DIR/issued/server.crt" -noout -enddate | cut -d= -f2)
server_expiry_epoch=$(date -d "$server_expiry" +%s)
days_until_server_expiry=$(( (server_expiry_epoch - current_epoch) / 86400 ))
echo "Server Certificate expires in $days_until_server_expiry days ($server_expiry)"
if [ $days_until_server_expiry -lt $WARN_DAYS ]; then
echo "WARNING: Server certificate expires in less than $WARN_DAYS days!"
fi
To use this script:
sudo chmod +x /usr/local/bin/check-openvpn-certs.sh
sudo /usr/local/bin/check-openvpn-certs.sh
Add to crontab for monthly checks:
# Edit root's crontab
sudo crontab -e
# Add this line for monthly certificate checks
0 0 1 * * /usr/local/bin/check-openvpn-certs.sh | mail -s "OpenVPN Certificate Status" admin@yourdomain.com
Once your VPN is working correctly:
For ongoing maintenance and troubleshooting, see the Troubleshooting Guide.