MacVisor

Networking

NAT, bridged and custom networks, reaching VMs by name, and port forwarding.

Each VM has one network interface and can have up to three more. Every interface keeps a stable MAC address and connects in one of three modes.

Network modes

ModeUse it for
NATInternet access through the Mac, nothing else
BridgedThe VM joins a physical network as its own device
Custom networkA named shared or host-only segment with DHCP, DNS, reservations, port forwards and a firewall

See Custom networks and Network firewall for the third mode.

How NAT, bridged, and named host-only/shared networks connect VMs and the Mac.

mvz create ubuntu dev --network nat
mvz set dev --network nat|bridged:<interface>|<network>    # applies at the next start

The Default MacVisor Network

VMs made from cloud images join a shared custom network called Default MacVisor Network. They can reach each other and, through the Mac, the internet.

It is also the fallback. If a new, cloned, imported or template-made VM names a network or bridged interface this Mac doesn't have, MacVisor puts it on the Default MacVisor Network and notes it in the service log.

Names

Reach VMs by name rather than by IP address. A name keeps working when the address changes.

  • <vm>.mvz resolves on the Mac to the VM's current address: ping dev.mvz, curl http://dev.mvz:8080. The longer <vm>.macvisor also works. The name part is the VM's name in lowercase letters, digits and hyphens, so "Dev VM" is dev-vm.mvz. A name with none of those, such as one in Japanese, becomes vm- and the VM's short id: vm-1a2b3c4d.mvz. Every VM also answers to its short id, 1a2b3c4d.mvz.

  • host.mvz.internal (or host.macvisor.internal) is the Mac, from inside a Linux, FreeBSD or Windows VM with the MacVisor Agent, as host.docker.internal is in Docker. MacVisor tells the agent the Mac's own address on the guest's network:

    • on NAT, shared and host-only networks, the Mac's side of the network;
    • on a bridged adapter, the Mac's address on that LAN, once the guest has checked it can reach the Mac there (Wi-Fi bridging may not pass that traffic).

    Where the Mac has no address on the guest's network, such as a subnet behind an appliance VM, the name isn't set. It is never the LAN's router. An agent run by MacVisor 27.2.0 or earlier keeps the old rule, the guest's default gateway. macOS guests don't have the name.

Run mvz ssh-config --install once and ssh dev.mvz works, as does VS Code Remote-SSH, with the VM's host key pinned.

Names resolve only to an address a VM can actually have: one on the Mac's VM networks or, for a bridged VM, on a network the Mac is also on. A bridged VM on a network where the Mac has no address does not resolve.

Bridging

Choose a physical interface when the VM must be on your LAN. Your network's DHCP, switches and firewalls treat it like any other device.

For tagged segments, create an 802.1Q interface with Networks → New VLAN Interface…. A VM can bridge to it directly, or a shared custom network can use it as its uplink. See VLAN interfaces.

MacVisor creates a tagged VLAN interface on a selected physical parent, then makes it available for direct VM bridging or as a shared-network uplink.

Reaching a VM from other devices

The Default MacVisor Network, NAT and every shared or host-only network are reachable only from this Mac. To reach a VM from other devices:

  • Bridge it to a physical interface, or to a VLAN interface, so it is a device on your LAN. See Bridging.
  • Forward a port on a custom network: other devices on the Mac's networks, as well as the Mac, reach a network forward. Its rules can name a VM on the network.

A VM's own port forwards, below, are for this Mac only.

Port forwarding

A VM's port forwards listen on this Mac only: on 127.0.0.1, and also on ::1 so that localhost reaches the VM too (macOS tries ::1 first). MacVisor's guest agent carries each connection over the VM's virtual socket, not its network, to the guest's localhost. So:

  • only this Mac can use them;
  • the network's firewall doesn't apply to them;
  • a service the guest keeps to its own loopback is reached too.

VMs made from a cloud image forward ports automatically. Any TCP or UDP port the guest listens on appears on the Mac's 127.0.0.1 at the same number, for as long as the guest listens. To turn this off for a VM, switch off Forward guest ports automatically in VM Settings → Cloud-Init, or create the VM with --no-forward. Forwards you add by hand keep working either way. VMs without cloud-init get no automatic forwards.

