Skip to content

Repository files navigation

linpodx

Containers, AI sandboxes, GUI apps. Native on Linux.

Linux-native container management with a Rust CLI, desktop GUI,
AI-agent sandboxing, and lightweight multi-distro environments.

# Latest stable release (default)
curl -fsSL https://raw.githubusercontent.com/kernalix7/linpodx/main/install.sh | bash

# Latest main HEAD (development; may be unstable)
curl -fsSL https://raw.githubusercontent.com/kernalix7/linpodx/main/install.sh | bash -s -- --main

# Uninstall (keeps local linpodx data; pass --purge to wipe data/config)
curl -fsSL https://raw.githubusercontent.com/kernalix7/linpodx/main/uninstall.sh | bash -s -- --confirm

Pre-alpha Latest

license rust tests CI

Works on

openSUSE Fedora Debian Ubuntu RHEL family Arch

English  ·  한국어  ·  Changelog  ·  Architecture  ·  Contributing  ·  Security


Status: Pre-alpha

linpodx is preparing its first v0.1.0 release. Phase 0..17 implementation is in-tree: local daemon, CLI, Tauri-based desktop GUI, AI-agent sandbox, audit log, snapshots, host-stdio bridge, GUI passthrough, multi-distro templates, remote daemon, plugin hooks, cluster scaffolding, and snapshot encryption hardening. The current release gate is conservative: 829 unit tests pass, 54 host/runtime-dependent integration tests are ignored by default, and the project still expects sharp edges outside development workstations.

No Docker Desktop VM. linpodx talks to rootless Podman on Linux, keeps the daemon local by default, and exposes the same container state through CLI, GUI, and event subscriptions.

linpodx pairs an 18-tab daemon-served web UI (Dashboard, Containers, Pods, Stacks, Images, Volumes, Networks, Secrets, Snapshots, Sessions, Sandbox, Audit, Cluster, Pinned Clients, Plugins, Disk, Disk Usage, Settings) with a thin Tauri 2 desktop shell that displays that same UI locally. Pods and compose-style Stacks group related containers, a Secrets tab manages the Podman secret store, a Disk center reclaims space across images/containers/volumes, and resource rows carry right-click context menus for common actions. Alongside the container manager sits the AI-agent sandbox suite: YAML policy profiles, approval gates, a tamper-evident hash-chained audit log, per-container session timelines, and snapshot/rollback workflows.

Screenshots

Dashboard tab showing disk usage, CPU/memory sparklines, resource counts, and live events
Dashboard — disk, CPU/memory, and live events at a glance
Containers tab listing containers with stack, image, status, CPU, and memory columns
Containers — lifecycle state, stack grouping, resource usage
Disk tab breaking down reclaimable space by images, containers, volumes, and build cache
Disk — reclaimable space by images, containers, and volumes
linpodx-gui Tauri desktop shell displaying the Dashboard tab
Desktop shell — the Tauri 2 app displaying the same web UI

Why linpodx

Tool Gap linpodx targets
Docker Desktop Heavy Linux story, license friction, weak desktop passthrough, no AI-agent sandbox model
Rancher Desktop Kubernetes-first; too much machinery for daily local container work
Podman Desktop Strong general container UI, but not built around sandbox approvals, snapshots, or multi-distro shells
distrobox / toolbx Great lightweight environments, but CLI-first and light on policy/audit controls
Full VMs Strong isolation, but slower boot and heavier CPU/RAM/storage footprint

linpodx bundles a desktop container manager, a safe AI-agent execution sandbox, and GUI-integrated Linux environments into one Linux-native toolchain.

Use cases

  1. Desktop container management — daily container, image, volume, and network work through a CLI and GUI backed by the same daemon.
  2. AI-agent sandbox execution — run risky agentic shell workflows in containers with approval gates, audit trails, resource limits, snapshots, and rollback.
  3. Lightweight distro shells — keep Ubuntu, Fedora, Arch, Debian, Alpine, and NixOS environments side-by-side without full VMs.
  4. GUI-integrated containers — forward Wayland/X11, audio, GPU, clipboard, DBus, theme, and HiDPI state into selected containers.
  5. Local-first remote access — stay Unix-socket local by default, then opt into WebSocket, bearer tokens, mTLS, and cert pinning when needed.

Quick install

One-liner, any supported Linux distro:

curl -fsSL https://raw.githubusercontent.com/kernalix7/linpodx/main/install.sh | bash

Install from a local checkout or offline source tree:

git clone https://github.com/kernalix7/linpodx.git
cd linpodx
./install.sh --source .

