Difference between revisions of "OpenVPN Bridge"

From ArchWiki
Jump to: navigation, search
(updated openvpn examples from 1.6 to 2.1.1; gave preference to static bridge setup, as openvpn comes with openvpn-tapdev daemon on arch, and i believe it more closely follows the arch way)
Line 1: Line 1:
 
[[Category:Networking (English)]]
 
[[Category:Networking (English)]]
 
[[Category:HOWTOs (English)]]
 
[[Category:HOWTOs (English)]]
OpenVPN is a full-featured SSL VPN solution which can accommodate a wide range of configurations
+
'''TODO:''' check this now updated article for accuracy, readability and completeness
and is particularly useful for "road warriors" :).
+
  
This wiki page will discuss how to configure OpenVPN (1.6) in Bridge mode with a linux server and either a linux or a windows client. http://openvpn.sourceforge.net/howto.html discusses how to setup OpenVPN routing and explains the pros and cons of each. The article does not go into depth about iptables or how to allow traffic through your firewall to reach your OpenVPN machine.  This page describes the "quick n dirty" setup using a secret ssh key for authentication.  See the [http://www.openvpn.net OpenVPN website] for more information about SSL setups.
+
This page describes multiple ways to create a network bridge on Arch Linux and host an OpenVPN server using a IP layer-2 based Ethernet bridge (TAP) rather than a IP layer-3 based IP tunnel (TUN). The general [[OpenVPN]] page describes setting up PAM authentication or OpenSSL security certificates in more detail.
  
'''TODO''': This document seems out of date. I noticed there is a /etc/conf.d/bridges now, probably the bridging part should be taken out of the vpn configuration.
+
==Introduction==
  
