vpnkit lets a HyperKit VM coexist with the host's VPN
A toolkit for embedding VPN capabilities in your application
At a glance
- What is it?
- vpnkit is a Moby project that solves a specific conflict: running a VM usually means changing the host's routing table, DNS and firewall, and so does connecting a VPN, so the two fight and the VM loses its network. The answer is to intercept the VM's traffic at the Ethernet level and translate it into ordinary socket calls, and the result is a single binary that works on macOS and Windows.
- Who is it for?
- vpnkit suits someone running HyperKit on a laptop that is regularly on a corporate VPN, and it suits anyone who wants the HyperKit workflow without reconfiguring the host's network stack. It is the wrong tool for Linux guests using ordinary bridge networking, for a host that does not use a VPN at all, and for a team that has moved to Docker Desktop's own networking.
- Can I use it commercially?
- Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 2 days ago.
- What is it written in?
- Mainly OCaml, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.
Editorial analysis
A VM and a VPN both want to own the routing table
The why section of the README is the clearest statement of the problem, and it is worth reading because the name of the project does not explain it.
Running a VM usually involves modifying the network configuration on the host, for example by activating Ethernet bridges, adding new routing table entries, and changing DNS and firewall or NAT configurations. Activating a VPN involves modifying the same routing tables, DNS and firewall or NAT configurations. So there can be a clash, and the README says this often results in the network connection to the VM being disconnected.
That is the failure. A developer on a corporate VPN starts their VM and the VM has no network, or the VPN drops when the VM starts. The two features are individually reasonable and jointly broken, because they both believe they own the host's packet forwarding.
VPNKit, which the README describes as part of HyperKit, attempts to work nicely with VPN software by intercepting the VM traffic at the Ethernet level, parsing and understanding protocols such as NTP, DNS, UDP and TCP, and doing the right thing with respect to the host's VPN configuration.
The mechanism is stated in one sentence and it is the crux of the design. VPNKit operates by reconstructing Ethernet traffic from the VM and translating it into the relevant socket API calls on macOS or Windows. This allows the host application to generate traffic without requiring low-level Ethernet bridging support.
So the host does not bridge, it does not add routes, and it does not touch the firewall for VM traffic. It speaks the protocols the VM expects, over ordinary sockets, and the host's own VPN stack is left alone. The project description is a toolkit for embedding VPN capabilities in your application, and the target audience is whoever is embedding a VM runtime.
The build needs opam, and there are two ways to do it
Building on Unix, which includes macOS, starts with installing `wget`, `opam`, `pkg-config` and `dylibbundler` using the package manager of your choice.
For an existing opam user there are two routes, and the README is explicit that you can build against your existing opam package universe or against the custom universe contained in this repository.
The opam route is three commands.
make ocamlmake dependsmakeThe first creates the OCaml build environment, the second installs the OCaml dependencies, and the third builds. When the build succeeds the `vpnkit` binary should be available in `_build/install/default/bin/vpnkit`.
The Dune route is shorter because it fetches and installs the dependencies itself.
dune build --workspace=dune-workspace.ciwhich again leaves the binary in `_build/install/default/bin/vpnkit`, and the same workspace file lets you build and execute it in one step.
dune exec --workspace=dune-workspace.ci vpnkitThe two opam repositories are the thing to notice. The Makefile's `ocaml` target adds a repository called `archive-without-constraint`, hosted at the tarides organisation and pointed at a branch that removes a dune upper constraint, and the Dockerfile does the same. That is a workaround for a dependency resolution problem, pinned by URL and branch, and it tells you the build environment is not entirely self-contained.
On Windows the requirement is an OCaml environment with Cygwin, and the instructions are to unset `OPAMROOT` inside the `OCaml64` shell and run `make`. The note that although the Cygwin tools are needed for the build scripts, Cygwin itself will not be linked to the final executable is the kind of detail that saves a day when the executable fails to start.
Wiring it to HyperKit takes a socket and a NIC
The running instructions are short, and the whole integration is two command line arguments.
First you ask vpnkit to listen for ethernet connections on a local Unix domain socket.
vpnkit --ethernet /tmp/ethernet --debugThen you ask com.docker.hyperkit to connect a NIC to that socket by adding a command-line option like `-s 2:0,virtio-vpnkit,path=/tmp/ethernet`. The documentation notes that you may need to change the slot `2:0` to a free slot in your VM configuration.
That is the entire contract between the two programs. The `virtio-vpnkit` device type is what the guest kernel needs in order to present the interface, and the `path=` is the socket that vpnkit is listening on. The slot number is a slot in the VM's PCI configuration, so the practical first step for an existing VM is to find a free slot.
The design documentation in `docs/` describes three things. Using vpnkit as a default gateway describes the flow of ethernet traffic to and from the VM, and is the document to read first. Port forwarding describes how ports are forwarded from the host into the VM. And there is an experimental transparent HTTP proxy document describing the experimental support for transparent HTTP and HTTPS proxying.
That last one is worth flagging for a corporate environment. If the host is behind a proxy that the VM's traffic has to traverse, an experimental transparent proxy may be what makes the difference between a VM that can reach the internet and one that cannot, and experimental is exactly the word you want to weigh when you are deciding whether to depend on it.
A Go service, an OCaml core and a vendored tree
The repository is more than one language, and the layout says which part does what.
There is a `go/` directory with a `go.mod` for the module `github.com/moby/vpnkit` on Go 1.24, with a comment that the version should be kept in sync with the version of Go available in linuxkit and alpine. Its dependencies are the interesting part: `github.com/linuxkit/virtsock` for the virtual socket layer, `labstack/echo` for the HTTP server, `spf13/viper` for configuration, `sirupsen/logrus` for logging, `Microsoft/go-winio` for Windows named pipes, and the Kubernetes client libraries at 0.27.1. The Kubernetes client is there for the port forwarding and network policy surfaces, which is where a cluster-aware tool needs it.
The `src/` directory holds the OCaml code, with `c/` for the C stubs, and the top level has `dune`, `dune-project`, `dune-workspace`, a `dune-workspace.ci` and a `vendor/` directory. The `vpnkit.opam` file is the package definition, and the Makefile shows the opam switch is pinned to `ocaml-base-compiler.4.14.3`, with the Dockerfile building on `ocaml/opam:alpine-3.23-ocaml-4.14`.
The Docker build is a three stage image. The builder installs the opam universe, pins the local checkout as a path package and runs `opam install vpnkit`. A scratch stage copies out the single binary, and the final stage drops it into an alpine image, so the shipped artefact is one file.
Two make targets are for the people who maintain it rather than use it. `deps.csv` is generated by asking opam for the recursive dependency list with the license column, and `licenses.json` is produced from it by a script, which is how the project keeps track of the licences of everything it pulls in. The `test` target runs both the unit tests and the end to end tests through dune.
Where vpnkit is the wrong answer
The limitations here are all about scope, and they are worth being blunt about.
The first is that vpnkit exists to serve HyperKit. The README describes it as a set of tools and services for helping HyperKit VMs interoperate with host VPN configurations, and the integration depends on the guest having a `virtio-vpnkit` network device. A VM that boots with an ordinary virtio-net or a bridged interface does not need any of this, and a team on a modern Linux host running containers with Docker Desktop's networking is solving a problem that was solved years ago in a different way.
The second is the host platform. The socket API translation is described for macOS and Windows, and the project builds on Unix and on Cygwin for Windows. A Linux host is not the target, which is the reverse of where most container development now happens, and it means the tool is most useful on a developer laptop rather than in a server environment.
The third is the dependency on the host's VPN stack behaving. vpnkit avoids clashing with the VPN by understanding the protocols and deferring to the host's configuration, which is a much better answer than fighting over the routing table, but it is still an integration with software that is not under this project's control. When the corporate VPN adds a protocol vpnkit has not seen, the symptom is a VM with partial connectivity, and the documentation does not describe a protocol matrix or a compatibility list to check against.
The alternative approach, and the difference in approach is real, is to not run a VM at all, and to use a container runtime whose networking already coexists with the host's VPN, or a remote development environment that runs elsewhere. The trade is that you give up the ability to run an unmodified operating system with a full kernel, which is what HyperKit is for, in exchange for a setup that needs no special networking component. For a developer who needs the whole kernel, vpnkit is the answer. For a developer who only needs a build environment, it is a lot of machinery for the job.
Editorial conclusion
vpnkit suits someone running HyperKit on a laptop that is regularly on a corporate VPN, and it suits anyone who wants the HyperKit workflow without reconfiguring the host's network stack. It is the wrong tool for Linux guests using ordinary bridge networking, for a host that does not use a VPN at all, and for a team that has moved to Docker Desktop's own networking. Check first that your HyperKit version still supports the virtio-vpnkit device, since the whole integration depends on that NIC, and read `docs/ethernet.md` before you wire anything up, because the default gateway flow is where the configuration decisions live.
Frequently asked questions
What problem does vpnkit solve?
Running a VM usually means modifying the host network configuration, for example Ethernet bridges, routing table entries, DNS and firewall or NAT settings, and activating a VPN modifies the same things. The clash often results in the VM's network connection being disconnected, and vpnkit intercepts the VM traffic at the Ethernet level to avoid it.
How do I run vpnkit with HyperKit?
Start vpnkit with `vpnkit --ethernet /tmp/ethernet --debug` so it listens for ethernet connections on a local Unix domain socket, then add the option `-s 2:0,virtio-vpnkit,path=/tmp/ethernet` to hyperkit so a NIC connects to that socket. You may need to change the slot `2:0` to a free slot in your VM configuration.
How do I build vpnkit?
On Unix, install `wget`, `opam`, `pkg-config` and `dylibbundler`, then run `make ocaml` to set up the OCaml environment, `make depends` for the dependencies and `make` to build. The binary ends up in `_build/install/default/bin/vpnkit`. Alternatively, `dune build --workspace=dune-workspace.ci` fetches the dependencies itself, and `dune exec --workspace=dune-workspace.ci vpnkit` builds and runs it.
What is the transparent HTTP proxy in vpnkit?
The design documentation lists an experimental transparent HTTP proxy under `docs/transparent-http-proxy.md`, describing experimental support for transparent HTTP and HTTPS proxying. The other two design documents cover using vpnkit as a default gateway in `docs/ethernet.md` and port forwarding in `docs/ports.md`.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/moby-vpnkit)Was this useful?