vagrant

Disposable VMs for safe testing — full sudo, Docker, Go, nested KVM, destroy and recreate. Use when you need a sandbox to build, test, or break things without affecting the host. Use when the user says "spin up a VM", "test in isolation", "run with sudo", "try something dangerous", "set up a dev environment", "I need Docker", "test firewall rules", "clean environment", or needs root access, network testing, or safe experimentation.

Safety Notice

This listing is from the official public ClawHub registry. Review SKILL.md and referenced scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "vagrant" with this command: npx skills add jpoley/vagrant-skill

User Input

$ARGUMENTS

You MUST consider the user input before proceeding (if not empty).

Execution Instructions

This skill provides a disposable VM sandbox for safe development and testing. All privileged operations (sudo, iptables, Docker, systemd, KVM) happen inside the VM — the host is never modified.

You (the agent) should NEVER need host-level sudo. Instead, use this Vagrant workflow to get a fully provisioned, disposable VM where you have unrestricted root access.

Prerequisites

Before using this workflow, verify a provider is available:

# Check Vagrant is installed
command -v vagrant

# Check for a provider (any one is sufficient)
command -v prlctl        # Parallels (Mac Apple Silicon — recommended)
vagrant plugin list | grep libvirt  # libvirt (Linux — nested KVM)
command -v VBoxManage    # VirtualBox (fallback)

See references/platform-setup.md for detailed provider installation.


Core Workflow

Step 1: Create a Vagrantfile in the User's Project

If the user's project does not already have a Vagrantfile, you MUST create a real, working one in their project directory. This is not a template or example — it must work end-to-end with vagrant up.

Requirements for the Vagrantfile you create:

  • Base box: bento/ubuntu-24.04
  • Sync the project root into the VM: config.vm.synced_folder ".", "/project", type: "rsync"
  • Include all three providers (Parallels, libvirt, VirtualBox) so it works on any platform
  • Provision with the actual tools the project needs (inspect the project first — look for go.mod, package.json, requirements.txt, Makefile, Dockerfile, etc.)
  • Use set -euo pipefail in provisioning scripts
  • Make provisioning idempotent

Here is the base Vagrantfile — you MUST customize the provisioning section based on what the project actually uses:

# -*- mode: ruby -*-
# Vagrantfile — disposable dev/test VM

VM_CPUS   = Integer(ENV["VM_CPUS"]   || 4)
VM_MEMORY = Integer(ENV["VM_MEMORY"] || 4096)