Optional L4 egress helper capabilities:

./install.sh --source . --setcap-helper

Uninstall:

curl -fsSL https://raw.githubusercontent.com/kernalix7/linpodx/main/uninstall.sh | bash -s -- --confirm

Use --purge to remove local linpodx data/config as well. Podman containers, images, volumes, Rust, Podman, and system packages are left alone.

Choose a version

The installer follows the linpodx release posture: default to the latest published release, make main and arbitrary refs explicit.

# Latest stable release (default)
curl -fsSL https://raw.githubusercontent.com/kernalix7/linpodx/main/install.sh | bash

# Latest main HEAD
curl -fsSL https://raw.githubusercontent.com/kernalix7/linpodx/main/install.sh | bash -s -- --main

# Specific tag, branch, or commit
curl -fsSL https://raw.githubusercontent.com/kernalix7/linpodx/main/install.sh | bash -s -- --ref v0.1.0

# Env-var equivalents, useful under curl | bash
LINPODX_REF=main   curl -fsSL https://raw.githubusercontent.com/kernalix7/linpodx/main/install.sh | bash
LINPODX_REF=v0.1.0 curl -fsSL https://raw.githubusercontent.com/kernalix7/linpodx/main/install.sh | bash

Offline / source install

# Copy from a local clone instead of git clone
./install.sh --source /media/usb/linpodx

# Skip distro dependency installation; fail early if tools are missing
./install.sh --skip-deps

# Build CLI + daemon only
./install.sh --source . --no-gui

# Skip the privileged L4 egress helper
./install.sh --source . --no-helper

Environment variables mirror the flags: LINPODX_SOURCE, LINPODX_REF, LINPODX_SKIP_DEPS, LINPODX_NO_GUI, LINPODX_NO_HELPER, LINPODX_INSTALL_DIR, and LINPODX_BIN_DIR.

Prerequisites

  • Linux x86_64 or aarch64, with Wayland or X11 for the desktop GUI.
  • Podman 4.6.0 or newer, rootless preferred.
  • Rust 1.85+ for source builds. rust-toolchain.toml pins the workspace baseline.
  • rustfmt and clippy for development.
  • Build-time dependencies for the linpodx-gui desktop shell (Tauri 2 over the system WebKitGTK 4.1 + GTK 3 stack — see Troubleshooting if linpodx-gui fails to start):
    • Debian/Ubuntu: libwebkit2gtk-4.1-dev libgtk-3-dev librsvg2-dev
    • Fedora: webkit2gtk4.1-devel
    • openSUSE Tumbleweed: webkitgtk3-devel
  • Optional: nftables, util-linux / nsenter, and setcap for the privileged L4 egress helper.

The helper is intentionally opt-in because it needs CAP_NET_ADMIN and CAP_SYS_ADMIN:

sudo setcap cap_net_admin,cap_sys_admin+ep ~/.local/bin/linpodx-netfilter-helper
sudo install -d -m 0755 /run/linpodx
linpodx-netfilter-helper --daemon-uid "$(id -u)" &

Without the helper, DNS allowlist filtering still works and network egress apply reports helper_applied: false.

Launch

linpodx-daemon                 # Start the local Unix-socket daemon
linpodx ps --all               # Query containers from the CLI
linpodx-gui                    # Open the desktop dashboard

The daemon binds $XDG_RUNTIME_DIR/linpodx.sock by default, falling back to /tmp/linpodx-$UID.sock.

linpodx-gui is a thin Tauri 2 shell: it auto-starts linpodx-daemon if it isn't already running, then opens the same web UI the daemon serves locally on 127.0.0.1 with a one-shot token (see Web UI). The identical UI is reachable from any browser by starting the daemon with --remote-listen and opening /ui?token=<token>.

Key features

Desktop container manager

  • Container lifecycle: create, start, stop, restart, pause, remove
  • Image, volume, and network management through one CLI/API surface
  • Live event stream for daemon state changes
  • Tauri 2 desktop shell displaying the daemon's web UI — containers, images, volumes, networks, audit, snapshots, sessions, plugins, and cluster views, also reachable from a browser
  • JSON/table output for shell-friendly workflows

AI-agent sandbox

  • YAML sandbox profiles with capability drops, read-only rootfs, mount allowlists, and network modes
  • Approval gates for sensitive actions such as host mounts, capability adds, and bridge tool calls
  • Tamper-evident audit log with hash chaining
  • Session timeline that merges container lifetime, audit events, and bridge events
  • Snapshot before/after workflows for rollback-friendly experiments

