# VM-to-VM Integration


The VM-to-VM integration (also called a *peer* integration) lets one of your
VMs make HTTPS requests to another — an agent calling an API served by a
second VM, a staging box hitting a shared service, two agents talking to each
other — without either VM ever holding a credential.

Under the hood it's an [HTTP Proxy integration](integrations-http-proxy)
whose target is another VM you own, created with the `--peer` flag. Two
things make it more than a plain proxy:

- **Generated key, never on the VM.** exe.dev generates an API key scoped to
  the target VM, stores it server-side, and injects it at the network edge on
  every request. The source VM can *use* the integration but can never read
  the key — see [Where secrets live](integrations#where-secrets-live). The
  target VM's auth proxy consumes the key; your server never sees it either.
- **Caller identity on delivery.** Requests arrive at the target with an
  `X-Exedev-Source-Vm` header naming the calling VM. The platform *sets*
  (never appends) this header after stripping anything the source VM sent,
  so the caller cannot forge it. Use it to audit or route by caller.

## Setup from the UI

On the [Integrations page](/integrations), use the **HTTPS to another VM**
tile. Pick the target VM from the dropdown, optionally a port (the default
web port 8000 needs none), and attach it to the VMs that should be able to
call the target.

You can also type the target VM's name (or "vm-to-vm" or "peer") into the
[integration catalog](/integrations/catalog) search — matching one of your
own VMs offers this setup flow with that VM pre-selected as the target.

## Setup from the CLI

```
exe.dev ▶ integrations add http-proxy --name talk-to-bob --target https://bob.exe.xyz/ --peer --attach vm:alice
Added integration talk-to-bob (peer auth → bob)
```

The `--target` must be a VM you own (or have access to) on your exe.dev
domain. To reach a port other than 8000, put it in the target URL:
`https://bob.exe.xyz:3000/`.

The generated key shows up in `ssh-key list` with the label
`peer-<integration name>`; deleting the integration removes it.

## Example: two agents on two VMs

Say `bob` runs a small internal API on port 8000, and an agent on `alice`
needs to call it. Create the peer integration as above, then from `alice`:

```
exe.dev ▶ ssh alice curl -s http://talk-to-bob.int.exe.xyz/status
{"ok": true}
```

The request leaves `alice` with no credentials, picks up the generated key at
the edge, passes `bob`'s auth proxy, and arrives at bob's server on port 8000
looking like a normal request — plus the caller's name:

```
X-Exedev-Source-Vm: alice
```

Bob's server can use that header to decide what alice is allowed to do, tag
log lines by caller, or fan out behavior per peer. If several VMs attach the
same integration, they all reach `bob` through the same hostname and each is
identified by its own `X-Exedev-Source-Vm` value.

## Notes

- **Auth composes.** You can add `--header` or `--bearer` flags alongside
  `--peer`; those headers are forwarded to the target VM in addition to the
  automatic peer key (which travels in a reserved internal header the target
  never sees). `--no-auth` conflicts with `--peer` — peer auth is always
  injected.
- **Trust scope of `X-Exedev-Source-Vm`.** Traffic arriving through a peer
  integration carries a platform-stamped value the calling VM cannot spoof.
  But the header is informational on other paths: a human (or anything else
  you've [shared](cli-share) the target VM with) could set it on their own
  requests. If you make authorization decisions on it, keep the target VM
  unshared or verify the request came in over the integration.
- **Ownership.** The target must be a VM you can access; the generated key is
  scoped to exactly that VM (namespace `v0@<vm>.exe.xyz`) and is useless
  anywhere else.
- **Same mechanics as HTTP Proxy.** Attachment, `int.exe.xyz` hostnames,
  editing, and teams all work exactly as described in the
  [HTTP Proxy integration](integrations-http-proxy) docs.
