Skip to content

Instantly share code, notes, and snippets.

@Belphemur
Last active January 29, 2024 11:45
Show Gist options
  • Star 41 You must be signed in to star a gist
  • Fork 9 You must be signed in to fork a gist
  • Save Belphemur/3b03eaad96172b2159fc to your computer and use it in GitHub Desktop.
Save Belphemur/3b03eaad96172b2159fc to your computer and use it in GitHub Desktop.
Configuration and scripts for OpenVPN in Bridged Mode. Script to generate new client (with their keys and configuration file for OpenVPN). Script to manage the bridge. Configuration for systemd to start/stop the OpenVPN with Brige.
#!/bin/bash
# Define physical ethernet interface to be bridged
# with TAP interface(s) above.
eth="eth0"
eth_ip="192.168.42.2"
eth_netmask="255.255.255.0"
eth_broadcast="192.168.42.255"
eth_gateway="192.168.42.1"
eth_mac="XX:XX:XX:XX:XX:XX"
# Define Bridge Interface
br="br0"
# Define list of TAP interfaces to be bridged together
tap="tap0"
#!/bin/bash
. /etc/openvpn/bridge/bridge-conf
#################################
# Set up Ethernet bridge on Linux
# Requires: bridge-utils
#################################
for t in $tap; do
openvpn --mktun --dev $t
done
brctl addbr $br
brctl addif $br $eth
for t in $tap; do
brctl addif $br $t
done
for t in $tap; do
ifconfig $t 0.0.0.0 promisc up
iptables -A INPUT -i $t -j ACCEPT
done
iptables -A INPUT -i $br -j ACCEPT
iptables -A FORWARD -i $br -j ACCEPT
ifconfig $eth 0.0.0.0 promisc up
ifconfig $br $eth_ip netmask $eth_netmask broadcast $eth_broadcast
ip link set $br address $eth_mac
route add default gw $eth_gateway $br
#!/bin/bash
. /etc/openvpn/bridge/bridge-conf
####################################
# Tear Down Ethernet bridge on Linux
####################################
iptables -D INPUT -i $br -j ACCEPT
iptables -D FORWARD -i $br -j ACCEPT
ifconfig $br down
brctl delbr $br
for t in $tap; do
openvpn --rmtun --dev $t
iptables -D INPUT -i $t -j ACCEPT
done
ifconfig $eth $eth_ip netmask $eth_netmask broadcast $eth_broadcast
route add default gw $eth_gateway $eth
#!/bin/bash
#This script generate the key for the wanted client and it's configuration file
#to be used with OpenVPN. If the key has already been generated it will only
#generate the configuration file for OpenVPN
#VARIABLES
#If you don't set a remote (the external IP of the server or the hostname)
#the script will try to gather it using dig
#You need to change the port to the one set in your server
#if you want to add new directive to client configuration use $OPENVPN_CLIENT_DIRECTIVE
PROTO="${PROTO:-udp}"
REMOTE="${REMOTE:-}"
PORT="${PORT:-5555}"
OPENVPN_EASY_RSA_PATH="/etc/openvpn/easy-rsa/"
OPENVPN_CLIENT_DIRECTIVE="${OPENVPN_CLIENT_DIRECTIVE:-}"
DEV_TYPE=${DEV_TYPE:-tap0}
COMPRESS=${COMPRESS:-compress}
#DO NOT MODIFY BELOW
function usage {
echo "Usage: $0 clientName"
echo "ENV Variables:"
echo "PROTO: protocol used"
echo "REMOTE: host or IP address of the server"
echo "PORT: port on the server"
echo "DEV_TYPE: device type (tun+/tap+)"
echo "COMPRESS: The compression algorithm used (comp-lzo, compress (if pushed by the server), compress snappy)"
exit -1
}
function getIp {
echo `dig +short myip.opendns.com @resolver1.opendns.com`
}
function clientConfig {
cat <<CLIENT_CONF
client
dev $DEV_TYPE
proto $PROTO
remote $REMOTE $PORT
resolv-retry infinite
nobind
persist-key
persist-tun
remote-cert-tls server
cipher AES-256-CBC
auth SHA512
$COMPRESS
verb 3
pull
$OPENVPN_CLIENT_DIRECTIVE
<ca>
$CA
</ca>
<cert>
$CERT
</cert>
<key>
$KEY
</key>
CLIENT_CONF
}
if [ $# -eq 0 ]; then
echo "No arguments supplied"
usage
fi
if [ -z "$1" ]; then
echo "Client name not supplied"
usage
fi
if [ -z "$REMOTE" ]; then
REMOTE=$(getIp)
fi
CLIENT=$1
if [ ! -f $OPENVPN_EASY_RSA_PATH/keys/${CLIENT}.crt ]; then
pushd $OPENVPN_EASY_RSA_PATH
source ./vars
./build-key $CLIENT
popd
fi
CA=`cat $OPENVPN_EASY_RSA_PATH/keys/ca.crt | grep -A 100 "BEGIN CERTIFICATE" | grep -B 100 "END CERTIFICATE"`
CERT=`cat $OPENVPN_EASY_RSA_PATH/keys/${CLIENT}.crt | grep -A 100 "BEGIN CERTIFICATE" | grep -B 100 "END CERTIFICATE"`
KEY=`cat $OPENVPN_EASY_RSA_PATH/keys/${CLIENT}.key | grep -A 100 "BEGIN PRIVATE KEY" | grep -B 100 "END PRIVATE KEY"`
clientConfig > $CLIENT.ovpn
exit 0
[Unit]
Description=OpenVPN server %i
Wants=syslog.target
Requires=network.target
After=network-online.target
Documentation=man:openvpn(8)
Documentation=https://community.openvpn.net/openvpn/wiki/Openvpn23ManPage
Documentation=https://community.openvpn.net/openvpn/wiki/HOWTO
Documentation=https://www.aaflalo.me/2015/01/openvpn-tap-bridge-mode
[Service]
PrivateTmp=true
Type=forking
PermissionsStartOnly=true
RuntimeDirectory=openvpn
ExecStartPre=/etc/openvpn/bridge/bridge-start
PIDFile=/run/openvpn/%i.pid
ExecStart=/usr/sbin/openvpn --cd /etc/openvpn/ --status /run/openvpn/status-%i.log --status-version 2 --config %i.conf --daemon --writepid /run/openvpn/%i.pid
ExecStopPost=/etc/openvpn/bridge/bridge-stop
CapabilityBoundingSet=CAP_IPC_LOCK CAP_NET_ADMIN CAP_NET_BIND_SERVICE CAP_NET_RAW CAP_SETGID CAP_SETUID CAP_SYS_CHROOT CAP_DAC_READ_SEARCH CAP_AUDIT_WRITE
LimitNPROC=10
DeviceAllow=/dev/null rw
DeviceAllow=/dev/net/tun rw
[Install]
WantedBy=multi-user.target
dev tap0
#tun-mtu 1500
#tun-ipv6
tls-server
proto udp
port 5555
ca /etc/openvpn/easy-rsa/keys/ca.crt
cert /etc/openvpn/easy-rsa/keys/server.crt
key /etc/openvpn/easy-rsa/keys/server.key
dh /etc/openvpn/easy-rsa/keys/dh4096.pem
topology subnet
user nobody
group nogroup
server-bridge 192.168.42.2 255.255.255.0 192.168.42.128 192.168.42.254
#server-ipv6 2001:db8::/64
mssfix
persist-key
persist-tun
#log /var/log/openvpn
status /var/log/openvpn-status.log
verb 4
client-to-client
keepalive 10 120
mute 50
#set the dns servers
push "dhcp-option DNS 192.168.42.1"
#set the WINS server (SAMBA)
push "dhcp-option WINS 192.168.42.2"
#For windows, to make the network recognized
push "route 0.0.0.0 0.0.0.0 192.168.42.2"
cipher AES-256-CBC
auth SHA512
log-append /var/log/openvpn
compress lz4-v2
# Activate this option only if you're running OpenVPN < 2.4.X
# In that case, you can disable the compress lz4-v2 and enable comp-lzo.
#comp-lzo
#replay-window 128
@Emran1987
Copy link

can you please give me the diagram and as well vpn router and client ip address details

@blazeyzem
Copy link

Something went wrong with pam (let alone the fact that Debian tought that it might be fun to move /usr/lib/openvpn/openvpn-plugin-auth-pam.so to /usr/lib/x86_64-linux-gnu/openvpn/plugins/openvpn-plugin-auth-pam.so without a warning a couple of weeks ago.), and I got this line in my /var/log/auth.log: PAM audit_log_acct_message() failed: Operation not permitted.

This is due to systemd's capabilities, that are wrongly set in the /lib/systemd/system/openvpn@.service file, missing the CAP_AUDIT_WRITE

@Belphemur
Copy link
Author

@blazeyzem Thanks for your comment.

I've added the missing capability.

@blazeyzem
Copy link

blazeyzem commented Mar 3, 2020 via email

@daduskacpokus
Copy link

Awesome!

@bnhf
Copy link

bnhf commented Mar 7, 2022

I've been having issues setting up OpenVPN TAP servers on Debian 11 with the widely-used "openvpn-bridge" script. The above separate scripts for starting and stopping seem to be working better though, with the only issue I've had so far being the need to specifically add my two Pihole DNS servers to the /etc/resolve.conf file in the form:

nameserver 192.168.xxx.xxx
nameserver 192.168.xxx.xxx

This was necessary for the machine hosting the OpenVPN server to have DNS services available.

Thanks for posting!

@bnhf
Copy link

bnhf commented Mar 13, 2022

These scripts are certainly working better than the all-in-one openvpn-bridge script I was using, however I'm having an issue with my bridged Ethernet connection becoming unresponsive about once-a-day. Annoying to say the least on a headless system. It's definitely something with the bridge, as it can be fixed by restarting OpenVPN with:

/etc/init.d/openvpn restart

Requires connecting a console though, so I've written a script to monitor when the host is no longer able to dig a hostname on the LAN. Obviously, I'd like to figure out what's causing this (I have four hosts all exhibiting this same behavior), but in the meantime this script is working. I recommend naming it bridge-check, and putting it in the same /etc/openvpn/bridge directory as the others above. Make it executable, and add it to the root crontab -e in the form @reboot /etc/openvpn/bridge/bridge-check :

#!/bin/bash

# redirect stdout/stderr to syslog
exec 1> >(logger -s -t $(basename $0)) 2>&1

# Assign values to gateway variables
GATEWAY_HOST="UniFiSecurityGateway.localdomain"
GATEWAY_IP="192.168.110.1"

# Initial pause after boot
sleep 120

# begin infinite loop
while :
	do
		# check if primary gateway responds with IP
		REPLY=$(dig $GATEWAY_HOST +short)
			if [ "$REPLY" != $GATEWAY_IP ]
				then
					/etc/init.d/openvpn restart
					echo "OpenVPN server restarted due to failed dig"
					sleep 180
				else
					echo "OpenVPN bridge OK"
					sleep 60
			fi
	done

If you use Cockpit, look under Logs - Info and above - priority:info openvpn to get a display like this, where you can see all the checks and if there have been any restarts:

screenshot-brix-pc2-2022 03 13-13_23_10

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment