OpenConnect doesn't ship with any init scripts or systemd units. It's also not easy to non-interactively provide username, password and especially OTP. Additionally, running in a docker container gives some extra flexibility with routing.
The image is built by GitHub Actions for amd64 & arm64 and pushed to the following repositories:
There is additionally a build running in GitLab CI published to:
It's recommended to use the helper scripts as described below.
Otherwise, you can run the container using the specified arguments below.
docker run -d \
--cap-add NET_ADMIN \
-e URL=https://my.vpn.com \
-e USER=myuser \
-e AUTH_GROUP=mygroup \
-e PASS=mypassword \
-e OTP=123456 \
-e SEARCH_DOMAINS="my.corporate-domain.com subdomain.my.corporate-domain.com" \
docker.io/aw1cks/openconnect'
Variable | Explanation | Example Value |
---|---|---|
URL |
URL of AnyConnect VPN | https://my.vpn.com |
USER |
User to authenticate with | myuser |
AUTH_GROUP |
Authentication Group to use when connecting to VPN (optional) | mygroup |
PASS |
Password to authenticate with | mypassword |
OTP |
OTP/2FA code (optional) | 123456 |
SEARCH_DOMAINS |
Search domains to use. DNS for these domains will be routed via the VPN's DNS servers (optional). Separate with a space for multiple domains | my.corporate-domain.com subdomain.my.corporate-domain.com |
EXTRA_ARGS |
Any additional arguments to be passed to the OpenConnect client (optional). Only use this if you need something specific | --verbose |
The provided helper scripts in examples/
will create the container for you and set up the routing table appropriately.
docker
sudo
(and permissions to runip
anddocker
as root)iproute2
jq
- The
env
file is sourced from the same directory the script lives in - From the above file, all the container arguments are derived. These are passed using
-e
as environment variables to the container. - The container is spawned, then the address of the container is found using
docker inspect
piped tojq
. - The routes specified in the
env
file are added to the host routing table, via the container address discovered in the previous step. - The host resolv.conf is backed up to
/etc/resolv.conf.orig
, then modified to point to the local container on127.0.0.1
.
The script which stops the VPN cleans up the routing table, tears down the container, and restores the original resolv.conf
.
$ cd $(git rev-parse --show-cdup)
$ cp examples/* .
$ $EDITOR env # set your values here
$ ./run.sh
$ ./stop.sh # Tears down the container and cleans up the routing table
The following build args are used:
BUILD_DATE
(RFC3339 timestamp)COMMIT_SHA
(commit hash from which image was built)
docker build \
--build-arg BUILD_DATE="$(date -u +'%Y-%m-%dT%H:%M:%SZ')" \
--build-arg COMMIT_SHA="$(git rev-parse HEAD 2>/dev/null || echo 'null')" \
-t openconnect .
When running not in privileged mode, OpenConnect gives errors such as this:
Cannot open "/proc/sys/net/ipv4/route/flush"
This is normal and does not impact the operation of the VPN.
To suppress these errors, run with --privileged
.