Using openvpn-client
with Docker
I recently worked out the correct incantation to get a set of containers to connect to the internet via a VPN using docker-compose
. I run it on a QNAP NAS, but it should work on any Linux-like system (I couldn’t get it working on MacOS).
The following docker-compose.yml
will create two containers - one to run the VPN client and a second that runs curl
. I use this to run curl ipv4.canhazip.com
to check that the container has connectivity and the VPN IP address is returned.
yaml
---version: "3"services:vpn:container_name: vpnimage: dperson/openvpn-client:latestcap_add:- net_adminrestart: unless-stoppedvolumes:- /dev/net/tun:/dev/net/tun- ./vpn-config:/vpn # You'll need to provide thissecurity_opt:- label:disableports:- 8001:8001- 8002:8002- 8003:8003networks:- bridge_vpnentrypoint: ["/sbin/tini", "--", "/usr/bin/openvpn.sh", "-d"]curl:image: alpine/curlcontainer_name: curlrestart: unless-stoppednetwork_mode: service:vpnnetworks:bridge_vpn:
This compose file will expose ports 8001
, 8002
and 8003
from any containers using network_mode: service:vpn
and make them accessible via a bridge network. This is useful when running a service that connects to the internet using a VPN. (There are no exposed ports in this demo, but I wanted to make a note here as in my actual deployment some of the other services expose ports.)
The biggest change to this configuration compared to a lot of guides out there is the entrypoint
line for the vpn
service. The openvpn-client
image supports a -d
flag that adds some DNS related pre/post scripts. I found that these are required to make connectivity work via the VPN.
You may have noticed the vpn-config
folder being mounted. This is where you’ll provide your VPN configuration and authentication files. I tested this with Private Internet Access. If you’re a PIA customer, you’ll need to create a file named vpn.auth
with your PIA username on the first line, and password on the second line, plus a vpn.conf
file with the following contents:
apache
clientdev tunproto udpremote sweden.privacy.network 1198resolv-retry infinitenobindpersist-key# persist-tun # disable to completely reset vpn connection on failurecipher aes-128-cbcauth sha1tls-clientremote-cert-tls serverauth-user-pass /vpn/vpn.auth # to be reachable inside the containercomp-lzoverb 1reneg-sec 0crl-verify /vpn/crl.rsa.2048.pem # to be reachable inside the containerca /vpn/ca.rsa.2048.crt # to be reachable inside the containerdisable-occkeepalive 10 30 # send a ping every 10 sec and reconnect after 30 sec of unsuccessfull pingspull-filter ignore "auth-token" # fix PIA reconnection auth error that may occur every 8 hours
This configuration connects to Sweden, but you can switch to any endpoint that you like. You’ll also need to download crl.rsa.2048.pem
and ca.rsa.2048.pem
from the PIA site.
Once you have everything configured, it’s time to create the containers by running docker-compose up -d
. Once that’s complete, you can test your connection by logging in to the vpn
service and making a HTTP call:
bash
docker-compose exec vpn bash -c "curl ipv4.canhazip.com"
If the above command returns an IP address successfully, you can also test it using the curl
container which is configured to use the VPN for all network connectivity:
bash
docker-compose run curl ipv4.canhazip.com
At this point, you have a docker-compose
setup that connects all of the containers configured via an OpenVPN connection. Replace the curl
service with any other service you may want to run behind a VPN and enjoy as your traffic is safe from snooping eyes.