pbox 0.1.17

Disposable Proxmox LXC workspaces for development
pbox-0.1.17 is not a library.

pbox

Linux development environments on Proxmox. Create a box from a container image, install tools with Ansible recipes, and open a shell or desktop.

Quick start · Configuration · Relay setup · Recipes · Help

Quick start

Run the commands below on the Linux machine where you want to use pbox. A box is a Linux container running on Proxmox VE (PVE).

1. Check the requirements

Component Needed for
Proxmox VE Running boxes on a standalone node or cluster
Proxmox API token Giving pbox access to the nodes, containers and storage it manages
Network bridge Connecting boxes to a network with addressing, DNS and access to package repositories
Storage Container disks (rootdir) and uploaded templates (vztmpl); these can use different storage pools
Podman and Git Preparing images locally and downloading recipes
Ansible Applying recipes; ansible-playbook must be available locally
TigerVNC viewer Opening a desktop; optional for shell-only use

The default box network uses DHCP. A bridge alone does not supply DHCP or DNS. See network configuration for static addresses and direct or relay access.

2. Install

Install the CLI and guest agent with cargo-binstall:

cargo binstall pbox pbox-agent

Prebuilt binaries are available for x86-64 Linux and work with glibc or musl. Alternatively, compile the CLI and agent with Rust and a C toolchain:

cargo install --locked pbox pbox-agent

Cargo builds for the current machine. The agent must also match the guest's CPU architecture and libc; use the prebuilt agent for Alpine, or see agent builds.

Install Rust and a C toolchain, then:

git clone https://github.com/kierandrewett/pbox.git
cd pbox
cargo install --locked --path crates/pbox-cli
cargo install --locked --path crates/pbox-agent

Keep ~/.cargo/bin on your PATH. Both binaries are needed. Pbox copies pbox-agent into boxes automatically. It looks beside the CLI binary, or uses an explicit path:

pbox config set agent.binary /absolute/path/to/pbox-agent

3. Connect to Proxmox

Create an API token, then run:

pbox setup

The wizard asks for credentials and discovers nodes, storage and bridges.

Value Expected format Example
API URL HTTPS address of the PVE API https://pve.example.com:8006
Token ID USER@REALM!TOKEN_NAME pbox@pve!cli
Token secret The separate value shown when creating the token Paste into the hidden prompt
Node A PVE node name, or auto Select from the wizard
Rootfs storage Storage supporting container disks Select from the wizard
Template storage Storage supporting container templates May differ from rootfs storage
Bridge The network to attach new boxes to Select the bridge for your setup

Expected result: Configuration saved and PVE connection verified. This checks API access; creating a box also needs allocation and storage permissions. Permissions and configuration details.

4. Choose the connection path

Your setup Connection
Pbox can reach guest addresses on a LAN, routed network or VPN Direct. Guest SSH is used during initial setup; later sessions use the agent.
Pbox cannot reach guest addresses, but both pbox and the boxes can reach a relay Relay. Follow relay setup before creating a box.
Boxes have no outbound route or working DNS Configure the guest network first; a relay still needs to be reachable.

[!IMPORTANT] Reaching the Proxmox web interface does not imply that pbox can reach a box. A relay provides guest access; pbox still connects to the Proxmox API separately.

For an existing relay, obtain its URL and key file from whoever operates it:

pbox config set relay.url https://relay.example.com
pbox config set relay.key-file /absolute/path/to/relay.key
pbox relay check

For a new relay, generate a key and deploy the service, then run the check. Generating a key alone does not start a relay.

5. Create a box and open a shell

pbox new --image debian:13
pbox list
pbox ssh current

Pbox waits for the guest agent before completing creation. Press Ctrl-] to detach and keep your shell running. Reconnect with the same command. Type exit to end the shell; the box keeps running.

current selects the only box. With several boxes, use a pbx_ ID or unique name from pbox list. Shell access uses pbox's agent; you do not need to configure a separate SSH login.

Illustrative output; IDs, addresses and installed tools will differ.

$ pbox list
ID            STATE    PING  NODE  IPV4          NAME           IMAGE
pbx_d7ky95gz  running  ok    pve   172.30.0.134  pbox-d7ky95gz  docker.io/library/debian:13

$ pbox ssh current
> Connected to pbx_d7ky95gz · main
  Ctrl-] detaches. Type exit to end this shell.
[pbox@pbox-d7ky95gz ~]$

6. Install tools

pbox recipe list
pbox recipe apply --box-id current dev/base language/rust

Recipes run in the order given. Browse pbox-recipes for languages, browsers, IDEs and coding agents. Recipe logs and recovery.

For a desktop, install a desktop recipe and open the viewer:

pbox recipe apply --box-id current desktop/xfce
pbox desktop current

This opens a local TigerVNC window. Closing it leaves applications running. Desktop requirements and sessions.

Everyday commands

Replace BOX with an ID, unique name or current.

Task Command
List boxes pbox list
Inspect a box, including CPU, memory and disk allocation pbox info BOX
Open or resume your shell pbox ssh BOX
Run a command pbox exec BOX -- uname -a
Copy a file into a box pbox scp ./file.txt BOX:/tmp/file.txt
Reach an app on port 3000 pbox forward BOX 3000
Stop / start / restart pbox stop BOX / pbox start BOX / pbox restart BOX
Delete pbox rm BOX
Find images pbox image search debian
List image tags pbox image tags debian

pbox list uses a background inventory cache; changes can take a refresh to appear. Use pbox COMMAND --help for options and --json for structured results where supported.