GUI passthrough

  • Wayland and X11 socket forwarding
  • PipeWire / PulseAudio audio passthrough
  • GPU access through DRI-oriented device grants
  • DBus session bus, clipboard, HiDPI, and theme environment propagation
  • Per-profile and per-container passthrough configuration

Multi-distro environments

  • Ubuntu, Fedora, Arch, Debian, Alpine, and NixOS templates
  • Optional systemd inside supported container profiles
  • VM mode with persistent home volume, auto-restart, and host UID/GID mapping
  • Template inspection, build, create, enter, and remove commands
  • Lighter than a full VM for day-to-day Linux environment testing

Snapshots & storage

  • Podman commit snapshots with list, rollback, remove, prune, and async job APIs
  • Branch and diff helpers for comparing snapshot state
  • Overlayfs and BTRFS backend scaffolding
  • Snapshot encryption and key-rotation plumbing
  • Metrics and audit hooks for long-running jobs

Remote, plugins, and cluster

  • Local Unix socket by default, optional WebSocket remote daemon
  • mTLS, token auth, and client certificate pinning for remote access
  • Wasmtime plugin registry with signed-plugin verification
  • Cluster gossip, membership, and Raft state-machine scaffolding
  • Kubernetes read/write adapter surface for workstation automation

See CHANGELOG.md for the full v0.1.0 feature list.

Common workflows

Container lifecycle:

linpodx-daemon &
linpodx run --name demo docker.io/library/alpine:latest sleep 30
linpodx ps --all
linpodx logs demo
linpodx rm -f demo

Sandbox profile:

mkdir -p ~/.config/linpodx/profiles
cp examples/profiles/read-only-net-disabled.yaml ~/.config/linpodx/profiles/
linpodx sandbox reload
linpodx run --sandbox read-only-net-disabled --name probe alpine sleep 5
linpodx sandbox audit --profile read-only-net-disabled

Snapshots:

linpodx run --name work alpine sleep 600
linpodx snapshot create --label before-experiment work
linpodx snapshot list
linpodx snapshot rollback --new-name work-restored 1

Multi-distro shell:

linpodx distro list
linpodx distro build --kind ubuntu --include git,curl,python3
linpodx distro create --kind ubuntu --vm-mode my-ubuntu
linpodx distro enter my-ubuntu

Remote daemon:

linpodx-daemon --socket /tmp/lp.sock --remote-listen 127.0.0.1:8443 --remote-token dev
linpodx --remote ws://127.0.0.1:8443/ipc --token dev ps --all

Remote daemon

Run a daemon with a WebSocket listener when another process or host needs access to the same JSON-RPC surface:

linpodx-daemon \
  --socket /tmp/lp.sock \
  --remote-listen 127.0.0.1:8443 \
  --remote-token hunter2

linpodx --remote ws://127.0.0.1:8443/ipc --token hunter2 version
linpodx --remote 127.0.0.1:8443 --token hunter2 ps

Environment variables work too:

export LINPODX_REMOTE=ws://daemon.internal:8443/ipc
export LINPODX_REMOTE_TOKEN=hunter2
linpodx ps

Keep plain ws:// behind loopback, a firewall, or an SSH tunnel. For untrusted networks, use TLS and client certificates.

mTLS and client pinning

Generate local test certificates:

linpodx daemon cert generate --out ./certs

Start a remote daemon with TLS and client-certificate verification:

linpodx-daemon \
  --socket /tmp/lp.sock \
  --remote-listen 127.0.0.1:8443 \
  --remote-token hunter2 \
  --tls-cert ./certs/server.pem \
  --tls-key ./certs/server-key.pem \
  --client-ca ./certs/ca.pem \
  --pin-clients

Then connect with the client certificate:

linpodx \
  --remote wss://127.0.0.1:8443/ipc \
  --token hunter2 \
  --client-cert ./certs/client.pem \
  --client-key ./certs/client-key.pem \
  --client-ca ./certs/ca.pem \
  ps --all

Pinned clients are managed through linpodx daemon pin-client {add,list,remove,tofu}. TOFU enrollment can be enabled for controlled first-contact windows, then disabled once the expected clients are pinned.

Web UI

The daemon can serve a browser UI on the same listener as the remote /ipc endpoint:

linpodx-daemon \
  --socket /tmp/lp.sock \
  --remote-listen 127.0.0.1:8443 \
  --remote-token hunter2

Open http://127.0.0.1:8443/ui/ and provide the bearer token. The Web UI shares the remote listener's security posture, so use mTLS for untrusted networks.

