Skip to main content
The File Operations API provides endpoints for managing files within running containers.

Upload File

Upload a file to a container.
curl -X POST "https://api.rexec.sh/api/files/abc123?path=/home/user/" \
  -H "Authorization: Bearer $TOKEN" \
  -F "file=@/path/to/local/file.txt"
POST /api/files/:containerID

Path Parameters

containerID
string
required
Docker container ID (short or full)

Query Parameters

path
string
default:"/home/user/"
Destination directory path in container

Request Body

file
file
required
File to upload (multipart/form-data)

Validation

  • Max File Size: 100 MB
  • Filename Restrictions: No path traversal (.., /)
  • Container State: Must be running
  • Ownership: Must own the container

Response

message
string
Success message
filename
string
Sanitized filename
path
string
Full path in container
size
number
File size in bytes
Response Example
{
  "message": "file uploaded successfully",
  "filename": "script.sh",
  "path": "/home/user/script.sh",
  "size": 2048
}

Upload Implementation

The upload process:
  1. Stream TAR Archive: File is streamed as TAR to avoid memory buffering
  2. Docker CopyToContainer: Uses Docker SDK’s native copy operation
  3. Touch Container: Updates last-used timestamp
// Create TAR stream
pr, pw := io.Pipe()
tw := tar.NewWriter(pw)

go func() {
    defer pw.Close()
    defer tw.Close()
    
    hdr := &tar.Header{
        Name:    filename,
        Mode:    0644,
        Size:    header.Size,
        ModTime: time.Now(),
    }
    
    tw.WriteHeader(hdr)
    io.Copy(tw, io.LimitReader(file, header.Size))
}()

// Copy to container
client.CopyToContainer(ctx, dockerID, destPath, pr, 
    container.CopyToContainerOptions{})

Download File

Download a file from a container.
curl "https://api.rexec.sh/api/files/abc123?path=/home/user/file.txt" \
  -H "Authorization: Bearer $TOKEN" \
  -O -J
GET /api/files/:containerID

Path Parameters

containerID
string
required
Docker container ID

Query Parameters

path
string
required
File path in container (must be a file, not directory)

Response Headers

  • Content-Disposition: attachment; filename="file.txt"
  • Content-Type: application/octet-stream
  • Content-Length: File size
  • X-File-Size: Total size from stat
  • X-File-Mode: File permission mode

Response Body

Raw file bytes (binary stream)

Error Responses

error
string
  • "container not found" - Invalid container ID
  • "access denied" - Not your container
  • "container is not running" - Container must be running
  • "path parameter required" - Missing path query param
  • "file not found" - File doesn’t exist
  • "path is a directory" - Use /files/list for directories

List Directory

List files in a container directory.
curl "https://api.rexec.sh/api/files/abc123/list?path=/home/user/" \
  -H "Authorization: Bearer $TOKEN"
GET /api/files/:containerID/list

Query Parameters

path
string
default:"/home/user"
Directory path to list

Response

path
string
Requested directory path
files
array
Array of file information objects
count
number
Total number of files/directories
Response Example
{
  "path": "/home/user/",
  "files": [
    {
      "name": "script.sh",
      "path": "/home/user/script.sh",
      "size": 2048,
      "mode": "-rwxr-xr-x",
      "mod_time": "2024-01-15T14:30:00Z",
      "is_dir": false
    },
    {
      "name": "documents",
      "path": "/home/user/documents",
      "size": 4096,
      "mode": "drwxr-xr-x",
      "mod_time": "2024-01-15T10:00:00Z",
      "is_dir": true
    }
  ],
  "count": 2
}

File Object Schema

name
string
File or directory name
path
string
Full path (basePath + name)
size
number
Size in bytes
mode
string
Unix file mode (e.g., “-rw-r—r—”, “drwxr-xr-x”)
mod_time
string
Last modification time (ISO 8601)
is_dir
boolean
True if directory, false if file

Implementation Details

  • Uses ls -la command via Docker exec
  • Parses both GNU ls and busybox ls formats
  • Filters out . and .. entries
  • Handles filenames with spaces
  • Compatible with minimal containers (busybox)