Vagrant.configure("2") do |config|
  config.vm.box = "bento/ubuntu-24.04"
  config.vm.box_check_update = false
  config.vm.hostname = "dev"
  config.vm.boot_timeout = 300
  config.ssh.forward_agent = true

  # ─── Sync project into VM at /project ─────────────────────────────────────
  config.vm.synced_folder ".", "/project", type: "rsync",
    rsync__exclude: [
      ".git/", "node_modules/", "vendor/", ".vagrant/",
      "bin/", "dist/", "build/", ".next/",
    ]

  # ─── Provider: Parallels (Mac Apple Silicon — recommended) ────────────────
  config.vm.provider "parallels" do |prl|
    prl.cpus   = VM_CPUS
    prl.memory = VM_MEMORY
    prl.update_guest_tools = true
  end

  # ─── Provider: libvirt (Linux — preferred, nested KVM) ────────────────────
  config.vm.provider "libvirt" do |lv|
    lv.cpus   = VM_CPUS
    lv.memory = VM_MEMORY
    lv.cpu_mode = "host-passthrough"
    lv.nested = true
  end

  # ─── Provider: VirtualBox (cross-platform fallback) ───────────────────────
  config.vm.provider "virtualbox" do |vb|
    vb.cpus   = VM_CPUS
    vb.memory = VM_MEMORY
    vb.customize ["modifyvm", :id, "--nested-hw-virt", "on"]
  end

  # ─── Provision: install project dependencies ──────────────────────────────
  # CUSTOMIZE THIS for the project. Inspect go.mod, package.json,
  # requirements.txt, Dockerfile, Makefile, etc. and install what's needed.
  config.vm.provision "shell", privileged: true, inline: <<-SHELL
    set -euo pipefail
    export DEBIAN_FRONTEND=noninteractive
    apt-get update -qq
    apt-get install -y -qq build-essential curl git jq ca-certificates gnupg

    # ── Docker ────────────────────────────────────────────────────────────
    if ! command -v docker &>/dev/null; then
      install -m 0755 -d /etc/apt/keyrings
      curl -fsSL https://download.docker.com/linux/ubuntu/gpg \
        -o /etc/apt/keyrings/docker.asc
      chmod a+r /etc/apt/keyrings/docker.asc
      echo "deb [arch=$(dpkg --print-architecture) \
        signed-by=/etc/apt/keyrings/docker.asc] \
        https://download.docker.com/linux/ubuntu \
        $(. /etc/os-release && echo "$VERSION_CODENAME") stable" \
        | tee /etc/apt/sources.list.d/docker.list > /dev/null
      apt-get update -qq
      apt-get install -y -qq docker-ce docker-ce-cli containerd.io
    fi
    systemctl enable --now docker
    usermod -aG docker vagrant

    # ── Add project-specific tooling below ────────────────────────────────
    # Examples (uncomment / add what the project needs):
    #
    # Go:
    #   GO_VERSION="1.24.3"
    #   curl -fsSL "https://go.dev/dl/go${GO_VERSION}.linux-$(dpkg --print-architecture).tar.gz" \
    #     | tar -C /usr/local -xz
    #   echo 'export PATH="/usr/local/go/bin:$HOME/go/bin:$PATH"' > /etc/profile.d/go.sh
    #
    # Node.js:
    #   curl -fsSL https://deb.nodesource.com/setup_22.x | bash -
    #   apt-get install -y -qq nodejs
    #
    # Python:
    #   apt-get install -y -qq python3 python3-pip python3-venv

    echo "VM ready — project synced at /project"
  SHELL
end

You MUST customize the provisioning section. Read the project to determine what it needs:

  • go.mod → install Go
  • package.json → install Node.js
  • requirements.txt / pyproject.toml → install Python
  • Dockerfile → Docker is already included above
  • Network testing → add iptables dnsmasq dnsutils iproute2 net-tools
  • KVM/microVM testing → add qemu-kvm libvirt-daemon-system

Uncomment the relevant blocks and add any other tooling. Do NOT leave placeholder comments in the final Vagrantfile — produce a clean, working file.

Then add .vagrant/ to the user's .gitignore if not already present:

grep -qxF '.vagrant/' .gitignore 2>/dev/null || echo '.vagrant/' >> .gitignore

The Vagrantfile itself should be committed — it's reusable project infrastructure.

If the user already has a Vagrantfile, use it as-is unless they ask to modify it.

Step 2: Start the VM

vagrant up

This boots the VM with the user's project synced at /project inside the VM.

Step 3: Run Commands Inside the VM

All commands use vagrant ssh -c from the host. No interactive SSH needed.

# Run any command with sudo
vagrant ssh -c "sudo apt-get install -y some-package"

# Build the project
vagrant ssh -c "cd /project && make build"
vagrant ssh -c "cd /project && go test ./..."

# Docker operations
vagrant ssh -c "docker build -t myimage ."
vagrant ssh -c "docker run --rm myimage"

# Network/firewall testing
vagrant ssh -c "sudo iptables -L -n"

Step 4: Iterate on Code Changes

When you modify source on the host:

vagrant rsync                                    # sync changes to VM
vagrant ssh -c "cd /project && make build"       # rebuild
vagrant ssh -c "cd /project && make test"        # test

Step 5: Tear Down

vagrant destroy -f    # destroys VM completely, clean slate

Testing Patterns

Pattern: Build-Test-Fix Loop