This is the same UI linpodx-gui opens locally: the desktop shell calls the daemon's WebUiEnsure IPC method to bind an ephemeral loopback listener and mint a one-shot token, then points its webview at it — no separate GUI codebase to maintain.

The Leptos/WASM UI is opt-in at build time:

rustup target add wasm32-unknown-unknown
cargo install wasm-bindgen-cli
LINPODX_WASM=1 cargo build -p linpodx-daemon --release

Without LINPODX_WASM=1, the daemon serves the lightweight built-in fallback UI. For air-gapped terminal modals, vendor xterm.js assets at build time:

LINPODX_VENDOR_XTERM=1 cargo build --release -p linpodx-daemon

Security profiles

Compile a sandbox profile's seccomp and AppArmor artifacts:

linpodx sandbox profile compile read-only-net-disabled --secprofile-out /tmp/secprofiles

When the profile has syscall_allowlist or apparmor_extra, the daemon applies the generated files through Podman's --security-opt flags. Hosts without apparmor_parser keep the seccomp half and skip AppArmor.

SELinux profile synthesis is available on hosts with checkmodule, semodule_package, semodule, and SELinux in enforcing/permissive mode. Set selinux_type: <type_name> in a sandbox profile to synthesize, package, install, and apply a per-profile label. Hosts without SELinux tooling fall back gracefully.

Interactive exec

Interactive PTY mode is available over the WebSocket remote listener:

linpodx --remote 127.0.0.1:8443 --token hunter2 \
  exec -it <container_id> -- bash

The daemon allocates a PTY pair, the CLI switches the local terminal into raw mode, and /pty/<bridge_id> carries the interactive stream. Each bridge is single-use and closes when the process exits or the WebSocket disconnects.

Kubernetes adapter

linpodx can call the standard Kubernetes discovery chain (KUBECONFIG, ~/.kube/config, or in-cluster service account) through the daemon:

linpodx k8s pod create ./pod.yaml -n my-ns
cat pod.yaml | linpodx k8s pod create - -n my-ns
linpodx k8s pod delete hello -n my-ns
linpodx k8s ns create my-ns
linpodx k8s scale web --replicas 3 -n prod

Cluster-mutating operations are recorded in the local audit log.

Benchmarks

Criterion benches live under the relevant crates and have a baseline in bench-results/:

cargo bench -p linpodx-runtime --bench snapshot --bench container --bench cgroup \
  -p linpodx-mcp --bench policy \
  -p linpodx-plugin --bench invoke -- --quick

The bench workflow compares quick-mode means against the checked-in baseline and flags large regressions without failing the build.

Roadmap

Version Focus
v0.1.x Stabilize the local daemon, installer, GUI dashboard, and core sandbox flows
v0.2.x Packaging, systemd user units, Web UI polish, and remote daemon hardening
v0.3.x More distro workflows, richer GUI actions, and plugin author ergonomics
v0.4.x Multi-host/cluster usability and stronger operational recovery

Non-goals

  • Replacing Kubernetes, Rancher, k3s, or k0s.
  • First-class Windows/macOS hosts; linpodx is Linux-native.
  • Hiding Podman. The runtime remains visible, debuggable, and compatible with normal Podman workflows.
  • Removing user judgment from sensitive operations. Approval gates and audit logs are part of the product, not a temporary limitation.

Architecture

linpodx CLI / GUI / Web UI
          |
          | JSON-RPC 2.0 over Unix socket or WebSocket
          v
