File Transfer
SSH enables secure file transfers between your local machine and Morph instances using SFTP.
- Python
- TypeScript
- CLI
from morphcloud.api import MorphCloudClient
import os, tempfile, shutil, stat
# Create test files
test_dir = tempfile.mkdtemp(prefix='test_')
download_directory = tempfile.mkdtemp(prefix='download_')
with open(f"{test_dir}/test.txt", 'w') as f:
f.write('Hello from MorphCloud!')
os.makedirs(f"{test_dir}/subdir")
with open(f"{test_dir}/subdir/nested.txt", 'w') as f:
f.write('Nested file content')
# Transfer files
client = MorphCloudClient()
instance = client.instances.get("morphvm_abc123")
def upload_dir(sftp, local_path, remote_path):
try: sftp.mkdir(remote_path)
except: pass
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(sftp, local_item, remote_item)
def download_dir(sftp, 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(sftp, remote_item, local_item)
with instance.ssh() as ssh:
sftp = ssh._client.open_sftp()
try:
# Single file upload/download
sftp.put(f"{test_dir}/test.txt", "/tmp/test.txt")
sftp.get("/tmp/test.txt", f"{download_directory}/downloaded.txt")
# Directory upload/download
upload_dir(sftp, test_dir, "/tmp/upload_dir")
download_dir(sftp, "/tmp/upload_dir", f"{download_directory}/synced_dir")
finally:
sftp.close()
# Cleanup
shutil.rmtree(test_dir)
shutil.rmtree(download_directory)
import { MorphCloudClient } from 'morphcloud';
import * as fs from 'fs/promises';
import * as path from 'path';
import * as os from 'os';
async function main() {
// Create test files
const testDir = await fs.mkdtemp(path.join(os.tmpdir(), 'test_'));
const downloadDirectory = await fs.mkdtemp(path.join(os.tmpdir(), 'download_'));
await fs.writeFile(path.join(testDir, 'test.txt'), 'Hello from MorphCloud!');
await fs.mkdir(path.join(testDir, 'subdir'));
await fs.writeFile(path.join(testDir, 'subdir', 'nested.txt'), 'Nested file content');
// Transfer files
const client = new MorphCloudClient();
const instance = await client.instances.get({ instanceId: "morphvm_abc123" });
const ssh = await instance.ssh();
const promisify = (fn: Function) => (...args: any[]) => new Promise((resolve, reject) =>
fn(...args, (err: any, result: any) => err ? reject(err) : resolve(result)));
async function uploadDir(sftp: any, localPath: string, remotePath: string) {
try { await promisify(sftp.mkdir.bind(sftp))(remotePath); } catch {}
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(sftp, localItem, remoteItem);
} else {
await promisify(sftp.fastPut.bind(sftp))(localItem, remoteItem);
}
}
}
async function downloadDir(sftp: any, remotePath: string, localPath: string) {
await fs.mkdir(localPath, { recursive: true });
const items = await promisify(sftp.readdir.bind(sftp))(remotePath);
for (const item of items) {
const remoteItem = `${remotePath}/${item.filename}`;
const localItem = path.join(localPath, item.filename);
if (item.attrs.mode & 0o040000) { // S_IFDIR
await downloadDir(sftp, remoteItem, localItem);
} else {
await promisify(sftp.fastGet.bind(sftp))(remoteItem, localItem);
}
}
}
try {
const sftp = await ssh.requestSFTP();
// Single file upload/download
await promisify(sftp.fastPut.bind(sftp))(path.join(testDir, 'test.txt'), '/tmp/test.txt');
await promisify(sftp.fastGet.bind(sftp))('/tmp/test.txt', path.join(downloadDirectory, 'downloaded.txt'));
// Directory upload/download
await uploadDir(sftp, testDir, '/tmp/upload_dir');
await downloadDir(sftp, '/tmp/upload_dir', path.join(downloadDirectory, 'synced_dir'));
} finally {
ssh.dispose();
}
// Cleanup
await fs.rm(testDir, { recursive: true });
await fs.rm(downloadDirectory, { recursive: true });
}
main().catch(console.error);
# 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