Config & Secrets Injection
mvm supports injecting custom files onto the guest’s config and secrets drives at boot time. Files are written to the drive images before the VM starts.
CLI Usage
Section titled “CLI Usage”mkdir -p /tmp/my-config /tmp/my-secrets
echo '{"gateway": {"port": 8080}}' > /tmp/my-config/app.jsonecho 'API_KEY=sk-...' > /tmp/my-secrets/app.env
mvmctl run --template my-app \ --volume /tmp/my-config:/mnt/config \ --volume /tmp/my-secrets:/mnt/secretsThe --volume (-v for short) flag uses the format host_dir:/guest/path:
| Guest path | Drive | Permissions | Purpose |
|---|---|---|---|
/mnt/config | /dev/vdb | Read-only (0444) | Application configuration |
/mnt/secrets | /dev/vdc | Read-only (0400) | API keys, tokens, credentials |
Every file in the host directory is written to the corresponding drive image. For persistent volumes with explicit size, use the 3-part format: --volume host:/guest/path:size.
Library API
Section titled “Library API”The same functionality is available programmatically for library consumers like mvmd:
use mvm_runtime::vm::microvm::{DriveFile, FlakeRunConfig};
let config = FlakeRunConfig { config_files: vec![DriveFile { name: "app.json".into(), content: serde_json::to_string(&app_config)?, mode: 0o444, }], secret_files: vec![DriveFile { name: "app.env".into(), content: format!("API_KEY={}", api_key), mode: 0o400, }], ..base_config};Design
Section titled “Design”The DriveFile type is content-agnostic — it’s just {name, content, mode}. It knows nothing about specific file formats or keys. This means:
- Any file format works (JSON, TOML, YAML, env files, certificates, etc.)
- Adding support for new applications doesn’t require code changes
- NixOS
EnvironmentFilecan load.envfiles directly as systemd environment variables
Example: OpenClaw
Section titled “Example: OpenClaw”The OpenClaw example demonstrates all of these features. It ships with a default config baked into the image, but you can override it by mounting host directories.
Running with example config
Section titled “Running with example config”mvmctl template build openclawmvmctl run --template openclaw --name oc \ -v nix/examples/openclaw/config:/mnt/config \ -v nix/examples/openclaw/secrets:/mnt/secrets \ -p 3000:3000mvmctl forward oc 3000:3000The default config uses auth.mode: "none" — no token is required to access the Control UI. The gateway binds to loopback inside the VM with a TCP proxy forwarding external connections, so all connections appear local and are auto-approved by OpenClaw (no device pairing prompts). To enable token auth, set "auth": { "mode": "token" } in your config and OPENCLAW_GATEWAY_TOKEN in secrets/api-keys.env.
Running with custom config and API keys
Section titled “Running with custom config and API keys”# Create config directory with OpenClaw gateway settingsmkdir -p /tmp/oc-configcat > /tmp/oc-config/openclaw.json << 'EOF'{ "gateway": { "mode": "local", "channelHealthCheckMinutes": 0, "auth": { "mode": "none" }, "reload": { "mode": "off" }, "controlUi": { "dangerouslyAllowHostHeaderOriginFallback": true } }}EOF
# Create secrets directory with API keysmkdir -p /tmp/oc-secretscat > /tmp/oc-secrets/api-keys.env << 'EOF'ANTHROPIC_API_KEY=sk-ant-...EOF
mvmctl run --template openclaw --name oc \ -v /tmp/oc-config:/mnt/config \ -v /tmp/oc-secrets:/mnt/secrets \ -p 3000:3000The OpenClaw service’s preStart script checks for /mnt/config/openclaw.json and uses it (with envsubst expansion) instead of the built-in default. The command script sources /mnt/config/env.sh and /mnt/secrets/api-keys.env if they exist, making environment variables available to the gateway process.
Using snapshots for fast startup
Section titled “Using snapshots for fast startup”Build the template with --snapshot to capture a running VM state. Subsequent runs restore from the snapshot instead of cold-booting, reducing startup time significantly:
mvmctl template build openclaw --snapshotmvmctl run --template openclaw --name oc \ -v nix/examples/openclaw/config:/mnt/config \ -v nix/examples/openclaw/secrets:/mnt/secrets \ -p 3000:3000When restoring from a snapshot with -v mounts, the guest agent automatically remounts config/secrets drives and restarts services with the fresh data.
Running commands inside the VM
Section titled “Running commands inside the VM”The OpenClaw CLI is available inside the VM via mvmctl vm exec:
mvmctl vm exec oc -- openclaw nodes pendingmvmctl vm exec oc -- openclaw nodes approve <id>mvmctl vm exec oc -- openclaw nodes statusSee nix/examples/openclaw/ for the full example with sample config and secrets files.