For a fixed endpoint, a port automatic forwarding skips, or any other VM with guest tools, add a forward yourself under Host Port Forwarding in VM Settings → Network, or:

mvz ports add <vm> --host-port 2222 --guest-port 22 --name SSH
mvz ports add <vm> --host-port 5353 --guest-port 53 --udp
mvz ports list <vm>
mvz ports remove <vm> <forward-id|host-port>

--host ::1 listens on ::1 alone. Any other address is refused, with the ways to reach the VM from other devices. If another app already listens on that port, the forward can't start, and the VM's runner log says so. A forward you add by hand replaces the automatic one for that port.

What automatic forwarding leaves out

Automatic forwards don't ask first, and this list is their whole trust model. Any process in the guest can take a free port on the Mac's loopback, and a Mac tool that connects to that port before its own service has started talks to the guest. So MacVisor keeps automatic forwards away from the ports the Mac's own software expects. If that isn't enough for a VM, turn automatic forwarding off for it and forward what you need by hand.

  • Forwarded: services bound to 127.0.0.1, ::1, 0.0.0.0 or :: in the guest. A dev server bound to the guest's loopback is forwarded as is. A service bound to one specific guest address is not.
  • Skipped: TCP 22 (use mvz shell), ports below 1024 except 80 and 443, UDP ports from 32768 up, k3s ports other than the API server on 6443, and guest plumbing such as the kubelet (10250), containerd streaming, DHCP, NTP, mDNS, LLMNR, SSDP and VXLAN or WireGuard backends.
  • Held, with the reason shown in the VM's Overview and in mvz show <vm>: SQL Server (1433), Oracle (1521), Docker (2375, 2376), etcd (2379), Apple Remote Desktop (3283), MySQL (3306), PostgreSQL (5432), Screen Sharing (5900), Redis (6379), Vault (8200), Consul (8500), memcached (11211), Ollama (11434), MongoDB (27017), AirPlay Receiver (5000, 7000), and Cockpit (9090) on RHEL-family images.
  • Busy on the Mac: a port something on the Mac already uses can't be forwarded. mvz show <vm> says "the port is already in use on this Mac".
  • More than 512 ports: MacVisor forwards at most 512 of a VM's ports automatically. Any more are listed in the VM's Overview as not forwarded, with the reason.

To use a held port, forward it by hand in VM Settings → Network or with mvz ports add.

Per-VM and network forwards

Per-VM forwardNetwork forward
Set inVM Settings, mvz portsThe custom network's Port Forwarding tab (app only)
Reachable fromThis Mac onlyThis Mac and other devices on the Mac's networks
Goes throughThe guest agent, to the guest's localhostThe network, to an address on the segment
Needs guest toolsYesNo
ProtocolsTCP and UDPTCP and UDP
Change while runningYes, immediatelyIn force when the network is made again: once no VM uses it, or at once with Apply Now
TargetThe VM itselfA VM on the network (its reserved address), or any address on the segment

Docker and Kubernetes

A Docker or Podman VM's API is forwarded to ~/.macvisor/run/<id>.docker.sock while it runs. mvz docker <vm> makes a matching docker context. A k3s VM's API server is forwarded to 127.0.0.1:6443 (mvz kubeconfig <vm>). Every k3s kubeconfig points at that one address, so run one k3s VM at a time.

Guest addresses

With guest tools connected, MacVisor shows each guest interface and its addresses.

mvz ip <vm>
mvz ip <vm> --wait        # wait for an IPv4 address and print only that

A VM without guest tools still gets its IPv4 address shown, in the sidebar, the Overview, mvz ip and <vm>.mvz: MacVisor's network helper reads the Mac's ARP table for the VM's own MAC addresses, and MacVisor falls back to the DHCP lease and the VM's address reservation. Without an agent, what MacVisor finds depends on the network mode and can be incomplete. For the best results, especially with static addresses, install the MacVisor Agent or a QEMU guest agent.