==Server Config==
+
The [http://openvpn.net/index.php/open-source/documentation.html OpenVPN documentation pages] give a full overview of server-side and client-side options that OpenVPN supports. It is easier to set up OpenVPN in tunneling mode and control routing the traffic and it is generally advised to do so if it serves your purpose. However, some applications, such as Windows file sharing or Samba, rely on network broadcasts at the ethernet level and benefit from believing they are physically located on the same subnet, and software bridging serves this purpose.
First thing you want to do is install OpenVPN
+
 
 +
==Installation==
 +
 
 +
The first thing you want to do is install OpenVPN and Linux bridging utilities.
 
<pre>
 
<pre>
 
pacman -Sy openvpn bridge-utils
 
pacman -Sy openvpn bridge-utils
 
</pre>
 
</pre>
  
Next install this script as /etc/rc.d/openvpn
+
==Configuration==
 +
 
 +
Earlier versions of guides for OpenVPN provided by the OpenVPN team or various Linux packagers give example scripts for constructing a bridge when starting OpenVPN and destroying it when shutting OpenVPN down.
 +
 
 +
However, this is a somewhat deprecated approach, since OpenVPN as of 2.1.1 defaults to not allowing itself to call external scripts or programs unless explicitly enabled to, for security reasons.
 +
 
 +
Also, constructing the bridge is relatively slow compared to all other parts of the network initialization process. (In fact, so slow that dhcpcd will time out before the bridge is ready. See [[#Troubleshooting]].) Also, when restarting OpenVPN after configuration changes, there is no reason to rebuild a working bridge, interrupting all your other network applications. So, setting up a static bridge configuration as follows is one recommended method.
 +
 
 +
===Bridge===
 +
 
 +
Add a tap interface for OpenVPN to use in '''/etc/conf.d/openvpn-tapdev'''
 +
<pre>
 +
#
 +
# /etc/conf.d/openvpn-tapdev
 +
#
 +
# Place openvpn-tapdev before network into your DAEMONS array
 +
# This will create permanent tap devices which you can use for bridging
 +
#
 +
# Example:
 +
# TAPDEVS="work home"
 +
# Will create two tap devices "work" and "home"
 +
#
 +
TAPDEVS="tap0"
 +
</pre>
 +
 
 +
Add a rule for bridging this tap interface, and your other interfaces, to a bridge interface in '''/etc/conf.d/bridges'''
 +
<pre>
 +
#
 +
# Settings for layer-2 bridges
 +
#
 +
# For each bridge interface declared in INTERFACES (in rc.conf), declare
 +
# a bridge_${IF} variable that contains the real ethernet interfaces that
 +
# should be bridged together.
 +
#
 +
# Then list the bridge interface name in the BRIDGE_INTERFACES array.
 +
#
 +
# example:
 +
#
 +
# in /etc/rc.conf:
 +
#    eth0="eth0 up"
 +
#    eth1="eth1 up"
 +
#    br0="br0 192.168.0.2 netmask 255.255.255.0 up"
 +
#    INTERFACES=(lo eth0 eth1 br0)
 +
#
 +
# in /etc/conf.d/bridges
 +
#    bridge_br0="eth0 eth1"
 +
#    BRIDGE_INTERFACES=(br0)
 +
#
 +
bridge_br0="tap0 eth0"
 +
BRIDGE_INTERFACES=(br0)
 +
</pre>
 +
 
 +
Now, if using the default network daemon, invoke your bridge in '''/etc/rc.conf'''
 +
<pre>
 +
#...
 +
tap0="tap0 up"
 +
eth0="eth0 up"
 +
br0="dhcp"
 +
#alias example
 +
br0_0="br0:0 192.168.3.252 netmask 255.255.255.0 up"
 +
INTERFACES=(tap0 eth0 br0 br0_0)
 +
#...
 +
</pre>
 +
 
 +
===Server===
 +
 
 +
There are a few example server configurations located in '''/usr/share/openvpn/examples''' to look at.
 +
 
 +
Here is a server configuration that uses dhcp, and some features only available since 2.1.1, saved as '''/etc/openvpn/server.conf'''
 +
 
 +
{{Note|Setting '''multihome''' allows OpenVPN to listen on multiple interfaces with UDP but respond only on the one it first received a request from. Otherwise, if listening on multiple interfaces, OpenVPN may switch from one to the other during communication with a client, and clients would not accept packets originating from something other than the original endpoint. Lowering the value for '''script-security''' is necessary to write and invoke scripts that call external programs during OpenVPN operation}}
 +
<pre>
 +
# /etc/openvpn/server.conf
 +
# 2009.12.31
 +
#
 +
# address to bind to, instead of all available
 +
;local 192.168.3.252
 +
# new features, as of v2.1.1
 +
#can listen on multiple ips over udp
 +
multihome
 +
# needed to allow internally called scripts like up/down
 +
#  to call external programs like ifup, etc
 +
;script-security 2
 +
 
 +
# tcp might work better on certain "dev tun" setups
 +
#  but not for wrapping more tcp or further encrypted
 +
#  streams, as that would be redundant, and very slow
 +
# "port 1194" and "proto udp" are defaults
 +
port 1194
 +
proto udp
 +
 
 +
# could specify interface, like tap0 or tap1
 +
#  or use up/down routing scripts to handle
 +
#  more than one, if needed
 +
dev tap0
 +
 
 +
# simple scripts
 +
#  for adding/removing  to tap
 +
;up "up.sh br0:0"
 +
;down "down.sh br0:0"
 +
 
 +
# identical certificate on server & client
 +
ca config/keys/ca.crt
 +
# server's own cert/key
 +
cert config/keys/server.crt
 +
key config/keys/server.key  # keep secret
 +
# for certificate handshake
 +
dh config/keys/dh1024.pem
 +
 
 +
# no arguments will use this subnet's dhcp server
 +
#  not openvpn dynamic/static assigment
 +
# either way is good, but if you know you're not conflicting
 +
#  with any other IP addressing schemes on your subnet,
 +
#  this is much faster
 +
# this directive expands to include "mode server" and "tls-server"
 +
#  so including them elsewhere is redundant
 +
;server-bridge 192.168.3.252 255.255.255.0 192.168.3.1 192.168.3.16
 +
# like what dhcp does, reuses IPs
 +
;ifconfig-pool-persist ipp.txt
 +
 
 +
# this one uses a dhcp server, server-side
 +
#  potentially better for controlling ip addresses from one location
 +
#  clients must support binding their dhcp client to their tap adapter
 +
server-bridge nogw # 'nogw' is optional
 +
 
 +
# openvpn server routes client packets to each other itself
 +
#  should happen anyway in 'dev tap' mode, but this saves time
 +
client-to-client
 +
 
 +
# ping clients to auto close server side connection
 +
keepalive 10 60
 +
 
 +
# 0 for server, 1 for client
 +
tls-auth config/keys/ta.key 0 # This file is secret
 +
 
 +
# cryptographic cipher.
 +
;cipher BF-CBC        # Blowfish (default)
 +
cipher AES-128-CBC  # AES
 +
 
 +
# compression is useful for xfer of
 +
#  not already compressed files, like database
 +
#  files, otherwise add needless overhead
 +
# comp-lzo [mode] ; yes|no|adaptive, adaptive default
 +
;comp-lzo
 +
 
 +
# not needed yet
 +
;max-clients 100
 +
 
 +
# drop root priveledges once connected
 +
#  good idea, for servers running on linux
 +
user nobody
 +
group nobody
 +
 
 +
# avoid accessing things you no longer can
 +
persist-key
 +
persist-tun
 +
 
 +
# short status file showing current connections
 +
#  rewritten every minute.
 +
status openvpn-status.log
 +
 
 +
# use one or the other, useful for managing multiple
 +
#  concurrent servers on a system
 +
;log        openvpn.log
 +
;log-append  openvpn.log
 +
 
 +
# 0 is silent, except for fatal errors
 +
# 4 is reasonable for general usage
 +
# 5 and 6 can help to debug connection problems
 +
# 9 is extremely verbose
 +
verb 3
 +
 
 +
# silence repeating messages past certain number, in log
 +
;mute 20
 +
</pre>
 +
 
 +
The following modules will be automatically loaded, but you could specify them by editing '''/etc/rc.conf'''
 +
<pre>
 +
#...
 +
MODULES=(... tun bridge ...)
 +
#...
 +
</pre>
 +
 
 +
Now, add the following daemons to '''/etc/rc.conf'''
 +
{{Note|'''openvpn-tapdev''' must come before '''network'''}}
 +
<pre>
 +
#...
 +
DAEMONS=(... openvpn-tapdev network openvpn ...)
 +
#...
 +
</pre>
 +
 
 +
===Client===
 +
 
 +
The following is a matching '''client.ovpn''' for the options used in '''server.conf''' above, tested in Windows.
 +
{{Note|Windows supports authenticating via a dhcp server located on the OpenVPN server's side automatically because of how the TCP stack works on Windows; a Linux client may take more steps to get dhcp to work}}
 +
<pre>
 +
# /%openvpn%/config/client.conf
 +
# 2009.12.31
 +
 
 +
# defines order of certificate authentification
 +
# this directive expands to "pull" "tls-client"
 +
#  so including them elsewhere is redundant
 +
client
 +
 
 +
# type of server
 +
dev tap
 +
 
 +
# windows needs tap name, if more than one
 +
;dev-node OpenVPN Bridge Connection
 +
 
 +
# remote <hostname> [port] [proto]
 +
remote remote 1194 udp
 +
 
 +
# only works for peers using the "remote" option
 +
# ok if the ip address for remote changes during session
 +
float
 +
# uses a random port client-side
 +
nobind
 +
 
 +
# this is for laptops or internet conditions
 +
#  where openvpn server hostname cannot be resolved easily,
 +
#  or changes often, etc
 +
# infinte is the default, or value for seconds
 +
resolv-retry infinite
 +
 
 +
# public
 +
ca keys/ca.crt
 +
cert keys/satellite.crt
 +
# private
 +
key keys/satellite.key
 +
# needed when specified in server
 +
# 0 = server, 1 = client
 +
tls-auth keys/ta.key 1
 +
 
 +
# verify that the server has certificate field "server"
 +
# protects against certain attacks
 +
ns-cert-type server
 +
 
 +
;cipher BF-CBC
 +
cipher AES-128-CBC
 +
 
 +
# comp-lzo [mode] ; yes|no|adaptive, adaptive default
 +
;comp-lzo
 +
 
 +
# try to preserve some states across restarts
 +
persist-key
 +
persist-tun
 +
 
 +
verb 3
 +
</pre>
 +
 
 +
==Tips and Tricks==
 +
 
 +
{{Warning|This script doesn't always correctly report [FAIL] or [DONE] so output can't be relied upon and may be confusing. Also, it is very old and should probably be revisited and revised}}
  
'''TODO:''' this script doesn't always correctly report "FAILED" or "DONE" so output can't be relied upon and may be confusing.
+
You may not always want a static bridge, as there may be cases that you don't always want OpenVPN on, and when off you would prefer not having the bridge in place. In that case you have multiple options to achieve this. You could do this by replacing '''/etc/rc.d/openvpn''' with
Check /var/log/daemons if things don't seem to work.
+
 
<pre>
 
<pre>
 
#!/bin/bash
 
#!/bin/bash
Line 151: Line 405:
 
</pre>
 
</pre>
  
and make the script executable
+
and then make the script executable.
 
<pre>
 
<pre>
 
chmod 755 /etc/rc.d/openvpn
 
chmod 755 /etc/rc.d/openvpn
 
</pre>
 
</pre>
  
In /etc/rc.conf add the following modules to the MODULES array
+
Or, you can create scripts OpenVPN can use with '''up''' and '''down''' options to create and destroy tap interfaces dynamically, rather than using the provided openvpn-tapdev daemon, to add more options when adding it to a bridge. Here are some generic ones; make sure they are executable.
<pre>
+
tun bridge
+
</pre>
+
  
add the following configuration
+
'''up.sh'''
 
<pre>
 
<pre>
# Bridges and VPN setup
+
#!/bin/bash -e
br0=("br0 192.168.0.1 netmask 255.255.255.0 broadcast 192.168.0.255" eth0)
+
BRIDGES=(br0)
+
vpn0=("vpn0.conf" tap0 br0)
+
VPNS=(vpn0)
+
</pre>
+
  
and add the following daemons to the DAEMONS array
+
BR=$1
<pre>
+
DEV=$2
bridge_devices openvpn
+
MTU=$3
</pre>
+
  
So what does all of that mean up there?
+
/sbin/ifconfig $DEV mtu $MTU promisc up
First we create a bridge called br0 which attaches itself to eth0 and has certain ip address etc.
+
/usr/sbin/brctl addif $BR $DEV
Then we create a vpn daemon with config file "vpn0.conf" (see below) which uses device
+
tap0 and attaches to the bridge br0. The "BRIDGES" and "VPNS" arrays should allow you to define more then
+
one of each (but I didn't test this).
+
  
===Now onto creating the config files===
+
exit 0
Firstly create the secret key
+
<pre>
+
openvpn --genkey --secret /etc/openvpn/vpn0.key
+
 
</pre>
 
</pre>
and then make the vpn0.conf and save it in /etc/openvpn/
 
<pre>
 
#/etc/openvpn/vpn0.conf
 
#
 
# Sample OpenVPN server configuration file
 
# using a pre-shared static key.
 
#
 
# See man openvpn for more configuration options.
 
# (the config file options are the same as the commandline switches)
 
#
 
# '#' or ';' may be used to delimit comments.
 
  
# Define the virtual ethernet device.
+
'''down.sh'''
dev tap0
+
 
+
# Our pre-shared static key
+
secret /etc/openvpn/vpn0.key
+
 
+
# OpenVPN uses UDP port 1194 by default.
+
# Each OpenVPN tunnel must use
+
# a different port number.
+
# lport or rport can be used
+
# to denote different ports
+
# for local and remote.
+
port 1194
+
 
+
# Protocol to use; udp is the default for good reason.
+
# Alternative is 'tcp-server' (with 'tcp-client' on the other side of the line)
+
# which can be useful in certain situations or behind certain firewalls.
+
; proto udp
+
 
+
# Downgrade UID and GID to
+
# "nobody" after initialization
+
# for extra security.
+
user nobody
+
group nobody
+
 
+
# If you built OpenVPN with
+
# LZO compression, uncomment
+
# out the following line.
+
comp-lzo
+
 
+
# Send a UDP ping to remote once
+
# every 15 seconds to keep
+
# stateful firewall connection
+
# alive.  Uncomment this
+
# out if you are using a stateful
+
# firewall.
+
; ping 15
+
 
+
# Uncomment this section for a more reliable detection when a system
+
# loses its connection.  For example, dial-ups or laptops that
+
# travel to other locations.
+
ping 15
+
ping-restart 45
+
ping-timer-rem
+
persist-tun
+
persist-key
+
 
+
# Verbosity level.
+
# 0 -- quiet except for fatal errors.
+
# 1 -- mostly quiet, but display non-fatal network errors.
+
# 3 -- medium output, good for normal operation.
+
# 9 -- verbose, good for troubleshooting
+
verb 3
+
</pre>
+
 
+
If you have more then one vpn daemon you should not reuse devices or port numbers across .conf files.
+
 
+
Now we can start up our daemons scripts.
+
 
<pre>
 
<pre>
sudo modprobe tun
+
#!/bin/bash -e
sudo modprobe bridge
+
sudo /etc/rc.d/openvpn start
+
</pre>
+
  
==Linux client config==
+
BR=$1
Install openvpn on the client machine the same way as on the server.
+
DEV=$2
Copy /etc/rc.d/openvpn, /etc/openvpn/vpn0.key and /etc/openvpn/vpn0.conf to the client (preferably using sftp or scp).
+
  
Add the following lines to /etc/openvpn/vpn0.conf with the "real" address of the server
+
/usr/sbin/brctl delif $BR $DEV
and the virtual address of the client.
+
/sbin/ifconfig $DEV down
<pre>
+
remote real_server_address
+
ifconfig vpn_client_ip vpn_netmask
+
</pre>
+
(And set proto to 'tcp-client' if you used 'tcp-server' on the server)
+
  
Now edit /etc/rc.conf to include
+
exit 0
<pre>
+
# Bridges and VPN setup
+
BRIDGES=()
+
vpn0=("vpn0.conf" tap0)
+
VPNS=(vpn0)
+
 
</pre>
 
</pre>
  
Now start it up
+
==Troubleshooting==
<pre>
+
modprobe tun
+
/etc/rc.d/openvpn start
+
</pre>
+
  
You should now be able to ping across the tunnel to any of the hosts on the other end.
+
Q: Why does starting the network [FAIL] ?
 
+
==Windows client config==
+
Install OpenVPN from openvpn-1.6.0-install.exe
+
now copy the vpn0.key from the VPN server (preferably using sftp or scp) and the vpn0.conf
+
below to "C:\Program Files\OpenVPN\config\". And delete the sample file in that folder (or at least move it to another folder).
+
<pre>
+
# replace with the public ip address of the vpn server
+
remote remote.public.ip.address
+
port 1194
+
dev tap
+
ifconfig 192.168.0.200 255.255.255.0
+
ifconfig-nowarn
+
secret "C:\Program Files\OpenVPN\config\vpn0.key"
+
ping 10
+
comp-lzo
+
verb 5
+
</pre>
+
  
Now open a command prompt and enter
+
A: If you followed the server.conf example above, it is because you are using dhcp on the bridge and setting up the bridge takes longer than dhcpcd is willing to wait. You can fix this by dropping the forwarding delay when adding the bridge to a lower number by adding the following line to '''/etc/rc.d/network'''
 
<pre>
 
<pre>
net start openvpnservice
+
.. /usr/sbin/brctl addbr $br
 +
+  /usr/sbin/brctl setfd $br 5
 +
.. eval brifs="\$bridge_${br}"
 
</pre>
 
</pre>
  
You should now be able to ping across the tunnel to any of the hosts on the other end.
+
==More Resources==
  
 +
[[OpenVPN]] | General page on configuring OpenVPN, including setting up authentication methods.
 
----
 
----
  

Revision as of 03:16, 14 June 2010

TODO: check this now updated article for accuracy, readability and completeness

This page describes multiple ways to create a network bridge on Arch Linux and host an OpenVPN server using a IP layer-2 based Ethernet bridge (TAP) rather than a IP layer-3 based IP tunnel (TUN). The general OpenVPN page describes setting up PAM authentication or OpenSSL security certificates in more detail.

Introduction

The OpenVPN documentation pages give a full overview of server-side and client-side options that OpenVPN supports. It is easier to set up OpenVPN in tunneling mode and control routing the traffic and it is generally advised to do so if it serves your purpose. However, some applications, such as Windows file sharing or Samba, rely on network broadcasts at the ethernet level and benefit from believing they are physically located on the same subnet, and software bridging serves this purpose.

Installation

The first thing you want to do is install OpenVPN and Linux bridging utilities.

pacman -Sy openvpn bridge-utils

Configuration

Earlier versions of guides for OpenVPN provided by the OpenVPN team or various Linux packagers give example scripts for constructing a bridge when starting OpenVPN and destroying it when shutting OpenVPN down.

However, this is a somewhat deprecated approach, since OpenVPN as of 2.1.1 defaults to not allowing itself to call external scripts or programs unless explicitly enabled to, for security reasons.

Also, constructing the bridge is relatively slow compared to all other parts of the network initialization process. (In fact, so slow that dhcpcd will time out before the bridge is ready. See #Troubleshooting.) Also, when restarting OpenVPN after configuration changes, there is no reason to rebuild a working bridge, interrupting all your other network applications. So, setting up a static bridge configuration as follows is one recommended method.

Bridge

Add a tap interface for OpenVPN to use in /etc/conf.d/openvpn-tapdev

#
# /etc/conf.d/openvpn-tapdev
#
# Place openvpn-tapdev before network into your DAEMONS array
# This will create permanent tap devices which you can use for bridging
#
# Example:
# TAPDEVS="work home"
# Will create two tap devices "work" and "home"
#
TAPDEVS="tap0"

Add a rule for bridging this tap interface, and your other interfaces, to a bridge interface in /etc/conf.d/bridges

#
# Settings for layer-2 bridges
#
# For each bridge interface declared in INTERFACES (in rc.conf), declare
# a bridge_${IF} variable that contains the real ethernet interfaces that
# should be bridged together.
#
# Then list the bridge interface name in the BRIDGE_INTERFACES array.
#
# example:
#
# in /etc/rc.conf:
#    eth0="eth0 up"
#    eth1="eth1 up"
#    br0="br0 192.168.0.2 netmask 255.255.255.0 up"
#    INTERFACES=(lo eth0 eth1 br0)
#
# in /etc/conf.d/bridges
#    bridge_br0="eth0 eth1"
#    BRIDGE_INTERFACES=(br0)
#
bridge_br0="tap0 eth0"
BRIDGE_INTERFACES=(br0)

Now, if using the default network daemon, invoke your bridge in /etc/rc.conf

#...
tap0="tap0 up"
eth0="eth0 up"
br0="dhcp"
#alias example
br0_0="br0:0 192.168.3.252 netmask 255.255.255.0 up"
INTERFACES=(tap0 eth0 br0 br0_0)
#...

Server

There are a few example server configurations located in /usr/share/openvpn/examples to look at.

Here is a server configuration that uses dhcp, and some features only available since 2.1.1, saved as /etc/openvpn/server.conf

Note: Setting multihome allows OpenVPN to listen on multiple interfaces with UDP but respond only on the one it first received a request from. Otherwise, if listening on multiple interfaces, OpenVPN may switch from one to the other during communication with a client, and clients would not accept packets originating from something other than the original endpoint. Lowering the value for script-security is necessary to write and invoke scripts that call external programs during OpenVPN operation
# /etc/openvpn/server.conf
# 2009.12.31
#
# address to bind to, instead of all available
;local 192.168.3.252
# new features, as of v2.1.1
#can listen on multiple ips over udp
multihome
# needed to allow internally called scripts like up/down
#  to call external programs like ifup, etc
;script-security 2

# tcp might work better on certain "dev tun" setups
#  but not for wrapping more tcp or further encrypted
#  streams, as that would be redundant, and very slow
# "port 1194" and "proto udp" are defaults
port 1194
proto udp

# could specify interface, like tap0 or tap1
#  or use up/down routing scripts to handle
#  more than one, if needed
dev tap0

# simple scripts
#  for adding/removing  to tap
;up "up.sh br0:0"
;down "down.sh br0:0"

# identical certificate on server & client
ca config/keys/ca.crt
# server's own cert/key
cert config/keys/server.crt
key config/keys/server.key  # keep secret
# for certificate handshake
dh config/keys/dh1024.pem

# no arguments will use this subnet's dhcp server
#  not openvpn dynamic/static assigment
# either way is good, but if you know you're not conflicting
#  with any other IP addressing schemes on your subnet,
#  this is much faster
# this directive expands to include "mode server" and "tls-server"
#  so including them elsewhere is redundant
;server-bridge 192.168.3.252 255.255.255.0 192.168.3.1 192.168.3.16
# like what dhcp does, reuses IPs
;ifconfig-pool-persist ipp.txt

# this one uses a dhcp server, server-side
#  potentially better for controlling ip addresses from one location
#  clients must support binding their dhcp client to their tap adapter
server-bridge nogw # 'nogw' is optional

# openvpn server routes client packets to each other itself
#  should happen anyway in 'dev tap' mode, but this saves time
client-to-client

# ping clients to auto close server side connection
keepalive 10 60

# 0 for server, 1 for client
tls-auth config/keys/ta.key 0 # This file is secret

# cryptographic cipher.
;cipher BF-CBC        # Blowfish (default)
cipher AES-128-CBC   # AES

# compression is useful for xfer of
#  not already compressed files, like database
#  files, otherwise add needless overhead
# comp-lzo [mode] ; yes|no|adaptive, adaptive default
;comp-lzo

# not needed yet
;max-clients 100

# drop root priveledges once connected
#  good idea, for servers running on linux
user nobody
group nobody

# avoid accessing things you no longer can
persist-key
persist-tun

# short status file showing current connections
#  rewritten every minute.
status openvpn-status.log

# use one or the other, useful for managing multiple
#  concurrent servers on a system
;log         openvpn.log
;log-append  openvpn.log

# 0 is silent, except for fatal errors
# 4 is reasonable for general usage
# 5 and 6 can help to debug connection problems
# 9 is extremely verbose
verb 3

# silence repeating messages past certain number, in log
;mute 20

The following modules will be automatically loaded, but you could specify them by editing /etc/rc.conf

#...
MODULES=(... tun bridge ...)
#...

Now, add the following daemons to /etc/rc.conf

Note: openvpn-tapdev must come before network
#...
DAEMONS=(... openvpn-tapdev network openvpn ...)
#...

Client

The following is a matching client.ovpn for the options used in server.conf above, tested in Windows.

Note: Windows supports authenticating via a dhcp server located on the OpenVPN server's side automatically because of how the TCP stack works on Windows; a Linux client may take more steps to get dhcp to work
# /%openvpn%/config/client.conf
# 2009.12.31

# defines order of certificate authentification
# this directive expands to "pull" "tls-client"
#  so including them elsewhere is redundant
client

# type of server
dev tap

# windows needs tap name, if more than one
;dev-node OpenVPN Bridge Connection

# remote <hostname> [port] [proto]
remote remote 1194 udp

# only works for peers using the "remote" option
# ok if the ip address for remote changes during session
float
# uses a random port client-side
nobind

# this is for laptops or internet conditions
#  where openvpn server hostname cannot be resolved easily,
#  or changes often, etc
# infinte is the default, or value for seconds
resolv-retry infinite

# public
ca keys/ca.crt
cert keys/satellite.crt
# private
key keys/satellite.key
# needed when specified in server
# 0 = server, 1 = client
tls-auth keys/ta.key 1

# verify that the server has certificate field "server"
# protects against certain attacks
ns-cert-type server

;cipher BF-CBC
cipher AES-128-CBC

# comp-lzo [mode] ; yes|no|adaptive, adaptive default
;comp-lzo

# try to preserve some states across restarts
persist-key
persist-tun

verb 3

Tips and Tricks

Warning: This script doesn't always correctly report [FAIL] or [DONE] so output can't be relied upon and may be confusing. Also, it is very old and should probably be revisited and revised

You may not always want a static bridge, as there may be cases that you don't always want OpenVPN on, and when off you would prefer not having the bridge in place. In that case you have multiple options to achieve this. You could do this by replacing /etc/rc.d/openvpn with

#!/bin/bash

# /etc/rc.d/openvpn
#
# An init script to start and stop OpenVPN daemons

. /etc/rc.conf
. /etc/rc.d/functions

openvpn_config_dir=/etc/openvpn

make_bridge ()
{
	#echo "# mkbr $1"
	# for example $1 = "br0" and
	# $br0 = ("br0 192.168.2.1 netmask 255.255.255.0 broadcast 192.168.2.255" eth1)	
	eval brvar="(\"\${${1}[@]}\")"
	brdev=$1

	brctl addbr $brdev
	add_to_bridge ${brvar[1]} $brdev

        ifconfig ${brvar[0]}
	return $?
}

add_to_bridge ()
{
	#echo "# addbr $1 $2"
	# for example $1=tap0 and $2=br0
	ifconfig $1 down >/dev/null 2>&1
	brctl addif $2 $1
	ifconfig $1 0.0.0.0 promisc up
}

destroy_bridge ()
{
	eval brvar="(\"\${${1}[@]}\")"
	brdev=$1
	
	ifconfig $brdev down
	brctl delbr $brdev
}

make_vpn ()
{
	#echo  "# mkvpn $1"
	# for example $1 = vpn0 and
	# $vpn0 = ("default.conf" tap0 br0)
	eval vpnvar="(\"\${${1}[@]}\")"
	
	openvpn --mktun --dev ${vpnvar[1]} > /dev/null
	if [ "${vpnvar[2]}" != "" ]; then
		add_to_bridge ${vpnvar[1]} ${vpnvar[2]}
	fi

	openvpn --cd $openvpn_config_dir --daemon --config ${vpnvar[0]}
	return $?
}

destroy_vpn ()
{
	eval vpnvar="(\"\${${1}[@]}\")"
	openvpn --rmtun --dev ${vpnvar[1]} > /dev/null
	return $?
}

case "$1" in
        start)
        stat_busy "Starting OpenVPN daemons"

        # enable IP forwarding
        echo 1 > /proc/sys/net/ipv4/ip_forward

	# create bridge(s)
	error=0
       	for brconf in ${BRIDGES[@]}; do
               	if echo $brconf | grep '^[^\!]' >/dev/null 2>&1; then
                       	make_bridge $brconf || error=1
               	fi
       	done

	# create vpn(s)
       	for vpnconf in ${VPNS[@]}; do
               	if echo $vpnconf | grep '^[^\!]' >/dev/null 2>&1; then
                       	make_vpn $vpnconf || error=1
               	fi
       	done

	if [ $error -eq 0 ]; then
		stat_done
	else
		stat_fail
	fi
	;;
        stop)
        stat_busy "Stopping OpenVPN daemons"

        killall `which openvpn` 2> /dev/null

	# destroy bridge(s)
	error=0
       	for brconf in ${BRIDGES[@]}; do
               	if echo $brconf | grep '^[^\!]' >/dev/null 2>&1; then
                       	destroy_bridge $brconf || error=1
               	fi
       	done

	# destroy vpn(s)
       	for vpnconf in ${VPNS[@]}; do
               	if echo $vpnconf | grep '^[^\!]' >/dev/null 2>&1; then
                       	destroy_vpn $vpnconf || error=1
               	fi
       	done

	if [ $error -eq 0 ]; then
		stat_done
	else
		stat_fail
	fi
	;;
        restart)
                $0 stop
		sleep 1
                $0 start
                ;;
        *)
                echo $"Usage: $0 {start|stop|restart}"
                RETVAL=1
esac

and then make the script executable.

chmod 755 /etc/rc.d/openvpn

Or, you can create scripts OpenVPN can use with up and down options to create and destroy tap interfaces dynamically, rather than using the provided openvpn-tapdev daemon, to add more options when adding it to a bridge. Here are some generic ones; make sure they are executable.

up.sh

#!/bin/bash -e

BR=$1
DEV=$2
MTU=$3

/sbin/ifconfig $DEV mtu $MTU promisc up
/usr/sbin/brctl addif $BR $DEV

exit 0

down.sh

#!/bin/bash -e

BR=$1
DEV=$2

/usr/sbin/brctl delif $BR $DEV
/sbin/ifconfig $DEV down

exit 0

Troubleshooting

Q: Why does starting the network [FAIL] ?

A: If you followed the server.conf example above, it is because you are using dhcp on the bridge and setting up the bridge takes longer than dhcpcd is willing to wait. You can fix this by dropping the forwarding delay when adding the bridge to a lower number by adding the following line to /etc/rc.d/network

.. /usr/sbin/brctl addbr $br
+  /usr/sbin/brctl setfd $br 5
.. eval brifs="\$bridge_${br}"

More Resources

OpenVPN | General page on configuring OpenVPN, including setting up authentication methods.


Any additions, clarifications, reorganizations, feedback etc. etc. are more than appreciated.