vagrant rsync && vagrant ssh -c "cd /project && make build"
vagrant ssh -c "cd /project && make test"
# If tests fail, fix code on host, repeat

Pattern: Docker-in-VM

vagrant ssh -c "cd /project && docker build -t test ."
vagrant ssh -c "docker run --rm test"

Pattern: Network/Firewall Testing

vagrant ssh -c "sudo iptables -A FORWARD -s 172.16.0.0/24 -j DROP"
vagrant ssh -c "sudo iptables -L -n -v"

Pattern: bats End-to-End Tests

Run a bats-core test suite against a live VM as proof that the system under test works. The VM must be up before running bats.

vagrant up
bats test/e2e.bats      # run tests, output is the proof
vagrant destroy -f      # tear down after

Capture output to show the user:

vagrant up
bats test/e2e.bats 2>&1 | tee /tmp/bats-results.txt
vagrant destroy -f
cat /tmp/bats-results.txt

bats exits non-zero on any failure — treat that as a test run failure.

Pattern: Full Reprovision (Nuclear Option)

vagrant destroy -f && vagrant up

Configuration

Environment variables to customize the VM (set before vagrant up):

VariableDefaultPurpose
VM_CPUS4Number of vCPUs
VM_MEMORY4096RAM in MB

Example:

VM_CPUS=8 VM_MEMORY=8192 vagrant up

See references/vm-contents.md for full details on VM filesystem layout and installed software.

Safety Guarantees

  • No host sudo required — all privileged operations are inside the VM
  • Fully disposablevagrant destroy -f removes everything
  • Idempotent provisioningvagrant provision is safe to re-run
  • Isolated networking — VM has its own network stack
  • Source is rsynced — VM gets a copy; your host repo is never modified by the VM
  • No persistent state — destroying the VM removes all data
  • Vagrantfile is committed — reusable across sessions; .vagrant/ is gitignored

Examples

Example 1: Test iptables firewall rules without touching host network

User says: "I need to test some firewall rules before deploying to production"

Actions:

  1. Create Vagrantfile with iptables dnsmasq dnsutils iproute2 net-tools provisioned
  2. vagrant up
  3. vagrant ssh -c "sudo iptables -A INPUT -p tcp --dport 443 -j ACCEPT"
  4. vagrant ssh -c "sudo iptables -A INPUT -p tcp --dport 0:442 -j DROP"
  5. vagrant ssh -c "sudo iptables -L -n -v" — verify rules look right
  6. vagrant ssh -c "sudo iptables-save > /project/firewall.rules" — export if good
  7. vagrant rsync to get rules file back, or vagrant destroy -f to scrap

Result: Firewall rules iterated safely. Host network never touched. Rules exportable.

Example 2: Test systemd service configuration

User says: "I need to test this systemd unit file before deploying"

Actions:

  1. Create Vagrantfile with the project synced
  2. vagrant up
  3. vagrant ssh -c "sudo cp /project/myservice.service /etc/systemd/system/"
  4. vagrant ssh -c "sudo systemctl daemon-reload && sudo systemctl start myservice"
  5. vagrant ssh -c "systemctl status myservice" — check it works
  6. vagrant ssh -c "sudo journalctl -u myservice --no-pager" — check logs
  7. vagrant destroy -f — clean slate

Result: Service tested with real systemd, real journald. No risk to host init system.

Example 3: Docker daemon configuration and privileged port binding

User says: "I need to test a Docker compose setup that binds port 80"

Actions:

  1. Create Vagrantfile with Docker CE provisioned
  2. vagrant up
  3. vagrant ssh -c "cd /project && docker compose up -d"
  4. vagrant ssh -c "curl -sf http://localhost" — test from inside VM
  5. vagrant ssh -c "docker compose logs" — check output
  6. vagrant ssh -c "docker compose down" — cleanup
  7. vagrant destroy -f

Result: Full Docker compose stack running with privileged ports — impossible without sudo on the host.

Example 4: Run the built-in e2e examples

