Alpine OpenVPN client with NAT masquerading — use it as a VPN gateway for your LAN.
67
A small Alpine-based OpenVPN client image. It connects the container to an OpenVPN server using an
.ovpn profile and a credentials file, and it also enables NAT masquerading on the tunnel interface,
so the container can act as a VPN gateway for other hosts on your LAN — not just for itself.
/config directory.iptables NAT masquerading for outbound tun0 traffic, so forwarded packets are rewritten
to the VPN-assigned source address.tcpdump and iptables for packet-level troubleshooting inside the container.tini as PID 1, so signals and restarts behave correctly.--auth-nocache and are not retained in memory after authentication.yusiwen/openvpn-cli:2.5.8 (platform linux/amd64)ccmpbll/openvpn-client (Alpine +
OpenVPN + bash, curl, jq, tini, speedtest-cli), with tcpdump and iptables added and a
custom entrypoint that installs the NAT rule before starting openvpn.2.5.8 tag records the OpenVPN version the image was built against.docker pull yusiwen/openvpn-cli:2.5.8
Prepare a directory with two files:
config/
├── client.ovpn # OpenVPN client profile
└── auth.txt # username and password, one per line
auth.txt must contain exactly two lines:
myCoolUsername
mySuperSecretPassword
Start the container:
docker run -d --name openvpn_client \
--restart unless-stopped \
--cap-add=NET_ADMIN \
--cap-add=NET_RAW \
--device /dev/net/tun \
-v /path/to/config:/config:rw \
-e OPENVPN_CONF=client.ovpn \
-e OPENVPN_AUTH=auth.txt \
yusiwen/openvpn-cli:2.5.8
Follow the connection log:
docker logs -f openvpn_client
| Variable | Default | Description |
|---|---|---|
OPENVPN_CONF | NONE | Name of the .ovpn profile inside /config. The container exits if the file is missing. |
OPENVPN_AUTH | NONE | Name of the credentials file inside /config. The container exits if the file is missing. |
OPENVPN_OPTS | empty | Extra arguments appended to the openvpn command line, e.g. --verb 4. |
CONFIG_PATH | /config | Directory the profile and auth file are read from. |
Because the tunnel is on tun0 and outbound traffic is masqueraded, other machines can route through
the container. A common setup is a macvlan network that gives the container a real address on the
physical segment:
services:
vpn:
image: yusiwen/openvpn-cli:2.5.8
container_name: openvpn_client
restart: unless-stopped
privileged: true
devices:
- /dev/net/tun:/dev/net/tun
volumes:
- ./config:/config:rw
environment:
- OPENVPN_CONF=client.ovpn
- OPENVPN_AUTH=auth.txt
sysctls:
- net.ipv4.ip_forward=1
networks:
macvlan:
ipv4_address: "192.168.1.50"
networks:
macvlan:
name: macvlan
driver: macvlan
driver_opts:
parent: eth0
ipam:
config:
- subnet: "192.168.1.0/24"
ip_range: "192.168.1.0/25"
gateway: "192.168.1.1"
Then set the default gateway of the client machines to the container address (192.168.1.50 in the
example).
Notes:
net.ipv4.ip_forward=1 is required for forwarding; the masquerade rule alone is not enough.macvlan container address directly — test from another host
on the LAN.--cap-add=NET_ADMIN --cap-add=NET_RAW and /dev/net/tun are sufficient; use
privileged: true when you also want the container to route and rewrite traffic on behalf of others.OPENVPN_CONF / OPENVPN_AUTH must match
the real file names in /config.docker exec openvpn_client sysctl net.ipv4.ip_forward and docker exec openvpn_client ip route.docker exec openvpn_client tcpdump -ni tun0.docker exec openvpn_client iptables -t nat -L POSTROUTING -n -v./dev/net/tun, and elevated network capabilities for iptables. It can rewrite
firewall state; run it only on hosts you control.chmod 600) and keep it out
of version control and out of images.macvlan address exposes the tunnel to the whole LAN segment. If that is not intended, keep the
container on a private bridge network instead.Content type
Image
Digest
sha256:31e56f50d…
Size
24.3 MB
Last updated
10 days ago
docker pull yusiwen/openvpn-cli:2.5.8