Back

How we solved host VPN conflicts by running OpenVPN inside Docker containers

Captain's log, stardate d642.y41/AB

Docker hosting Coding Lessons Learnt
Juan Salvador
Engineering Manager
How we solved host VPN conflicts by running OpenVPN inside Docker containers

When your development workflow depends on OpenVPN but your host machine is forced to run a corporate VPN, things can get complicated fast. Host-level VPN software often takes over routing rules, intercepts private networks, and breaks access to remote development services, even when your OpenVPN configuration is correct.

Our team faced this exact issue. Instead of fighting with the host VPN client, we chose a better alternative: we moved the OpenVPN connection inside our Docker development containers.

This article explains the problem, the reasoning, and the complete solution, step by step.

Why host-level VPNs break Docker-based development

Modern corporate VPN clients often enforce strict security policies. They often:

Our development environment relied on OpenVPN to reach remote services. The OpenVPN client could still “connect”, but the host VPN silently hijacked traffic and routed it through its own tunnel instead. OpenVPN showed as connected, but the dev environment was unreachable.

The solution: run OpenVPN inside Docker, not on the host

Here’s the key insight: Docker containers run in their own network namespaces. That means host VPN routing rules don’t affect container routing.

By moving OpenVPN into the container:

This technique cleanly separates host networking (corporate VPN) from development networking (OpenVPN inside Docker), creating a stable and conflict-free environment.

How we built container-level OpenVPN support

1. Install OpenVPN inside the development image

First, ensure the package is available in your Dockerfile:

    RUN apt-get install -yqq ... openvpn
    RUN mkdir -p /opt/openvpn && chown -R user:user /opt/openvpn

2. Give the container NET_ADMIN capabilities

OpenVPN needs privileges to create tun devices. In your docker-compose.yml:

    privileged: true
    cap_add:
        - NET_ADMIN

3. Mount .ovpn config files into the container

Developers store VPN files
under .dockerdev/ovpn/:

    volumes:
        - ./ovpn:/opt/openvpn

Make sure these files are ignored by Git.

    *.ovpn

4. Add an entrypoint script that auto-starts OpenVPN

    OPEN_VPN_CONFIG=/opt/openvpn/$CUSTOMER_NETWORK.ovpn

    if [ -f "$OPEN_VPN_CONFIG" ]; then
        echo "Connecting with VPN"
        sudo openvpn --daemon --log-append /var/log/openvpn/openvpn.log --config $OPEN_VPN_CONFIG
    fi

    exec "$@"

The container checks the selected network and launches OpenVPN automatically.

5. Select the VPN profile using an environment variable

    CUSTOMER_NETWORK: dev-eu-west-3

The value must match an existing .ovpn file:

    dev-eu-west-3.ovpn

Developer setup: step-by-step

Once the infrastructure is in place, the developer workflow is simple:

Rebuild the containers:

    bin/dockerdev setup

Add your .ovpn files:

    Place them in .dockerdev/ovpn/dev-eu-west-3.ovpn

Copy the override template:

    cd .dockerdev
    cp compose.override.yml.sample compose.override.yml

Edit as needed setting the CUSTOMER_NETWORK environment variable to the right VPN name.

Start development services: bin/dockerdev start server

    bin/dockerdev start server

If an OpenVPN profile exists, the VPN starts inside the container automatically.

Why this approach works so well

Running OpenVPN inside Docker gives you:

✅ No more routing conflicts.

✅ Clean separation between host and development networks.

✅ Predictable and isolated development routing.

✅ Zero host OS changes.

✅ Faster onboarding for developers.

✅ A fully reproducible environment.

✅ Reliable access to cloud services behind OpenVPN.

This architecture dramatically improved our development workflow, and it’s a pattern any remote-friendly or cloud-based team can benefit from.

Share this post

Related articles

How I use Docker for Rails development: running services

How I use Docker for Rails development: running services

Project setup can be a very cumbersome process for developers. In this blog post, our developer Dani explains how he uses Docker to develop in Rails

Read full article
Rust for NodeJS developers (III) - Docker development environment

Rust for NodeJS developers (III) - Docker development environment

Docker can be beneficial not just for deploying applications but also for local development. By creating a Docker environment for our Rust API, we can ensure a consistent and isolated development experience across different machines and team members.

Read full article
Rust for NodeJS developers (IV) - SQLx CLI

Rust for NodeJS developers (IV) - SQLx CLI

In this article, we'll explore SQLx - a robust database toolkit for Rust.

Read full article