An OpenVPN client that runs directly on Axis cameras as an ACAP application, entirely in userspace with no root and no kernel TUN device. It makes the camera reachable from your OpenVPN network and lets the camera route its own traffic out through the tunnel.
- No root required — runs as the standard unprivileged
sdkACAP user - Works on Axis OS 12 (and 11.x) — verified on Axis OS 12.10
- No kernel TUN / CAP_NET_ADMIN — the OpenVPN3 core terminates the tunnel in userspace and hands packets to an in-process gVisor netstack
Disclaimer: Independent, community-developed ACAP. Not affiliated with, endorsed by, or supported by Axis Communications AB or the OpenVPN project. Use at your own risk.
Three layers, the same pattern as the WireGuard and ZeroTier camera ACAPs:
- OpenVPN3 core (
lib/tun_probe, C++) connects to your server. Built withUSE_TUN_BUILDER, itstun_builder_establish()returns one end of aSOCK_DGRAMsocketpair instead of opening/dev/net/tun, so no privileges are needed. The encrypted transport is an ordinary UDP/TCP socket. - Userspace netstack (
lib/netstack_proxy, Go) attaches a gVisor netstack to that socketpair and runs the proxy layer:- Transparent TCP forwarders for camera ports 80 / 443 / 554
- Inbound SOCKS5 on
<vpn-ip>:1080(reach any camera port from the VPN) - Outbound HTTP CONNECT on
127.0.0.1:8080(camera → VPN/internet) - Outbound SOCKS5 on
127.0.0.1:1080
- C bridge (
OpenVPN) reads settings via axparameter, serves a small HTTP endpoint for uploading the.ovpnprofile (too large for the parameter store), launches the client, and restarts it on config changes with a watchdog.
Download the .eap for your camera's architecture and install via the camera
web interface under Apps → Add app.
| Architecture | File |
|---|---|
| aarch64 | OpenVPN_<version>_aarch64.eap |
| armv7hf | OpenVPN_<version>_armv7hf.eap |
Open the app's settings page and:
- Paste your
.ovpnprofile (inline certs supported) or pick a file. - Add Username/Password only if your profile is not autologin.
- Optionally change the outbound proxy ports (defaults 8080 / 1080) to avoid clashing with other VPN ACAPs.
- Save & Restart.
The status page shows the connection state, the assigned VPN IP, and the proxy addresses.
Once connected, from any machine on the OpenVPN network:
curl http://<vpn-ip>/ # camera web UI via the tunnel
curl -k https://<vpn-ip>/ # HTTPS
# RTSP: rtsp://<vpn-ip>:554/...
# Any other port: use the inbound SOCKS5 proxy at <vpn-ip>:1080Set the camera's System → Network → Global proxy (HTTP/HTTPS) to
http://127.0.0.1:8080, or point a SOCKS5-aware service at 127.0.0.1:1080.
Requires Docker or Podman.
./build.sh # aarch64 + armv7hf
ARCHES=aarch64 ./build.sh # single archThe build is two-staged: Dockerfile.openvpn3 cross-compiles the OpenVPN3 core
(cached base image), then Dockerfile builds the Go sidecar, the C bridge, and
packages the .eap.
Like the non-root WireGuard/ZeroTier builds, this is a userspace proxy data
plane: the camera is reachable from the VPN and can route out through it, but the
whole camera OS is not transparently placed on the VPN. Server-pushed DNS and
redirect-gateway apply to the netstack, not the camera's system resolver.
This project is licensed under the GNU Affero General Public License v3.0 (AGPL-3.0-or-later) — see LICENSE. AGPL is required because the app bundles the OpenVPN3 core, which is AGPL-3.0-or-later.
Third-party components and their licenses are listed in THIRD_PARTY_NOTICES.md.