File Transfer
SSH enables secure file transfers between your local machine and Morph instances using SFTP.
- Python
- TypeScript
- CLI
from morphcloud.api import MorphCloudClient
client = MorphCloudClient()
instance = client.instances.get("morphvm_abc123")
with instance.ssh() as ssh:
# Get SFTP client
sftp = ssh._client.open_sftp()
try:
# Upload a file
sftp.put("/local/path/file.txt", "/remote/path/file.txt")
# Download a file
sftp.get("/remote/path/file.txt", "/local/path/file.txt")
# Upload directory recursively
def upload_dir(local_path, remote_path):
sftp.mkdir(remote_path)
for item in os.listdir(local_path):
local_item = os.path.join(local_path, item)
remote_item = f"{remote_path}/{item}"
if os.path.isfile(local_item):
sftp.put(local_item, remote_item)
else:
upload_dir(local_item, remote_item)
upload_dir("/local/dir", "/remote/dir")
# Download directory recursively
def download_dir(remote_path, local_path):
os.makedirs(local_path, exist_ok=True)
for item in sftp.listdir_attr(remote_path):
remote_item = f"{remote_path}/{item.filename}"
local_item = os.path.join(local_path, item.filename)
if stat.S_ISREG(item.st_mode):
sftp.get(remote_item, local_item)
elif stat.S_ISDIR(item.st_mode):
download_dir(remote_item, local_item)
download_dir("/remote/dir", "/local/dir")
finally:
sftp.close()
import { MorphCloudClient } from 'morphcloud';
import * as fs from 'fs/promises';
import * as path from 'path';
import * as stat from 'fs';
const client = new MorphCloudClient();
async function transferFiles() {
const instance = await client.instances.get({ instanceId: "morphvm_abc123" });
const ssh = await instance.ssh();
try {
const sftp = await ssh.requestSFTP();
// Upload a file
await sftp.fastPut("/local/path/file.txt", "/remote/path/file.txt");
// Download a file
await sftp.fastGet("/remote/path/file.txt", "/local/path/file.txt");
// Helper to create remote directories recursively
async function makeRemoteDirs(sftp: any, dir: string) {
if (!dir || dir === '/') return;
try {
await sftp.stat(dir);
} catch (error) {
await makeRemoteDirs(sftp, path.dirname(dir));
try {
await sftp.mkdir(dir);
} catch (error) {
// Ignore if directory exists
}
}
}
// Upload directory recursively
async function uploadDir(localPath: string, remotePath: string) {
await makeRemoteDirs(sftp, remotePath);
const items = await fs.readdir(localPath, { withFileTypes: true });
for (const item of items) {
const localItem = path.join(localPath, item.name);
const remoteItem = `${remotePath}/${item.name}`;
if (item.isDirectory()) {
await uploadDir(localItem, remoteItem);
} else {
await sftp.fastPut(localItem, remoteItem);
}
}
}
// Download directory recursively
async function downloadDir(remotePath: string, localPath: string) {
await fs.mkdir(localPath, { recursive: true });
const items = await sftp.readdir(remotePath);
for (const item of items) {
const remoteItem = `${remotePath}/${item.filename}`;
const localItem = path.join(localPath, item.filename);
if (stat.S_ISDIR(item.attrs.mode)) {
await downloadDir(remoteItem, localItem);
} else {
await sftp.fastGet(remoteItem, localItem);
}
}
}
// Example usage:
await uploadDir("/local/dir", "/remote/dir");
await downloadDir("/remote/dir", "/local/dir");
} finally {
ssh.dispose();
}
}
# Copy a single file to instance
morphcloud instance copy ./local/file.txt morphvm_abc123:/remote/path/file.txt
# Copy a single file from instance
morphcloud instance copy morphvm_abc123:/remote/path/file.txt ./local/file.txt
# Copy directory to instance recursively
morphcloud instance copy -r ./local/dir/ morphvm_abc123:/remote/dir/
# Copy directory from instance recursively
morphcloud instance copy -r morphvm_abc123:/remote/dir/ ./local/dir/
Notes:
- The CLI's
copy
command provides better progress indication and error handling than manual SFTP operations - Both source and destination paths use the format
instance_id:/path
for remote paths - When copying to an instance without specifying a full path, files go to the user's home directory
- The
-r
or--recursive
flag is required for directory copies