linpodx-daemon
  |-- Podman runtime adapter
  |-- sandbox policy manager
  |-- audit/event/session/snapshot managers
  |-- plugin registry
  |-- remote daemon transport
  `-- cluster / distro / passthrough adapters
          |
          v
Rootless Podman + Linux desktop integrations
Crate Purpose
linpodx-cli linpodx command-line client
linpodx-daemon Unix-socket API server, dispatcher, event bus, remote transport
linpodx-gui Tauri 2 desktop shell for the daemon-served web UI
linpodx-runtime Podman wrapper, images, volumes, networks, snapshots, passthrough
linpodx-sandbox profiles, approvals, audit, sessions, snapshot triggers
linpodx-common shared IPC, state, errors, database migrations
linpodx-distro distro templates and VM-mode helpers
linpodx-plugin Wasmtime plugin loading, manifests, signing, registry
linpodx-cluster gossip, Raft, Kubernetes adapter
linpodx-webui browser UI bundle, served by the daemon both locally (linpodx-gui) and to the remote listener

Documentation

Document What's inside
CHANGELOG.md v0.1.0 release notes and pre-release phase history
docs/README.ko.md Korean overview
docs/INSTALL.md Installer, uninstall, offline/source install, prerequisites
docs/TROUBLESHOOTING.md First-run snags and recovery steps
docs/RELEASE.md Versioning, tag discipline, release checklist
docs/architecture.md System architecture, data flow, trust boundaries
docs/scenarios/ai-agent-sandbox.md Sandbox workflow
docs/scenarios/gui-app.md GUI passthrough scenario
docs/scenarios/multi-distro-shell.md Multi-distro shell scenario
docs/scenarios/plugin-author.md Plugin author workflow
docs/scenarios/remote-daemon.md Remote daemon workflow
CONTRIBUTING.md Development setup and workflow
SECURITY.md Security disclosure process

Supported distros

Distro Package manager Status
openSUSE Tumbleweed / Leap / Slowroll zypper Supported
Fedora / RHEL family / AlmaLinux / Rocky dnf Supported
Debian / Ubuntu / Linux Mint / Pop!_OS apt Supported
Arch / Manjaro / EndeavourOS pacman Supported

Podman 4.6.0 or newer is required. Rust 1.85+ is required for source builds.

Testing

cargo +1.85 fmt --all -- --check
cargo +1.85 clippy --workspace --all-targets --all-features -- -D warnings
cargo +1.85 build --workspace
cargo +1.85 test --workspace
cargo +1.85 doc --workspace --no-deps

Ignored integration tests touch host runtimes, networking helpers, Podman lifecycle, or external services:

cargo +1.85 test --workspace -- --ignored --test-threads=1

Development

git clone https://github.com/kernalix7/linpodx.git
cd linpodx
rustup toolchain install 1.85 --component clippy --component rustfmt
cargo +1.85 build --workspace

Run from a checkout without installing:

cargo +1.85 run -p linpodx-daemon
cargo +1.85 run -p linpodx-cli -- ps --all
cargo +1.85 run -p linpodx-gui

Snapshot encryption

Snapshots can be stored encrypted at rest with AES-256-GCM. Encryption is opt-in through environment variables read by the daemon at startup:

Variable Meaning
LINPODX_SNAPSHOT_ENCRYPT_PASSPHRASE Derive the encryption key from this passphrase. Required for the passphrase path.
LINPODX_SNAPSHOT_KEY Use this raw base64-encoded 32-byte key directly. Mutually exclusive with the passphrase.
LINPODX_SNAPSHOT_KDF argon2id (default; OWASP 2023 baseline m=19456, t=2, p=1) or sha256-rounds-1k for backward compatibility.

When neither variable is set, snapshots are written unencrypted (the original v0.1.0 behaviour). Existing snapshots written under one KDF keep their original KDF tag; use linpodx snapshot key-rotate and linpodx snapshot re-encrypt-all to migrate the on-disk corpus. Inspect a single snapshot with:

linpodx snapshot encryption-status <snapshot_id>

Troubleshooting

Common first-run snags:

  • daemon: connection refused — start the daemon (linpodx-daemon &).
  • podman: command not found / version too old — install Podman 4.6.0+ for your distro.
  • linpodx-gui exits with a libwebkit2gtk / libgtk-3 error — install the WebKitGTK 4.1 + GTK 3 runtime libraries listed under Prerequisites.
  • snapshot decryption failed — match the same LINPODX_SNAPSHOT_ENCRYPT_PASSPHRASE / LINPODX_SNAPSHOT_KEY / LINPODX_SNAPSHOT_KDF the snapshot was created with.
  • plugin signature rejected — install the publisher's public key under ~/.config/linpodx/plugins/keys/, or set LINPODX_ALLOW_UNSIGNED_PLUGINS=1 for local development.
  • Container starts but has no network egress — the active sandbox profile is in network: kind: allowlist; widen it or run without --sandbox.

See docs/TROUBLESHOOTING.md for the full list (daemon connectivity, podman runtime, GUI startup, snapshot encryption + key-rotation, plugin signatures + revocation, remote daemon mTLS + pinning, cluster leader routing, sandbox approvals).

Security

linpodx defaults to rootless Podman and local Unix-socket IPC. Optional features such as the netfilter helper, remote daemon listener, mTLS, certificate pinning, host mounts, and plugin loading expand the trust boundary; enable them deliberately and review SECURITY.md for reporting guidance.

License

MIT - Kim DaeHyun (kernalix7@kodenet.io)

About

Linux pod system for Linux

Resources

Code of conduct

Contributing

Security policy

Stars

2 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages