Wren Linux

wren-linux / vendor / mockvps-kvm / README.md (as plain text)

mockvps-kvm

Spin up a disposable Debian "VPS" on your own machine with QEMU/KVM. One script, one qemu-system-x86_64 process, plain files. No libvirt daemon, no VirtualBox, no GUI.

$ ./mockvps-kvm.sh        # unattended Debian install, typically 5-15 minutes
$ ssh mockvps-kvm         # key-only login, ready to use

Use it to try out server setup scripts, practice sysadmin tasks, test Ansible playbooks, or run a throwaway web server, then delete every trace with one command.

Features

Requirements

The script adds your user to the kvm group if needed (uses sudo). It does not need to run as root.

Quick start

In Wren Linux, bash extras/mockvps-kvm.sh installs what it needs and a mockvps-kvm command, so below ./mockvps-kvm.sh is simply mockvps-kvm. Inside a Wren Linux folder the script refuses to run directly until that setup is done (it prints what to run; MOCKVPS_FORCE=1 overrides). A copy of the script on its own, outside Wren Linux, works straight from its folder:

./mockvps-kvm.sh                 # install and wait for SSH
ssh mockvps-kvm                  # log in (dedicated key, ~/.ssh/config entry added)
cat ~/vpskvm/credentials/mockvps-kvm.env   # the guest's sudo password

Day-to-day:

./mockvps-kvm.sh --stop          # graceful power off
./mockvps-kvm.sh --start         # boot it again
./mockvps-kvm.sh --status
./mockvps-kvm.sh --uninstall     # remove everything (asks first)

By default the guest gets 2 vCPUs, 2 GiB RAM and a 20 GB disk, and an SSH tunnel makes the guest's port 80 available at http://localhost:8080 while an ssh mockvps-kvm session is open.

Viewing a website from your host

The VM is headless, so you browse from your own machine. The script sets up an SSH tunnel for this: http://localhost:8080 on your host reaches port 80 in the guest.

ssh mockvps-kvm                          # keep this session open
# inside the VM:
sudo apt-get install -y apache2          # or nginx, etc.
# on your host, in any browser:
#   http://localhost:8080

By default nothing is exposed to your network: the tunnels listen on your host's loopback only (unless you changed -k or your own SSH settings).

Provisioning

cloud-init (--user-data)

Use a normal #cloud-config file. It is seeded as the NoCloud datasource during the install, and the script waits for cloud-init to finish before reporting the VM ready. It applies to fresh installs only.

#cloud-config
package_update: true
packages: [nginx, git]
write_files:
  - path: /var/www/html/index.html
    content: "hello from mockvps"
runcmd:
  - systemctl enable --now nginx
./mockvps-kvm.sh --user-data my-config.yaml
# then browse http://localhost:8080 while `ssh mockvps-kvm` is open

Notes:

Install extra packages (-P)

./mockvps-kvm.sh -P git -P curl -P htop

The Debian installer installs them. Repeatable, fresh installs only.

SSH provisioner (--provision)

Run one or more bash scripts as root inside the guest once SSH is up:

./mockvps-kvm.sh --provision setup-base.sh --provision setup-app.sh

Iterate on a script against a running VM without reinstalling:

./mockvps-kvm.sh --provision-only --provision setup-app.sh

Snapshots

Snapshots are qcow2 internal snapshots of the disk. The VM is powered off for the operation (the script asks, then boots it again if it was running). They capture disk state only, not RAM.

./mockvps-kvm.sh --snapshot before-upgrade
# ... break things ...
./mockvps-kvm.sh --restore before-upgrade      # asks first; everything written since is lost
./mockvps-kvm.sh --snapshots                   # list
./mockvps-kvm.sh --delete-snapshot before-upgrade

Names are 1-64 characters from A-Za-z0-9_.-, not starting with - or .. A restore keeps the snapshot, so you can roll back to it again.

Options

OptionDefaultMeaning
-n, --name NAMEmockvps-kvmVM name (also the ssh host alias)
-u, --user USERvpsGuest user
-p, --port PORT2232Host port for the SSH forward
-c, --cpus N2vCPUs
-m, --memory MIB2048RAM in MiB
-d, --disk MB20000Disk size in MB
-w, --workdir DIR~/vpskvmState directory (no spaces)
-s, --suite NAMEstableDebian release, e.g. trixie
-f, --forward L:GAlso tunnel host port L to guest port G over SSH (repeatable, L 1024-65535)
-k, --ip IP127.0.0.1Bind the SSH forward to another address (you are warned and asked to confirm)
--no-web-tunnelSkip the default 8080 -> guest:80 tunnel
--user-data FILEcloud-init user-data (fresh install)
-P, --package NAMEExtra package for the installer (repeatable, fresh install)
--provision FILEScript to run as root in the guest (repeatable)
--https-mirroroffInstaller fetches packages over https
--require-signatureoffRefuse to continue unless the netboot checksums are GPG-authenticated
-y, --yesNon-interactive: confirm all prompts
-h, --helpFull help

Management actions (use exactly one):

ActionMeaning
--start / --stop / --statusBoot headless / graceful ACPI power off / is it running?
--provision-onlyRun the --provision files against the running VM
--snapshot NAME / --restore NAME / --snapshots / --delete-snapshot NAMESnapshots
--uninstall (alias --remove)Remove every trace of the VM
--uninstall --dry-runOnly list what would be removed
--uninstall --purge-softwareAlso purge the QEMU packages and drop your kvm group membership. QEMU keeps no registry of other users, so only use this if nothing else on the host uses QEMU.

Environment variables

Every option has an environment equivalent; flags win.

VM_NAME, VM_USER, SSH_HOST_PORT, VM_VCPUS, VM_MEMORY, VM_DISK_SIZE_MB, WORKDIR, DEBIAN_SUITE, SSH_HOST_IP, WEB_TUNNEL=0|1, FORWARDS="8443:443,3000:3000", USER_DATA=FILE, PACKAGES="git,curl", PROVISION_FILES="a.sh:b.sh", PROVISION_ONLY=1, DEBIAN_MIRROR_PROTO=http|https, REQUIRE_SIGNATURE=1, UNINSTALL=1, DRY_RUN=1, PURGE_SOFTWARE=1, START=1, STOP=1, STATUS=1, VM_PASSWORD (see below).

Installer stall detection: INSTALL_STALL_WARN (default 180 s) and INSTALL_STALL_ABORT (default 600 s). MOCKVPS_QEMU selects a different QEMU binary.

Security model

Where things live

PathContents
~/vpskvm/<name>.qcow2Guest disk (and its snapshots)
~/vpskvm/credentials/<name>.envGuest sudo password (0600)
~/vpskvm/<name>-install.log, -run.logSerial console logs
~/vpskvm/boot/, run/Netboot files; QEMU pidfile and monitor socket
~/.ssh/<name>_id (+ .pub)Dedicated SSH key
~/.ssh/configA managed block between # BEGIN/END mockvps-kvm:<name> markers (a .mockvps-kvm.bak backup is kept)

--uninstall removes all of the above (and the matching known_hosts entries) but never this repository.

Exit codes

0 success, 1 error, 3 the VM is up but key-only SSH login was refused (the message says how to recover using the stored password).

Troubleshooting

Limitations

License

MIT