Delete File

Delete a file or directory from a container.
curl -X DELETE "https://api.rexec.sh/api/files/abc123?path=/home/user/file.txt" \
  -H "Authorization: Bearer $TOKEN"
DELETE /api/files/:containerID

Query Parameters

path
string
required
File or directory path to delete

Safety Restrictions

Cannot delete system paths:
  • /, /bin, /sbin, /usr, /etc, /var, /lib, /root
  • Any path under these (except /home/*)

Response

message
string
Success message
path
string
Deleted file path
Response Example
{
  "message": "file deleted successfully",
  "path": "/home/user/file.txt"
}

Implementation

  • Uses rm -rf command via Docker exec
  • Checks exit code for success/failure
  • Recursively deletes directories

Create Directory

Create a directory in a container.
curl -X POST "https://api.rexec.sh/api/files/abc123/mkdir?path=/home/user/newdir" \
  -H "Authorization: Bearer $TOKEN"
POST /api/files/:containerID/mkdir

Query Parameters

path
string
required
Directory path to create

Response

message
string
Success message
path
string
Created directory path
Response Example
{
  "message": "directory created successfully",
  "path": "/home/user/newdir"
}

Implementation

  • Uses mkdir -p command (creates parent directories)
  • Checks exit code for verification

Error Handling

All file operation endpoints follow consistent error patterns:

Authorization Errors

401 Unauthorized
{
  "error": "unauthorized"
}
403 Forbidden
{
  "error": "access denied"
}
403 System Path
{
  "error": "cannot delete system files"
}

Resource Errors

404 Not Found
{
  "error": "container not found"
}
404 File Not Found
{
  "error": "file not found: /path/to/file"
}

Validation Errors

400 Bad Request
{
  "error": "path parameter required"
}
400 File Too Large
{
  "error": "file too large (max 100MB)"
}
400 Invalid Filename
{
  "error": "invalid filename"
}
400 Not Running
{
  "error": "container is not running"
}
400 Directory Error
{
  "error": "path is a directory, use /files/list to list contents"
}

Best Practices

Upload Large Files

Files are streamed to avoid memory issues. The 100MB limit is server-side configurable.

Security

  • Always validate and sanitize user-provided paths
  • Filenames with .., / are rejected
  • System paths are protected from deletion
  • Only container owners can access files

Performance

  • List operations: Use specific paths instead of listing root
  • Download: Use range requests for large files (if implemented)
  • Upload: Compress files before upload when possible

Container State

All file operations require the container to be in running state. Operations will fail with 400 Bad Request if container is stopped.

Common Use Cases

Batch File Upload

const files = ['file1.txt', 'file2.txt', 'file3.txt'];

for (const file of files) {
  const formData = new FormData();
  formData.append('file', await fetch(file).then(r => r.blob()));
  
  await fetch(`https://api.rexec.sh/api/files/${containerID}?path=/home/user/`, {
    method: 'POST',
    headers: { 'Authorization': `Bearer ${token}` },
    body: formData
  });
}

Recursive Directory Download

async function downloadDirectory(containerID, path) {
  const response = await fetch(
    `https://api.rexec.sh/api/files/${containerID}/list?path=${path}`,
    { headers: { 'Authorization': `Bearer ${token}` } }
  );
  
  const { files } = await response.json();
  
  for (const file of files) {
    if (file.is_dir) {
      await downloadDirectory(containerID, file.path);
    } else {
      await downloadFile(containerID, file.path);
    }
  }
}

File Synchronization

async function syncFiles(containerID, localPath, remotePath) {
  // List remote files
  const remoteFiles = await listFiles(containerID, remotePath);
  
  // Compare with local
  const localFiles = await fs.readdir(localPath);
  
  // Upload new/modified files
  for (const file of localFiles) {
    const remote = remoteFiles.find(f => f.name === file);
    const local = await fs.stat(path.join(localPath, file));
    
    if (!remote || remote.mod_time < local.mtime) {
      await uploadFile(containerID, path.join(localPath, file), remotePath);
    }
  }
}

Build docs developers (and LLMs) love