Docs · Reference

SSH

Reaching a guest over SSH from the Mac — which address actually works, the one line added to your ssh config, keys, accounts and host-key trust.

SSH is off on every machine until you turn it on. Enabling it opens a login path into the guest, and that is not something anyone should acquire by accident.

1vm ssh enable dev
1vm ssh config --install     # add the Include line to ~/.ssh/config
ssh dev                      # plain ssh now resolves the machine

There is also a Configure → SSH pane in the app with the same controls; neither front end wraps the other.

Which address actually works

This is the part that trips people up, and it depends on the engine. The guest address you see in 1vm list is not always something you can connect to.

EngineNetworkMac → guest
Virtualization.frameworkNAT or host-onlyDirect, to the guest's 192.168.64.x lease
Virtualization.frameworkBridgedDirect, to its LAN address
1VM engineNAT or host-onlyThrough a loopback port forward only
1VM engineBridgedDirect, to its LAN address

On the 1VM engine the guest sits behind a user-mode network stack at a constant 10.0.2.15, and your Mac has no interface on that subnet. ssh 10.0.2.15 can never work there. What works is the forward:

ssh -p 2222 onevm@127.0.0.1

Turning SSH on creates that forward for you, and it applies live — no reboot. Forwards bind 127.0.0.1, so enabling SSH never exposes a guest to your network.

The one line added to your ssh config

1vm ssh config --install adds exactly one sentinel-delimited block, at the top of ~/.ssh/config:

# >>> 1VM managed >>> do not edit this block
Include ~/Library/Application Support/OneVM/VMs/.ssh/config
# <<< 1VM managed <<<

Everything else is generated into the library's own .ssh/ directory, so your file keeps one line and 1VM owns the rest. ONEVM_HOME moves the whole thing, which means a project-local library carries its own SSH config.

The rules this follows, because it is editing a file it does not own:

  • Top of the file, because ssh_config is first-obtained-wins — an Include placed after an existing Host * block would silently lose.
  • Idempotent. Running it ten times leaves one block.
  • Atomic, with a backup. The original is copied to a timestamped config.1vm-backup-… before anything is written.
  • Reversible. --uninstall removes exactly the sentinel block and nothing else. --print shows it without writing.
  • It refuses rather than reorders. If your config already sets options for all hosts above where the block would go, 1VM tells you and declines instead of rearranging your file.
  • It will not shadow a real host. If the machine name already resolves to something in your ssh config, only the <name>.1vm alias is emitted.

A generated block looks like this — the port and address come from the reachability rules above, never from the raw guest IP:

Host dev dev.1vm
    HostName 127.0.0.1
    Port 22417
    User dev
    IdentityFile ".../dev.vm/agent-key"
    IdentitiesOnly yes
    AddressFamily inet
    StrictHostKeyChecking yes
    ConnectTimeout 5

Keys

Each machine has its own Ed25519 key inside its bundle at agent-key, mode 0600. Because it lives in the folder, 1vm clone carries it along and the clone is reachable with the same identity.

You can use your own key instead. 1VM stores the path to it and copies only the matching .pub into the guest — it never reads, copies or stores your private half.

1vm ssh keys dev                    # show the machine key
1vm ssh keys dev --print-public     # the public line
1vm ssh keys dev --regenerate       # new keypair
1vm set dev ssh.identityFile ~/.ssh/id_ed25519

Accounts

1vm set dev ssh.users … manages which accounts exist in the guest. Names are validated per guest family — Linux and macOS take [a-z_][a-z0-9_-]{0,31}, Windows is capped at 20 characters and rejects the reserved punctuation — and admin membership maps to wheel/sudo, Administrators, or admin respectively.

onevm is reserved. It is the account 1vm exec, 1vm task run and the MCP server log in as, so renaming or deleting it would break them. The pane shows it as a locked row labelled as the agent account rather than hiding it — a login that exists but is invisible in the list of logins would be a lie.

root and Administrator are reserved too, and root login stays off.

Host-key trust

Most tools trust whatever answers on first connection. 1VM does better, because it has an out-of-band channel: it reads the guest's public host key over the guest-agent channel, which does not traverse the network being authenticated, and pins it.

StateWhat you seeWhat ssh does
Not learned yet"the first connection will trust whatever answers"StrictHostKeyChecking accept-new
Learnedthe SHA256:… fingerprint and the dateStrictHostKeyChecking yes
Mismatcha warning naming the date the old key was pinned, and a Relearn buttonyes — so the connection correctly fails
1vm ssh trust dev              # pin the current host key
1vm ssh trust dev --relearn    # re-pin after a legitimate change

A mismatch is normal after 1vm reset, after restoring a snapshot taken before sshd existed, or after a reinstall. It is also exactly what an attack looks like — so it is always a button you press, never a silent overwrite.

Cloning. The identity key is copied to a clone deliberately; the host-key pin is not, because two machines presenting one host key is a real problem. Use 1vm clone dev test --rekey-ssh to regenerate the guest's host keys on first boot.

Security defaults

  • Key-only authentication. Password and keyboard-interactive auth are off, root login is off, and there is no agent or X11 forwarding.
  • Forwards bind loopback, so a guest is never exposed to your LAN by enabling SSH. Binding a public address is possible but warns you in plain words about what it means.
  • Private key material and account-creation arguments travel the private channel only and never reach a log.

Rollback mode wipes SSH accounts

Rollback mode discards everything written since boot at power-off — which includes accounts and keys provisioned into the guest. This is not a bug, and 1VM handles it by re-running provisioning on every boot rather than trusting a marker file. Expect the guest's host key to change each time, too.

Guest to Mac

The reverse direction — SSH from the guest to your Mac — reaches the Mac at 10.0.2.2 on the 1VM engine, and only for ports with a registered service. 1VM will not enable macOS Remote Login for you; that stays your decision in System Settings.

Current state

SSH is implemented across the app, the CLI and both engines, and covered by the unit test suite. Two honest caveats:

  • Live-guest soak testing is still the outstanding acceptance gate.
  • The shipped Omarchy factory image predates openssh being added to its package list, so a factory Omarchy guest has no sshd until that image is rebuilt. Other Linux guests are unaffected.