Docker-openvpn: How do you set up a bridge VPN (TAP) with this?

Created on 2 Apr 2019  路  10Comments  路  Source: kylemanna/docker-openvpn

Simply using the -t option changes the the device to tap0, but doesn't change the server directive to server-bridge. But even after doing that, TAP mode doesn't work. Is there a way to make the OpenVPN server provide a TAP bridged VPN?

Most helpful comment

Interested in knowing this as well, I have unsuccessfully tried to set it up and looked for dockerized examples of a tap setup to no avail.

All 10 comments

Interested in knowing this as well, I have unsuccessfully tried to set it up and looked for dockerized examples of a tap setup to no avail.

I'm working on fork for doing this and I have it functional right now but with some manual tweaking. Multi-arch docker images are on docker hub. I'm running this on BeagleBoneBlack (armv7, Debian GNU/Linux 10 (buster)).

My tweaks:

  • change server to server-bridge in openvpn.config
#server 192.168.255.0 255.255.255.0
server-bridge 192.168.1.199 255.255.255.0 192.168.1.191 192.168.1.198
  • run docker with --net host
export OVPN_DATA=ovpn-data-tap-host

docker run \
    -v $OVPN_DATA:/etc/openvpn \
    --log-opt max-size=10m \
    --name openvpn-tap-host -d \
    --net host \
    --restart always \
    --cap-add=NET_ADMIN \
    aktur/openvpn
  • adding bridge-start executable script, my example with hardcoded values:
bash-5.0# cat /etc/openvpn/bridge-start 
#!/bin/bash

#################################
# Set up Ethernet bridge on Linux
# Requires: bridge-utils
#################################

# Define Bridge Interface
br="br0"

# Define list of TAP interfaces to be bridged,
# for example tap="tap0 tap1 tap2".
tap="tap0"

# Define physical ethernet interface to be bridged
# with TAP interface(s) above.
eth="eth0"
eth_ip="192.168.1.199"
eth_netmask="255.255.255.0"
eth_broadcast="192.168.1.255"
gateway="192.168.1.1"

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
done

ifconfig $eth 0.0.0.0 promisc up

ifconfig $br $eth_ip netmask $eth_netmask broadcast $eth_broadcast

# Add default route if eth is also gateway port
route add default gw $gateway $br

@aktur Hi there,
I'm trying to use your fork to get this up and running. It seems like the container is starting fine and one client can connect to it. A second connection is not possible. Are there additional steps to be taken for this?

When do you run the bridge-start script? Is this done by the container. I did not see this in the container logs and running it before starting the container results in many errors: tap0 does not (yet) exist, ifconfig command not found (host is arch so ip is used).

Thank you very much!

@Mailblocker I have no problems with connecting a second client to my tap server. Are you using different keys for both connections?

bridge-start is run by the container. I'm not sure if there should be any logs visible. No need to start it manually, you only need to put correct values corresponding to your network configuration in it.

@aktur Thank you for the quick reply.

I'm using different keys for both connections. Maybe I did something wrong in the initial setup. How do I tell the openvpn server to use tap mode? Only by setting the openvpn.conf parameter dev from tun to tap? I think this line if [ $OVPN_DEVICE == "tap" ]; then is not processed in my setup. At least I dont see any bridges created on the host system after starting up the container.

@Mailblocker the tap device you set indeed in the initial setup. In the Quick start section you have the line

docker run -v $OVPN_DATA:/etc/openvpn --log-driver=none --rm aktur/openvpn ovpn_genconfig -u udp://VPN.SERVERNAME.COM # add -t for TAP device 

therefore you must add -t when running ovpn_genconfig

@aktur Thank you very much! Damn I missed that, I will try the setup from scratch this week.

Hi @aktur
I gave it another shot today but I couldn't fully succeed. This is the steps I have taken from a clean start:

1. export OVPN_DATA=absolute_path_to_data_volume
2. export OVPN_URL=url_to_my_server
3. echo OVPN_DATA=$OVPN_DATA > .env
4. docker-compose.yml

    version: '3.8'

    services:
      openvpn_tap:
        container_name: openvpn_tap
        image: aktur/openvpn
        restart: always
        cap_add:
         - NET_ADMIN
        network_mode: "host"
        volumes:
         - ${OVPN_DATA}:/etc/openvpn

5. docker run -v $OVPN_DATA:/etc/openvpn --log-driver=none --rm aktur/openvpn ovpn_genconfig -u udp://$OVPN_URL -t
6. docker run -v $OVPN_DATA:/etc/openvpn --rm -it aktur/openvpn ovpn_initpki
    6.1 insert password for ca cert
7. docker-compose up -d openvpn_tap 
9. export CLIENTNAME=some_user_name
8. docker run -v $OVPN_DATA:/etc/openvpn --rm -it aktur/openvpn easyrsa build-client-full $CLIENTNAME
    8.1 enter password for user twice
    8.2 enter password for ca cert to sign the user cert