Terminal sessions

pbox ssh BOX opens your main shell. If the connection drops, run it again and carry on where you left off. Ctrl-] detaches; exit ends the shell. The connection message and terminal title identify the session.

The application gets the full terminal, including its normal scrolling, text selection, clickable links, mouse input and cursor settings. pbox does not draw a bar over interactive sessions, capture the wheel, add scroll shortcuts or enter its own alternate screen. Native scrollback stays in the same terminal when you detach.

Use --read-only to watch without sending input, resizing the guest, or taking over another connection. Ctrl+C exits the viewer and leaves the session running. The read-only viewer shows CPU, RAM and disk usage in its bottom row.

Task Command
Open a separate terminal pbox ssh BOX:build
Watch without taking control pbox attach BOX:build --read-only
Update the guest agent pbox agent update BOX
List terminals and foreground programs across all boxes pbox session list
List terminals in one box pbox session list BOX
Read the screen and retained history pbox session read BOX:build --history
End a terminal and its processes pbox session close BOX:build

The list shows the current directory and foreground process chain, such as codex [1234] · bash. pbox --json session list also includes process IDs and parent IDs. Older terminal supervisors show only the original command until they can update without ending existing sessions.

A separate terminal supervisor keeps shells and programs running during agent updates; tmux is not required. Reconnect with pbox attach BOX:build after an interrupted connection. Attaching moves the session from its previous connection. Stopping the box or its terminal supervisor ends the sessions.

[!NOTE] Update survival works with systemd and pbox’s minimal guest init. Sessions created by older agents still defer their first update until you close them. Other init setups also defer updates while sessions are running.

SSH and session control commands check for agent updates before connecting. pbox agent update BOX performs the same update without opening a shell; use --json for a result a script can inspect. Updates use the local pbox-agent binary. Session listing and read-only viewing never update the guest.

[!WARNING] To end legacy terminals blocking an update, run pbox agent update BOX --kill-sessions. It lists the affected sessions and asks for confirmation. Add --yes for non-interactive use. This stops their running programs and may lose unsaved work; normal updates preserve sessions.

pbox ssh BOX -- COMMAND still runs a one-off command. Add --session NAME to keep that command in a named terminal. Working directory, user and environment options apply when a session is created; reconnecting keeps its existing shell.

BOX:NAME works with session start, read, send and close. The separate BOX NAME form and SSH’s --session NAME option also work. Closing shows the box, session, command, user and starting directory before asking for confirmation.

Control a session from a script or agent

These commands work with pipes and TERM=dumb. No local terminal emulator is needed.

pbox session start BOX:codex -- codex
pbox session read BOX:codex
pbox session send BOX:codex --text "Explain this project"
pbox session send BOX:codex --key Enter
pbox --json session read BOX:codex
Command Result
start BOX NAME -- COMMAND Creates a detached terminal; an existing name is an error
read BOX NAME Prints the current screen as plain text
send BOX NAME --text TEXT Types or pastes text; does not add Enter
send BOX NAME --key KEY Presses a key, such as Enter, Escape, Up or Ctrl+C
send BOX NAME --stdin Reads text from a pipe, up to 64 KiB

Repeat --key for a sequence. When combined, text is sent before keys. Reads and sends leave any SSH attachment in place. read shows the current screen, not a full output log; its JSON includes dimensions and a zero-based cursor position. send acknowledges input accepted by the agent; read again to see the application's response. If a send loses its connection, check the screen before repeating it to avoid sending the same input twice.

The agent handles terminal queries while detached. You can still attach at any time with pbox ssh BOX --session NAME.

Save an environment

Snapshot Checkpoint
Purpose Create new boxes from a saved environment Roll back the same box
Lifetime Independent of the source box Deleted with the box
Storage Full copy in Proxmox Requires native snapshot support
pbox snapshot create current --name tools-ready
pbox new --snapshot tools-ready

pbox checkpoint create current before-change

Snapshot capture stops the source while copying; save work first. Capture, restore and recovery.

Shell completion

For Zsh, add to ~/.zshrc:

source <(pbox completions zsh)

For Bash, add to ~/.bashrc:

source <(pbox completions bash)

For Fish, run once:

mkdir -p ~/.config/fish/completions
pbox completions fish > ~/.config/fish/completions/pbox.fish

Updates

pbox update installs the latest published CLI through cargo-binstall or Cargo.

Pbox checks for published updates before selected commands and caches successful checks for a day. Network failures are silent. Set PBOX_NO_UPDATE_CHECK=1 to disable checks. The CLI update does not update the local agent binary or relay; pbox ssh compares the guest agent with the local binary before connecting. It defers agent updates while terminal sessions are running. End those sessions first to allow the update on your next connection.

Troubleshooting

Problem Next step
pbox-agent binary was not found Install the agent or set agent.binary; see installation.
PVE rejects credentials or permissions Check the full token ID, secret and user/token permissions.
Box has no address Check bridge, DHCP or static addressing in networking.
Creation stops while waiting for the agent Inspect the box in PVE, correct the reported problem, then run pbox repair BOX.
Relay check fails Check the URL, running service and matching key using the relay guide.
Recipe fails Read the saved log path or rerun with --verbose; see recipes.
Desktop will not start Check local viewer and guest session requirements in desktop help.

Report an issue with the command, pbox version or source commit, guest image and relevant error output. Remove credentials from logs before sharing them.

License

Mozilla Public License 2.0.