Appearance
Mount Object Storage Buckets
Sandboxes support mounting S3-compatible object storage buckets internally using FUSE technology, allowing you to read and write remote object storage data as if it were local files. Sufy Kodo object storage is compatible with the AWS S3 protocol and can be mounted directly using the s3fs tool.
Use Cases
- Accessing large amounts of pre-stored data (e.g., datasets, model files) within a sandbox.
- Sharing the same remote data across multiple sandboxes.
- Persisting files generated in a sandbox to object storage for long-term retention.
Important Notes
- Object storage mounting relies on network transfer, so read/write performance is lower than local file systems. It is not suitable for high-frequency I/O scenarios.
- File operations are non-atomic, meaning there is a risk of local success but remote write failure.
- Suitable for low-frequency read/write and performance-insensitive data access scenarios.
- The runtime environment requires a usable FUSE device (
/dev/fuse). - Before using
-o allow_other, you must enableuser_allow_otherin the environment (see the template configuration below). - It is recommended to unmount (
fusermount -u) before destroying a sandbox to reduce the risk of incomplete writes. - In production code, environment variables in examples should be validated and shell-escaped.
Prerequisites: Create a Template with s3fs
Install s3fs and configure static FUSE settings in your sandbox template's Dockerfile. Since the sandbox runs as the user by default, pre-create the mount directory during the build phase:
dockerfile
FROM e2b/base:latest
# Install s3fs
RUN DEBIAN_FRONTEND=noninteractive apt-get update && apt-get install -y s3fs && rm -rf /var/lib/apt/lists/*
# Enable user_allow_other to allow non-root users to use the -o allow_other mount option
RUN sed -i 's/#user_allow_other/user_allow_other/' /etc/fuse.conf
# Pre-create the mount directory and assign ownership to the default user
RUN mkdir -p /mnt/bucket && chown user:user /mnt/bucketThe /dev/fuse device is provided by the sandbox runtime, so it should not be modified in the Dockerfile build step. If your runtime image requires a permission adjustment, run sudo chmod 666 /dev/fuse after the sandbox starts and before mounting the bucket.
After building a custom template with s3fs, create a sandbox using that template to use the mount feature. For details on creating and building custom templates, refer to the Sandbox Template documentation.
Note: If you do not use a custom template, you can perform the above configuration at runtime using sudo, but this must be repeated each time a sandbox is created. It is recommended to bake the configuration into the template.
Mounting a Sufy Kodo Bucket
Sufy Kodo is compatible with the AWS S3 protocol. Use the S3 endpoint for the corresponding region to mount via s3fs.
Mounting steps:
- Write the AccessKey and SecretKey to a credentials file and set permissions to 600.
- Use the
s3fscommand to mount the bucket to the specified directory.
javascript
import "dotenv/config";
import { Sandbox } from "@e2b/code-interpreter";
async function main() {
const KODO_ACCESS_KEY = process.env.KODO_ACCESS_KEY;
const KODO_SECRET_KEY = process.env.KODO_SECRET_KEY;
const KODO_BUCKET_NAME = process.env.KODO_BUCKET_NAME;
const KODO_S3_ENDPOINT = process.env.KODO_S3_ENDPOINT; // e.g., https://s3.cn-east-1.sufycs.com
const MOUNT_DIR = "/mnt/bucket";
if (
!KODO_ACCESS_KEY ||
!KODO_SECRET_KEY ||
!KODO_BUCKET_NAME ||
!KODO_S3_ENDPOINT
) {
throw new Error(
"Missing required env vars: KODO_ACCESS_KEY, KODO_SECRET_KEY, KODO_BUCKET_NAME, KODO_S3_ENDPOINT",
);
}
// Production recommendation: validate and escape user-controlled parameters before inserting into shell commands.
const shellEscape = (value) => `'${value.replace(/'/g, `'\\''`)}'`;
const sandbox = await Sandbox.create("your-s3fs-template");
try {
// Write credentials file (default sandbox user is 'user')
await sandbox.files.write(
"/home/user/.passwd-s3fs",
`${KODO_ACCESS_KEY}:${KODO_SECRET_KEY}`,
);
await sandbox.commands.run("chmod 600 /home/user/.passwd-s3fs");
// Mount the bucket (mount directory pre-created in template Dockerfile)
await sandbox.commands.run(
`s3fs ${shellEscape(KODO_BUCKET_NAME)} ${MOUNT_DIR} -o url=${shellEscape(KODO_S3_ENDPOINT)} -o allow_other -o use_path_request_style -o passwd_file=/home/user/.passwd-s3fs`,
);
// Wait for mount to be ready (s3fs initialization takes a few seconds)
await sandbox.commands.run(
`for i in $(seq 1 10); do mountpoint -q ${MOUNT_DIR} && touch ${MOUNT_DIR}/.ready 2>/dev/null && rm -f ${MOUNT_DIR}/.ready && break; sleep 1; done`,
);
// Verify mount result
const files = await sandbox.commands.run(`ls ${MOUNT_DIR}`);
console.log("Bucket contents:", files.stdout);
// Read and write like local files
await sandbox.commands.run(`echo "hello kodo" > ${MOUNT_DIR}/test.txt`);
const result = await sandbox.commands.run(`cat ${MOUNT_DIR}/test.txt`);
console.log(result.stdout); // Output: hello kodo\n
} finally {
await sandbox.commands.run(`fusermount -u ${MOUNT_DIR}`).catch(() => {});
await sandbox.kill();
}
}
main();Parameter Description
| Parameter | Description |
|---|---|
KODO_ACCESS_KEY | Sufy AccessKey |
KODO_SECRET_KEY | Sufy SecretKey |
KODO_BUCKET_NAME | Bucket name |
KODO_S3_ENDPOINT | S3-compatible endpoint, e.g., https://s3.cn-east-1.sufycs.com |
MOUNT_DIR | Mount directory path inside the sandbox (must be pre-created in the template) |
s3fs Mount Options
| Option | Description |
|---|---|
-o url | Endpoint URL of the S3-compatible service |
-o allow_other | Allow other users to access the mount directory (requires user_allow_other) |
-o use_path_request_style | Use path-style URL (required for Sufy Kodo) |
-o passwd_file | Specify the credentials file path (default is ~/.passwd-s3fs) |
For more s3fs configuration and usage, refer to the Sufy Kodo S3FS Usage Guide.
S3-Compatible Service Domains
KODO_S3_ENDPOINT must be the S3-compatible domain for the bucket's region. The following are the domains for each region:
| Storage Region | Region ID | Endpoint |
|---|---|---|
| East China - Zhejiang | cn-east-1 | https://s3.cn-east-1.sufycs.com |
| East China - Zhejiang 2 | cn-east-2 | https://s3.cn-east-2.sufycs.com |
| North China - Hebei | cn-north-1 | https://s3.cn-north-1.sufycs.com |
| South China - Guangdong | cn-south-1 | https://s3.cn-south-1.sufycs.com |
| North America - Los Angeles | us-north-1 | https://s3.us-north-1.sufycs.com |
| Asia Pacific - Singapore | ap-southeast-1 | https://s3.ap-southeast-1.sufycs.com |
| Asia Pacific - Hanoi | ap-southeast-2 | https://s3.ap-southeast-2.sufycs.com |
| Asia Pacific - Ho Chi Minh | ap-southeast-3 | https://s3.ap-southeast-3.sufycs.com |
For a complete list of domains, refer to the Sufy Kodo S3-Compatible Service Domains.
Mounting an AWS S3 Bucket
s3fs also supports mounting AWS S3. The process is similar; simply replace the credentials and endpoint information.
javascript
import "dotenv/config";
import { Sandbox } from "@e2b/code-interpreter";
async function main() {
const AWS_ACCESS_KEY_ID = process.env.AWS_ACCESS_KEY_ID;
const AWS_SECRET_ACCESS_KEY = process.env.AWS_SECRET_ACCESS_KEY;
const AWS_BUCKET_NAME = process.env.AWS_BUCKET_NAME;
const AWS_REGION = process.env.AWS_REGION || "us-east-1";
const MOUNT_DIR = "/mnt/bucket";
if (!AWS_ACCESS_KEY_ID || !AWS_SECRET_ACCESS_KEY || !AWS_BUCKET_NAME) {
throw new Error(
"Missing required env vars: AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_BUCKET_NAME",
);
}
// Production recommendation: validate and escape user-controlled parameters before inserting into shell commands.
const shellEscape = (value) => `'${value.replace(/'/g, `'\\''`)}'`;
const sandbox = await Sandbox.create("your-s3fs-template");
try {
// Write credentials file (default sandbox user is 'user')
await sandbox.files.write(
"/home/user/.passwd-s3fs",
`${AWS_ACCESS_KEY_ID}:${AWS_SECRET_ACCESS_KEY}`,
);
await sandbox.commands.run("chmod 600 /home/user/.passwd-s3fs");
// Mount the bucket
await sandbox.commands.run(
`s3fs ${shellEscape(AWS_BUCKET_NAME)} ${MOUNT_DIR} -o allow_other -o endpoint=${shellEscape(AWS_REGION)} -o url=${shellEscape(`https://s3.${AWS_REGION}.amazonaws.com`)} -o passwd_file=/home/user/.passwd-s3fs`,
);
// Verify mount result
const files = await sandbox.commands.run(`ls ${MOUNT_DIR}`);
console.log("Bucket contents:", files.stdout);
} finally {
await sandbox.commands.run(`fusermount -u ${MOUNT_DIR}`).catch(() => {});
await sandbox.kill();
}
}
main();Mounting Other S3-Compatible Storage
Any object storage service compatible with the AWS S3 protocol can be mounted using s3fs. In addition to replacing the url, AccessKey, and SecretKey, it is recommended to specify the access style:
- If the service requires path-style access, add
-o use_path_request_style. - If the service supports virtual-hosted-style access, you can omit
-o use_path_request_style.
Generic example:
javascript
import "dotenv/config";
import { Sandbox } from "@e2b/code-interpreter";
async function main() {
const S3_ACCESS_KEY = process.env.S3_ACCESS_KEY;
const S3_SECRET_KEY = process.env.S3_SECRET_KEY;
const S3_BUCKET_NAME = process.env.S3_BUCKET_NAME;
const S3_ENDPOINT_URL = process.env.S3_ENDPOINT_URL; // e.g., https://minio.example.com
const MOUNT_DIR = "/mnt/bucket";
if (!S3_ACCESS_KEY || !S3_SECRET_KEY || !S3_BUCKET_NAME || !S3_ENDPOINT_URL) {
throw new Error(
"Missing required env vars: S3_ACCESS_KEY, S3_SECRET_KEY, S3_BUCKET_NAME, S3_ENDPOINT_URL",
);
}
// Production recommendation: validate and escape user-controlled parameters before inserting into shell commands.
const shellEscape = (value) => `'${value.replace(/'/g, `'\\''`)}'`;
const sandbox = await Sandbox.create("your-s3fs-template");
try {
await sandbox.files.write(
"/home/user/.passwd-s3fs",
`${S3_ACCESS_KEY}:${S3_SECRET_KEY}`,
);
await sandbox.commands.run("chmod 600 /home/user/.passwd-s3fs");
await sandbox.commands.run(
`s3fs ${shellEscape(S3_BUCKET_NAME)} ${MOUNT_DIR} -o url=${shellEscape(S3_ENDPOINT_URL)} -o allow_other -o use_path_request_style -o passwd_file=/home/user/.passwd-s3fs`,
);
const files = await sandbox.commands.run(`ls ${MOUNT_DIR}`);
console.log("Bucket contents:", files.stdout);
} finally {
await sandbox.commands.run(`fusermount -u ${MOUNT_DIR}`).catch(() => {});
await sandbox.kill();
}
}
main();