9. docker run -v $OVPN_DATA:/etc/openvpn --rm aktur/openvpn ovpn_getclient $CLIENTNAME > $CLIENTNAME.ovpn
10. Copy the client file to my machine: scp $CLIENTNAME.ovpn some_user@some_machine:~
11. Edit openvpn conf first line to: server-bridge 192.168.2.42 255.255.255.0 192.168.2.101 192.168.2.200
12. Create bridge-start at $OVPN_DATA/bridge-start with content:
    #!/bin/bash

    #################################
    # Set up Ethernet bridge on Linux
    # Requires: bridge-utils
    #################################

    # Define Bridge Interface
    br="br0"

    # Define list of TAP interfaces to be bridged,
    # for example tap="tap0 tap1 tap2".
    tap="tap0"

    # Define physical ethernet interface to be bridged
    # with TAP interface(s) above.
    eth="wlp1s0"
    eth_ip="192.168.2.42"
    eth_netmask="255.255.255.0"
    eth_broadcast="192.168.2.255"
    gateway="192.168.2.1"

    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
    done

    ifconfig $eth 0.0.0.0 promisc up

    ifconfig $br $eth_ip netmask $eth_netmask broadcast $eth_broadcast

    # Add default route if eth is also gateway port
    route add default gw $gateway $br

12. chmod +x  $OVPN_DATA/bridge-start 
13. docker-compose down
14. docker-compose up

What did work:

  • I could see that the openvpn.conf now is set to use tap
  • I can see that the bridge-start script is executed when spinning up the container in its startup (not using -d for detached mode)

But as soon as the bridge-start script is executed my machine loses the network connection. My interface (wlp1s0) loses its ipv4 and can not access the network anymore. At the same time I am unable to connect via SSH or OpenVPN at this point.

Any ideas?

I really appreciate your help.

Hi @Mailblocker,

Quick question: is your LAN you want to bridge with OpenVPN 192.168.2.0/24?

Anyway, it is clear that you have problems with bridging - this is in fact a complete separate problem from openvpn. Namely, you can run openvpn in tap mode without bridge but then unicast/multicast traffic won't propagate. On the other hand, you can set up a bridge outside of openvpn and test it.

Anyway, I try to help you with networking.

  • it is correct that after bringing up a bridge your eth interface does not have ipv4 address anymore. Now it is a part of bridge and the ip should be attached to br0 interface.
  • check your bridge with brctl show. Here is mine:
bash-5.0# brctl show
bridge name bridge id       STP enabled interfaces
docker0     8000.024274f6de62   no
br0     8000.b0d5cc1aa80c   no      eth0
                            tap0
bash-5.0# ifconfig
br0       Link encap:Ethernet  HWaddr B0:D5:CC:1A:A8:0C  
          inet addr:192.168.1.199  Bcast:192.168.1.255  Mask:255.255.255.0
          inet6 addr: fe80::861:44ff:fe0b:b2c8/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:91488 errors:0 dropped:1701 overruns:0 frame:0
          TX packets:84103 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000 
          RX bytes:9862348 (9.4 MiB)  TX bytes:15960545 (15.2 MiB)

eth0      Link encap:Ethernet  HWaddr B0:D5:CC:1A:A8:0C  
          inet6 addr: fe80::b2d5:ccff:fe1a:a80c/64 Scope:Link
          UP BROADCAST RUNNING PROMISC MULTICAST  MTU:1500  Metric:1
          RX packets:93672 errors:0 dropped:811 overruns:0 frame:0
          TX packets:87200 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000 
          RX bytes:12007595 (11.4 MiB)  TX bytes:16390066 (15.6 MiB)
          Interrupt:55 
...

Also, check your routing table. In my case I use the same physical interface for both openvpn and default gateway.

bash-5.0# route -n
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
0.0.0.0         192.168.1.1     0.0.0.0         UG    0      0        0 br0
169.254.0.0     0.0.0.0         255.255.0.0     U     0      0        0 tap0
172.17.0.0      0.0.0.0         255.255.0.0     U     0      0        0 docker0
192.168.1.0     0.0.0.0         255.255.255.0   U     0      0        0 br0

As you can see, there isn't even eth0 listed in the routing table, all traffic is routed through bridge and multicasted to tap0 (openvpn) and eth0 (physical).

All in all, if you still have a problem grab some networking book and read about ethernet bridging.

Also, I've noticed that you start and stop main openvpn container openvpn_tap many times, in pt. 7 and 13, 14. This shouldn't be necessary and changing routing tables can lock you out if you don't have a proper shutting down configuration, I.e. tearing down the bridge end removing taps from it.

@Mailblocker also do you have a firewall? Then you have to unblock br0 interface too.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

jkroepke picture jkroepke  路  7Comments

degritsenko picture degritsenko  路  3Comments

ebarault picture ebarault  路  4Comments

lucaszanella picture lucaszanella  路  7Comments

kevincaradant picture kevincaradant  路  5Comments