How to Configure the LXC Backend in Microsoft MXC: Complete Setup Guide

To configure the LXC backend in Microsoft MXC, set containment: "lxc" in your JSON configuration and provide an lxc object specifying the Linux distribution and release for the container root filesystem.

Microsoft MXC (eXecution Container) enables secure code execution through Linux containers via its LXC backend. When you configure the LXC backend in MXC, the runner invokes the lxc-exec binary to create isolated environments with granular filesystem and network controls. This guide covers the complete configuration process based on the source implementation in the microsoft/mxc repository.

Prerequisites for LXC Backend Installation

Before configuring the LXC backend, install LXC and development libraries on your Linux host. Root privileges are typically required unless you configure unprivileged LXC containers.

For Debian or Ubuntu systems:

sudo apt install lxc lxc-utils liblxc-dev

For Fedora or RHEL systems:

sudo dnf install lxc lxc-devel

For Arch Linux:

sudo pacman -S lxc

These prerequisites enable the lxc-exec binary to interface with the host's LXC libraries as documented in docs/lxc-support/lxc-backend.md.

Architectural Components of the LXC Backend

The LXC implementation in MXC relies on several core structures defined in the source code.

ContainmentBackend::Lxc – The wire name "lxc" in your configuration triggers the MXC runner to invoke the LXC-specific execution path. This enum variant is defined in src/core/wxc_common/src/models.rs at lines 18-22.

LxcConfig – This struct captures the container image parameters. Located in src/core/wxc_common/src/models.rs at lines 56-64, it requires distribution and release fields that map directly to LXC template names.

LifecycleConfig – Controls container persistence through the destroy_on_exit boolean. When enabled, the container is automatically destroyed after script execution. See src/core/wxc_common/src/models.rs lines 5-8.

ContainerPolicy – Enforces security boundaries via bind-mounts and network rules. This includes read-only, read-write, and denied path specifications, implemented in src/core/wxc_common/src/models.rs at lines 27-38.

lxc-exec binary – The platform-specific wrapper located at src/core/lxc/src/main.rs that orchestrates container creation, policy application, script execution, and teardown.

Step-by-Step LXC Backend Configuration

1. Create the JSON Configuration File

Define a configuration file that selects the LXC backend and specifies the container environment. The lxc object is mandatory when containment is set to "lxc" and maps directly to the LxcConfig struct.

{
    "schemaVersion": "0.6.0-alpha",
    "containerId": "my-lxc-sandbox",
    "containment": "lxc",
    "lxc": {
        "distribution": "alpine",
        "release": "3.21"
    },
    "filesystem": {
        "readwritePaths": ["/tmp/output"],
        "readonlyPaths": ["/opt/tools"],
        "deniedPaths": ["/etc/shadow"]
    },
    "network": {
        "defaultPolicy": "block",
        "allowedHosts": ["api.github.com"]
    },
    "lifecycle": {
        "destroyOnExit": true
    },
    "script": "echo 'Hello from LXC'; uname -a"
}

The distribution and release values must correspond to valid LXC template names available on your host system.

2. Execute via Command Line Interface

Run the configuration using the lxc-exec binary built from the src/core/lxc crate.

Standard execution:

./lxc-exec config.json

Enable verbose diagnostics for troubleshooting:

./lxc-exec --debug config.json

For embedded tooling scenarios, pass the configuration as base64:

./lxc-exec --config-base64 <base64-encoded-config>

These CLI options are documented in docs/lxc-support/lxc-backend.md at lines 6-18.

3. Execute via TypeScript SDK

The MXC TypeScript SDK automatically selects lxc-exec when running on Linux hosts and the policy specifies LXC containment.

import { spawnSandbox, SandboxPolicy } from '@microsoft/mxc-sdk';

const policy: SandboxPolicy = {
    filesystem: {
        readwritePaths: ['/tmp/output'],
        readonlyPaths: ['/opt/tools'],
    },
    network: {
        allowOutbound: false,
    },
};

const pty = spawnSandbox('echo hello from LXC', policy);
pty.onData(d => console.log(d));
pty.onExit(e => console.log('Exit code:', e.exitCode));

The SDK handles the JSON serialization and binary invocation as described in docs/lxc-support/lxc-backend.md at lines 22-38.

4. Manage Container Lifecycle

When destroyOnExit is set to false, containers persist after execution. Manually remove them using:

./lxc-exec --delete --containername my-lxc-sandbox

This command references the containerId specified in your original configuration.

Key Source Files for LXC Configuration

Understanding these files helps with advanced troubleshooting and custom builds:

  • src/core/wxc_common/src/models.rs – Defines ContainmentBackend, LxcConfig, LifecycleConfig, and policy structs used by the JSON parser.
  • src/core/lxc/src/main.rs – Implements the native lxc-exec binary that creates containers, applies bind-mounts and iptables rules, and manages execution.
  • docs/lxc-support/lxc-backend.md – Human-readable guide covering prerequisites, schema definitions, and usage examples.
  • tests/configs/basic_lxc.json – Minimal working configuration example used by the test suite.
  • tests/scripts/run_lxc_*.sh – Shell scripts demonstrating end-to-end LXC test harness execution.

Summary

  • Enable LXC backend by setting containment: "lxc" in your MXC JSON configuration.
  • Specify container image using the lxc object with distribution and release fields that map to LXC templates.
  • Control security boundaries through filesystem and network policies defined in ContainerPolicy.
  • Manage persistence via the lifecycle.destroyOnExit boolean; manual deletion uses ./lxc-exec --delete.
  • Execute containers using either the lxc-exec CLI directly or the TypeScript SDK, which auto-detects Linux hosts.

Frequently Asked Questions

What LXC template names are valid for the distribution and release fields?

Valid values depend on templates installed on your host system. Common options include alpine with releases like 3.21, ubuntu with noble or jammy, and debian with bookworm. The lxc section maps directly to the LxcConfig struct in src/core/wxc_common/src/models.rs, which passes these values to the standard LXC template creation tools.

How do I troubleshoot LXC container startup failures?

Run the lxc-exec binary with the --debug flag to enable verbose logging: ./lxc-exec --debug config.json. This outputs detailed information about container creation, bind-mount operations, and network policy application. Check docs/lxc-support/lxc-backend.md for platform-specific prerequisites that might be missing.

Can I use unprivileged LXC containers with MXC?

Yes, but the host must be configured for unprivileged LXC usage with proper UID/GID mappings and subordinate ID ranges. The lxc-exec binary respects standard LXC configuration files, though the microsoft/mxc test suite assumes root privileges for full network and filesystem policy enforcement.

What happens when destroyOnExit is set to false?

The container remains on the host after script execution completes, allowing you to inspect the filesystem state or restart the container manually. You must subsequently delete it using ./lxc-exec --delete --containername <containerId> to free resources. This setting corresponds to the LifecycleConfig struct defined in src/core/wxc_common/src/models.rs.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →