Node.js native bindings for LXC (Linux Containers) — a complete, production-ready wrapper around
liblxcbuilt with N-API.
Promises backed by a libuv thread poolEventEmitter interfaceInstall LXC on Debian/Ubuntu:
sudo apt install lxc
Verify your kernel supports LXC features:
lxc-checkconfig
npm install node-lxc
Pre-built binaries are included for the following platforms — no compilation step required:
| Architecture | GNU triplet |
|---|---|
| x86-64 | x86_64-linux-gnu |
| ARM64 | aarch64-linux-gnu |
Other Linux architectures must be built from source.
import { Container, GetVersion } from "node-lxc";
console.log("LXC", GetVersion()); // e.g. "5.0.2"
// Create and start a container
const c = new Container("my-container");
await c.create({
template: "download",
argv: ["--dist", "ubuntu", "--release", "jammy", "--arch", "amd64"],
});
c.setConfigItem("lxc.net.0.type", "veth");
c.setConfigItem("lxc.net.0.link", "lxcbr0");
c.setConfigItem("lxc.net.0.flags", "up");
await c.start();
console.log(c.state); // "RUNNING"
console.log(c.initPID); // e.g. 12345
// Run a command and get the exit code
const code = await c.exec({ argv: ["/bin/sh", "-c", "echo hello"] });
console.log(code); // 0
await c.shutdown(30);
await c.destroy();
import {
GetVersion, // → string
GetGlobalConfigItem, // (key: string) → string
ListAllContainers, // (lxcpath?: string) → string[]
ListAllDefinedContainers, // (lxcpath?: string) → string[]
ListAllActiveContainers, // (lxcpath?: string) → string[]
ConfigItemIsSupported, // (key: string) → boolean
HasApiExtension, // (extension: string) → boolean
GetWaitStates, // () → string[]
} from "node-lxc";
const c = new Container(name: string, configPath?: string, alt_file?: string);
| Parameter | Description |
|---|---|
name |
Container name |
configPath |
LXC container directory (defaults to lxc.lxcpath) |
alt_file |
Alternate configuration file path |
await c.create({ template?, argv?, bdevtype?, bdev_specs?, flags? });
await c.start(useinit?, argv?);
await c.stop();
await c.reboot(timeout?); // → Promise<boolean>
await c.shutdown(timeout?); // → Promise<boolean>
await c.freeze();
await c.unfreeze();
await c.destroy({ include_snapshots?, force? });
await c.clone(options); // → Promise<Container>
c.name // string
c.defined // boolean
c.running // boolean
c.state // ContainerState ("RUNNING" | "STOPPED" | ...)
c.initPID // number (-1 if not running)
c.error // { num: number, string: string | null }
c.daemonize // boolean (get/set)
c.configPath // string (get/set)
c.configFileName // string
c.mayControl() // → boolean
await c.initPIDFd() // → number (pidfd)
await c.devptsFd() // → number
c.getConfigItem(key) // → string | null
c.setConfigItem(key, value)
c.clearConfigItem(key)
c.clearConfig()
c.getRunningConfigItem(key) // → string | null (live, running container)
c.getKeys(prefix?) // → string[]
c.getConfigItems(prefix?) // → Record<string, string | null>
await c.loadConfig(alt_file)
await c.save(alt_file)
// Run a command; returns its exit code
await c.exec({ argv: string[], ...lxc_attach_options }) // → number
// Run a command and capture all output
const { exitCode, stdout, stderr } = await c.execOutput({ argv: ["/bin/hostname"] });
// Run a command and stream output as events
const session = await c.execAsync({ argv: ["/usr/bin/top", "-b", "-n1"] });
session
.on("stdout", (chunk: Buffer) => process.stdout.write(chunk))
.on("stderr", (chunk: Buffer) => process.stderr.write(chunk))
.on("exit", (code: number) => console.log("exit:", code));
session.kill(); // send SIGTERM
session.kill(9); // send SIGKILL
// Open a shell; returns the shell's exit code
await c.attach(options?) // → number
// Non-blocking async console session (EventEmitter)
const session = await c.consoleAsync(ttynum?) // → ConsoleSession
session.on("data", (chunk: Buffer) => { ... });
session.on("close", () => { ... });
session.write(data);
session.resize(cols, rows);
session.close();
// Blocking console (connects current stdio)
await c.console(ttynum, [stdinfd, stdoutfd, stderrfd], escape);
// Raw TTY allocation
const [ttyfd, ptxfd] = await c.consoleGetFds(ttynum?);
const stats: ContainerStats = await c.stats();
// {
// "memory.usage_in_bytes": string | null,
// "memory.limit_in_bytes": string | null,
// "memory.memsw.usage_in_bytes": string | null,
// "cpuacct.usage": string | null,
// "cpu.stat": string | null,
// "blkio.throttle.io_service_bytes": string | null,
// }
await c.getInterfaces() // → string[]
await c.getIPs(iface, "inet") // → string[] (IPv4)
await c.getIPs(iface, "inet6", scope) // → string[] (IPv6)
await c.attachInterface(dev, dst_dev?)
await c.detachInterface(dev, dst_dev?)
await c.addDeviceNode(src_path, dest_path?)
await c.removeDeviceNode(src_path, dest_path?)
c.getCGroupItem(subsys) // → string | undefined
c.setCGroupItem(subsys, value)
await c.snapshot(commentfile) // → number (snap index)
await c.snapshotList() // → lxc_snapshot[]
await c.snapshotRestore(snapname, newname?)
await c.snapshotDestroy(snapname)
await c.snapshotDestroy(true) // destroy all
await c.mount(source, target, filesystemtype, mountflags, mnt)
await c.umount(source, mountflags, mnt)
await c.checkpoint(directory, stop?, verbose?)
await c.restore(directory, verbose?)
await c.migrate(cmd: LXC_MIGRATE, options?)
await c.seccompNotifyFd() // → number
await c.seccompNotifyFdActive() // → number
await c.consoleLog({ clear?, read?, read_max? }) // → string
The examples/ directory contains runnable scripts for common use cases:
| Script | Description |
|---|---|
examples/create/ |
Create a container from a template |
examples/start/ |
Start a container |
examples/execute/ |
Run a command in a container |
examples/attach/ |
Open a shell in a container |
examples/console_async/ |
Non-blocking console session |
examples/clone/ |
Clone a container |
examples/checkpoint/ |
CRIU checkpoint/restore |
examples/concurrent_create/ |
Concurrent container creation |
examples/stats/ |
Read cgroup resource metrics |
examples/images/ |
Browse available LXC images |
Run any example with ts-node:
npm run example:create
npm run example:execute
npm run example:console_async
Required additional dependencies:
| Tool | Version |
|---|---|
| liblxc-dev | same as LXC |
| g++ | ≥ 7 |
| cmake | any recent |
sudo apt install lxc lxc-dev g++ cmake
Clone and build:
git clone https://github.com/SourceRegistry/node-lxc.git
cd node-lxc
npm install
npx node-gyp configure && npx node-gyp build
npx tsc --build
npm test
The test suite uses Node.js's built-in node:test runner. Tests that require root access (container create/start/stop/destroy) are automatically skipped unless the process is running as root.
To run the full integration test suite:
sudo npm test
Bug reports and pull requests are welcome on GitHub.
Please ensure:
std::unique_ptr<char[]> for heap buffers[this, var] not [this, &var])Apache 2.0 © 2026 ProjectSource V.O.F.