Introduction

OpenVPN is one of the most popular VPN systems. It runs smoothly on Windows, Linux, and macOS. But sometimes you would like to have the option to access some service (like an HTTP server or SSH), but you don’t want to install new software on your machine. Docker comes to the rescue 🐳

Access service behind VPN

Scenario: Service behind VPN

In this simple scenario, I would like to access a server (SSH, web, or anything else) located in a private network. I’ve prepared a simple Docker file to install supervisor, openvpn and socat. I am also copying the prepared supervisor config files:

FROM ubuntu:20.04
EXPOSE 10022
RUN apt update && apt install -y supervisor openvpn socat && \
    apt clean
COPY *.conf /etc/supervisor/conf.d/
ENTRYPOINT ["/usr/bin/supervisord", "-c", "/etc/supervisor/conf.d/supervisord.conf"]

Config files

To run the OpenVPN client with supervisor and socat, we have to prepare config files for all of those services first. All those files should be copied to the /etc/supervisor/conf.d/ directory inside the Docker image.

supervisor config

[supervisord]
nodaemon=true
logfile=/var/log/supervisor/supervisord.log
pidfile=/var/run/supervisord.pid
[include]
files = /etc/supervisor/conf.d/*.conf

I am running supervisord as a daemon, configuring the logfile, pid file, and including config files.

openvpn

[program:openvpn]
command = openvpn --config /vpnconfig.ovpn
redirect_stderr = true
redirect_stdout = true
autostart = true

I want to redirect messages and errors from the service (OpenVPN, in this case) back to the supervisor stdout descriptor. In that case, I should have all logs from this service visible in the Docker logs or in a specified file (in my case).

I am also defining the command that should be used to run OpenVPN, and I am pointing to the vpnconfig file (the one that contains things like certificates and VPN server address).

socat

[program:socat_10022]
command = socat tcp-listen:10022,reuseaddr,fork tcp:10.14.11.20:22
redirect_stderr = true
redirect_stdout = true
autostart = true

Similar to the OpenVPN config file, I am configuring socat to listen on port 10022 and forward traffic to the 10.14.11.20 SSH service (port 22).

Building docker image

echo "vpnconfig.ovpn" >> .dockerignore

Just in case, to prevent putting confidential file into docker image.

docker build . -t docker-vpn

Just regular building docker image. Make sure that you put all config files mentioned earlier in the directory with Dockerfile.

How to use it?

docker run --rm -v ${PWD}/vpnconfig.ovpn:/vpnconfig.ovpn -p 10022:10022 --cap-add=NET_ADMIN --cap-add=SYS_MODULE --device /dev/net/tun docker-vpn

--cap-add=NET_ADMIN - is used for interaction with network stack without using privileged docker container --cap-add=SYS_MODULE - simillar for SYS_MODULE --device /dev/net/tun - I am adding device to the docker

I am exposing 10022 port from Docker container and putting vpnconfig.ovpn file in place required by openvpn client installed inside of the docker image.

When container starts, you can access 10.14.11.20 server using command:

ssh user@localhost -p 10022

Simillar config you can prepare for http, database or any other service.

In next post, I will show you how you can use makefile to automate connectivity.

Additional reading