> ## Documentation Index
> Fetch the complete documentation index at: https://docs.mirage.strukto.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# SSH

> Mount a remote filesystem over SSH/SFTP.

The SSH VFS mounts a remote server's filesystem over SFTP.
It supports full read and write operations.

## Config

```python theme={null}
from mirage import MountMode, Workspace
from mirage.vfs.ssh import SSHConfig, SSHVFS

config = SSHConfig(
    host="myserver",
    username="deploy",
    identity_file="~/.ssh/id_ed25519",
    root="/var/data",
)
vfs = SSHVFS(config=config)
ws = Workspace({"/remote": vfs}, mode=MountMode.WRITE)
```

| Field | Required | Default | Description |
| - | - | - | - |
| `host` | yes | | SSH host (name or IP) |
| `hostname` | no | | Override resolved hostname |
| `port` | no | `22` | SSH port |
| `username` | no | | SSH username |
| `identity_file` | no | | Path to private key |
| `password` | no | | Password authentication; redacted in snapshots |
| `passphrase` | no | | Passphrase of an encrypted `identity_file`; redacted in snapshots |
| `root` | no | `/` | Remote directory to mount |
| `timeout` | no | `30` | Connection timeout in seconds |
| `known_hosts` | no | | Path to known\_hosts file |

The `host` field matches entries in `~/.ssh/config`, so existing SSH
configurations are automatically picked up.

## Filesystem Layout

```text theme={null}
/remote/
  <remote-directory-tree>
```

The mounted tree mirrors the remote filesystem starting at `root`.

Example with `root="/var/data"`:

```text theme={null}
/remote/
  logs/
    app.log
    nginx/
      access.log
      error.log
  config/
    app.yaml
  uploads/
    image.png
```

## Cache

Uses `IndexCacheStore` for directory listings. Freshness is checked
via `{mtime}:{size}` fingerprints - files are re-fetched only when
the remote has changed.

## Example

```python theme={null}
import asyncio

from mirage import MountMode, Workspace
from mirage.vfs.ssh import SSHConfig, SSHVFS

config = SSHConfig(
    host="myserver",
    username="deploy",
    identity_file="~/.ssh/id_ed25519",
    root="/var/log",
)
vfs = SSHVFS(config=config)


async def main():
    ws = Workspace({"/logs": vfs}, mode=MountMode.READ)

    # List remote directory
    r = await ws.shell("ls /logs/")
    print(await r.stdout_str())

    # Read last 20 lines of a log
    r = await ws.shell("tail -n 20 /logs/nginx/access.log")
    print(await r.stdout_str())

    # Search across log files
    r = await ws.shell('grep "ERROR" /logs/app.log')
    print(await r.stdout_str())

    # Find large files
    r = await ws.shell("find /logs/ -name '*.log'")
    print(await r.stdout_str())

    # File metadata
    r = await ws.shell("stat /logs/app.log")
    print(await r.stdout_str())


if __name__ == "__main__":
    asyncio.run(main())
```

## Shell Commands

| Command | Notes |
| - | - |
| `ls` | List remote files and directories |
| `cat` | Read remote file content |
| `head` / `tail` | First/last N lines |
| `grep` / `rg` | Pattern search (use targeted paths) |
| `wc` | Line/word/byte counts |
| `stat` | File metadata (size, mtime) |
| `find` | Recursive search with `-name`, `-maxdepth` |
| `tree` | Directory tree view |
| `mkdir` | Create remote directories |
| `touch` | Create empty remote files |
| `cp` / `mv` / `rm` | Copy, move, delete on remote |
| `tee` | Write stdin to remote file |
| `diff` / `cmp` | Compare remote files |
| `sort` / `cut` / `tr` | Text processing |
| `tar` / `zip` / `gzip` | Compression |


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.