Three working examples live under examples/ in this skill's directory. All follow the same pattern — boot, test, tear down:

cd examples/<name>
vagrant up [--provider=<provider>]
bats test/e2e.bats 2>&1 | tee /tmp/e2e-results.txt
cat /tmp/e2e-results.txt
vagrant destroy -f

examples/nginx-hardened/ — Linux / libvirt (16 tests)

Deploys nginx + hardened iptables (INPUT DROP, allow SSH + HTTP only). Why VM: iptables -F INPUT; iptables -P INPUT DROP on the host locks you out.

cd examples/nginx-hardened
vagrant up
bats test/e2e.bats 2>&1 | tee /tmp/e2e-results.txt
vagrant destroy -f

examples/mac-docker-compose/ — Mac Apple Silicon / Parallels (14 tests)

Runs a Docker Compose stack: nginx on port 80 proxying a Python JSON API. Why VM: Docker Desktop requires a commercial license; Docker CE in a VM has none of its restrictions.

cd examples/mac-docker-compose
vagrant up --provider=parallels
bats test/e2e.bats 2>&1 | tee /tmp/e2e-results.txt
vagrant destroy -f

examples/windows-systemd-service/ — Windows WSL2 / VirtualBox (20 tests)

Deploys a Python HTTP server as a real systemd unit, running as a dedicated system user. Why VM: WSL2 does not run real systemd — unit files cannot be tested without a real Linux init.

WSL2 pre-flight:

export VAGRANT_WSL_ENABLE_WINDOWS_ACCESS="1"
export PATH="$PATH:/mnt/c/Program Files/Oracle/VirtualBox"
cd examples/windows-systemd-service
vagrant up --provider=virtualbox
bats test/e2e.bats 2>&1 | tee /tmp/e2e-results.txt
vagrant destroy -f

Troubleshooting

VM Won't Boot

Error: vagrant up hangs or times out Cause: Provider not installed or configured correctly Solution:

  1. Check provider is installed: vagrant plugin list
  2. Debug boot: vagrant up --debug 2>&1 | tail -50
  3. Try explicit provider: vagrant up --provider=virtualbox

Source Not Synced

Error: /project directory is empty or missing inside VM Cause: rsync failed or synced_folder misconfigured Solution:

  1. Re-sync: vagrant rsync
  2. Check Vagrantfile has synced_folder ".", "/project", type: "rsync"

Provider Mismatch

Error: vagrant up uses wrong provider Cause: Multiple providers installed, Vagrant auto-selects Solution:

  1. Check what's running: vagrant status
  2. Force provider: vagrant up --provider=parallels

KVM Not Available Inside VM

Error: /dev/kvm missing inside the VM Cause: Host doesn't support nested virtualization or provider not configured Solution:

  1. Ensure host has KVM: test -e /dev/kvm on host
  2. Use libvirt provider with cpu_mode = "host-passthrough"
  3. Mac: nested KVM is not available — use a Linux host for KVM workloads

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

General

OpenClaw 沙盒测试系统

OpenClaw 沙盒测试系统 v2.0 - 零风险配置变更测试,9 层防护 +5 原则,自动备份回滚,Git 版本管理

Registry SourceRecently Updated
3630Profile unavailable
Coding

xCloud Docker Deploy

Deploy any project to xCloud hosting — auto-detects stack (WordPress, Laravel, PHP, Node.js, Next.js, NestJS, Python, Go, Rust), routes to native or Docker d...

Registry SourceRecently Updated
4730Profile unavailable
Coding

Docker Compose Generator

生成 Docker Compose 配置,支持 MySQL, PostgreSQL, Redis, MongoDB, Elasticsearch 等常用服务。

Registry SourceRecently Updated
6010Profile unavailable
Coding

Self-Hosting Mastery

Complete self-hosting and homelab operating system. Deploy, secure, monitor, and maintain self-hosted services with production-grade reliability. Use when se...

Registry SourceRecently Updated
4630Profile unavailable