Run dynadock + Caddy environments in isolated VMs created by libvirt/KVM.
Project description
dockvirt
Create lightweight, isolated development environments with a single command.
dockvirt is a CLI tool that automates the process of creating virtual machines (VMs) using libvirt/KVM. It allows you to instantly run applications in Docker containers, with a pre-configured Caddy reverse proxy, fully isolated from your host operating system.
๐ค Why dockvirt?
The idea for dockvirt was born from the daily problems of developers working on their workstations. The main challenges it solves are:
๐ซ Problem: Port Conflicts on Your Workstation
# A typical developer situation
docker run -p 3000:3000 frontend-app # Port 3000 is busy
docker run -p 8080:8080 backend-app # Port 8080 is busy
docker run -p 5432:5432 postgres # Port 5432 is busy
# Local services on your system also use ports!
โ Solution: Full Isolation in a VM
# With dockvirt, each application gets its own VM
dockvirt up --name frontend --domain frontend.local --image nginx:latest --port 80
dockvirt up --name backend --domain backend.local --image httpd:latest --port 80
dockvirt up --name db --domain db.local --image postgres:latest --port 5432
# Each VM has its own port space - zero conflicts!
๐ฏ Key Advantages of the Solution:
- Eliminates Port Conflicts: Each application runs in a separate VM with its own network space.
- Isolates Environments: Different versions of Node.js, Python, and databases without dependency conflicts.
- Protects the Host System: Experiments in a VM do not affect the stability of your workstation.
- Simplifies Networking: Precise domains instead of memorizing ports.
- Allows Easy Switching: Quickly bring different projects
upordown. - It's Lightweight and Fast: Cloud-init + automatic images = a quick start.
- Gives You Full Control: Based on libvirt for advanced configuration possibilities.
๐ Comparison with Other Tools
| Tool | Key Advantages | Key Disadvantages |
|---|---|---|
| dockvirt | Full isolation (VM), simplicity, automation | Requires KVM (Linux only) |
| Docker Compose | Speed, simplicity, high popularity | No full isolation from the host system |
| Vagrant | Support for multiple providers, flexibility | Slower start, more complex configuration |
| Multipass | Very simple to use, good integration with Ubuntu | Limited control, strong ties to Canonical |
๐ Key Features
- End-to-End Automation: Create, configure, and destroy VMs with simple commands.
- Universal: Works on popular Linux distributions (Ubuntu, Fedora, and more).
- Flexibility: Full control over VM configuration (RAM, CPU, disk).
- Pre-configured Environment: Automatic installation of Docker and Caddy inside the VM.
- Isolation: Each environment runs in a separate virtual machine.
๐ง Requirements
System Requirements
- A Linux operating system with KVM support (or WSL2 on Windows)
- Python 3.8 or higher
- At least 8GB RAM (for running VMs)
- 20GB+ free disk space
Required System Packages
Ubuntu/Debian:
sudo apt install -y qemu-kvm libvirt-daemon-system libvirt-clients bridge-utils \
cloud-image-utils virt-install docker.io wget
Fedora/CentOS/RHEL:
sudo dnf install -y qemu-kvm libvirt libvirt-client virt-install \
cloud-utils docker wget
Arch Linux:
sudo pacman -S qemu-full libvirt virt-install bridge-utils \
cloud-image-utils docker wget
Post-Installation Setup
# Start and enable libvirt service
sudo systemctl start libvirtd
sudo systemctl enable libvirtd
# Add user to required groups
sudo usermod -aG libvirt $USER
sudo usermod -aG docker $USER
# Log out and back in for group changes to take effect
๐ฆ Installation
Quick Install (Automated)
We provide an installation script that handles all dependencies:
# Download and run the installer
curl -sSL https://raw.githubusercontent.com/dynapsys/dockvirt/main/scripts/install.sh | bash
# Or clone and install manually
git clone https://github.com/dynapsys/dockvirt.git
cd dockvirt
sudo ./scripts/install.sh
Manual Installation
๐ง Linux (Native)
-
Install system dependencies (see Requirements section above)
-
Install from PyPI (recommended):
pip install dockvirt
-
Or install from the repository (for developers):
git clone https://github.com/dynapsys/dockvirt.git cd dockvirt pip install -e .
-
Verify installation:
dockvirt check # Check system dependencies dockvirt --help # Show available commands
๐ช Windows (WSL2)
dockvirt works perfectly on WSL2, solving port conflict issues between Windows and your development applications:
-
Install WSL2 with Ubuntu:
# In PowerShell as Administrator wsl --install -d Ubuntu-22.04
-
In WSL2, install the dependencies:
# Update the system sudo apt update && sudo apt upgrade -y # Install all required dependencies sudo apt install -y qemu-kvm libvirt-daemon-system libvirt-clients bridge-utils \ cloud-image-utils virt-install docker.io wget # Configure services sudo systemctl start libvirtd sudo systemctl enable libvirtd sudo usermod -aG libvirt $USER sudo usermod -aG docker $USER # Add your user to the required groups sudo usermod -a -G libvirt,kvm $USER newgrp libvirt # Install dockvirt pip install dockvirt
-
Start libvirt:
sudo systemctl enable --now libvirtd sudo systemctl start libvirtd
๐ณ System Requirements
Linux/WSL2:
- KVM/QEMU (virtualization support)
- libvirt-daemon-system
- cloud-image-utils (
cloud-localds) - Docker (for building application images)
Checking for virtualization support:
# Check if KVM is available
lsmod | grep kvm
egrep -c '(vmx|svm)' /proc/cpuinfo # Should be > 0
๐๏ธ How It Works
VM Creation Process Flow
graph TD
A[dockvirt up] --> B{config.yaml exists?}
B -->|No| C[Create default config.yaml]
B -->|Yes| D[Load configuration]
C --> D
D --> E{OS image exists locally?}
E -->|No| F[Download image from URL]
E -->|Yes| G[Use local image]
F --> G
G --> H[Render cloud-init templates]
H --> I[Create cloud-init ISO]
I --> J[Create VM disk with backing file]
J --> K[Run virt-install]
K --> L[VM ready with Docker + Caddy]
System Architecture
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ HOST SYSTEM โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
โ dockvirt CLI โ
โ โโโ config.py (configuration management) โ
โ โโโ image_manager.py (OS image downloading) โ
โ โโโ vm_manager.py (VM creation/destruction) โ
โ โโโ cli.py (user interface) โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
โ ~/.dockvirt/ โ
โ โโโ config.yaml (default configuration) โ
โ โโโ images/ (OS image cache) โ
โ โโโ vm_name/ (cloud-init files for each VM) โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
โ libvirt/KVM โ
โ โโโ virt-install (VM creation) โ
โ โโโ virsh (VM management) โ
โ โโโ qemu-kvm (virtualization) โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
โผ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ VIRTUAL MACHINE โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
โ Ubuntu/Fedora OS + cloud-init โ
โ โโโ Docker Engine (automatically installed) โ
โ โโโ docker-compose (runs containers) โ
โ โโโ Caddy (reverse proxy on port 80/443) โ
โ โโโ App Container (Your application) โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ๏ธ Configuration
Configuration Hierarchy
dockvirt uses a layered configuration system:
- Global config (
~/.dockvirt/config.yaml) - System-wide defaults - Project config (
.dockvirtfile) - Project-specific defaults - CLI parameters - Override any defaults
Global Configuration
dockvirt automatically creates a configuration file at ~/.dockvirt/config.yaml on its first run:
default_os: ubuntu22.04
images:
ubuntu22.04:
name: ubuntu22.04
url: https://cloud-images.ubuntu.com/jammy/current/jammy-server-cloudimg-amd64.img
variant: ubuntu22.04
fedora38:
name: fedora38
url: https://archives.fedoraproject.org/pub/archive/fedora/linux/releases/38/Cloud/x86_64/images/Fedora-Cloud-Base-38-1.6.x86_64.qcow2
variant: fedora38
Note: The key os_images is also accepted for backward compatibility. The CLI merges both images and os_images automatically.
Project Configuration (.dockvirt file)
Create a .dockvirt file in your project directory:
# VM Configuration
name=my-project
domain=my-project.local
image=nginx:latest
port=80
os=ubuntu22.04
# Resource Allocation (optional)
mem=4096 # RAM in MB
disk=20 # Disk in GB
cpus=2 # Number of vCPUs
๐ฅ๏ธ Usage
๐ New Workflow - Docker Build Inside the VM
From now on, Docker images are built automatically inside the VM! You no longer need to build images on the host.
# Old way (no longer necessary):
# docker build -t my-app:latest .
# dockvirt up --image my-app:latest
# New way - just run:
cd my-project/ # directory with a Dockerfile
dockvirt up --name my-app --domain my-app.local --image my-app:latest --port 80
# The Dockerfile and your app files are automatically copied to the VM and built there!
๐ Quick Start with a .dockvirt File
The easiest way is to create a .dockvirt file in your project directory (like an .env file):
# Create the .dockvirt file
cat > .dockvirt << EOF
name=my-app
domain=my-app.local
image=my-app:latest
port=80
os=ubuntu22.04
mem=4096
disk=20
cpus=2
EOF
# Now, just run (in the directory with the Dockerfile):
dockvirt up
๐ง Or Use CLI Parameters
# Use the default OS (ubuntu22.04)
dockvirt up \
--name my-app \
--domain my-app.local \
--image nginx:latest \
--port 80
# Or choose a specific OS
dockvirt up \
--name fedora-app \
--domain fedora-app.local \
--image httpd:latest \
--port 80 \
--os fedora38
๐ Accessing Your Application
After creating the VM, dockvirt will display its IP address. Add it to your /etc/hosts file:
<ip_address> my-app.local
Tip: If you use a reverse proxy (Caddy) inside the VM, IP-based checks may require a Host header. You can verify with:
curl -H 'Host: my-app.local' http://<ip_address>/
๐ Getting the VM IP address
Use the built-in ip subcommand:
dockvirt ip --name <vm_name>
Note: The VM image installs and enables qemu-guest-agent, so IP detection works with both NAT and bridged networking.
๐ Networking: NAT vs Bridge (LAN)
By default, VMs use libvirt NAT (network=default). To expose a VM directly in your LAN, use a Linux bridge (e.g., br0) and run with --net bridge=br0.
- One-time (Fedora/NetworkManager) bridge creation example:
sudo nmcli con add type bridge ifname br0 con-name br0
sudo nmcli con add type bridge-slave ifname enp3s0 master br0
sudo nmcli con modify br0 ipv4.method auto ipv6.method auto
sudo nmcli con up br0
- Per-VM:
dockvirt up --net bridge=br0
- Or persist at project level by adding to
.dockvirt:
net=bridge=br0
With bridge networking, the VM receives a LAN IP and is visible to other machines on your network.
The .dockvirt file has priority over the default parameters, but CLI parameters override everything.
๐ฅ Advanced Usage Examples
๐ Example 1: Multi-Tenant SaaS Platform
Scenario: Each SaaS customer gets a completely isolated application instance in a separate VM.
# First build your application image
docker build -t myapp:v2.1 .
# Customer A
dockvirt up --name client-a --domain client-a.myaas.com --image myapp:v2.1 --os ubuntu22.04
# Customer B (using different image version)
dockvirt up --name client-b --domain client-b.myaas.com --image nginx:latest --os fedora38
# Customer C (beta tester)
dockvirt up --name client-c --domain beta.myaas.com --image myapp:v2.1 --os ubuntu22.04
Result:
- โ Zero conflicts between customers
- โ Different application versions for different customers
- โ Full data and resource isolation
- โ Automatic SSL/TLS for each domain
๐ Example 2: Development Environment as Code
Scenario: The entire development team gets identical environments with a single command.
# .dockvirt-stack (multi-app)
stack:
frontend:
image: myapp-frontend:latest
domain: app.dev.local
os: ubuntu22.04
backend:
image: myapp-api:latest
domain: api.dev.local
os: ubuntu22.04
database:
image: postgres:15
domain: db.dev.local
os: fedora38
# Note: Stack deployment is a planned feature
# For now, create individual VMs:
# Developer One
dockvirt up --name dev-john-frontend --domain app.dev-john.local --image myapp:latest --port 3000
dockvirt up --name dev-john-api --domain api.dev-john.local --image myapp:latest --port 8080
# Developer Two
dockvirt up --name dev-jane-frontend --domain app.dev-jane.local --image myapp:latest --port 3000
dockvirt up --name dev-jane-api --domain api.dev-jane.local --image myapp:latest --port 8080
๐ Detailed Examples
We have prepared several practical examples to show you the possibilities of the new, simplified API:
- Example 1: Static Nginx Website - Basic usage with automatic image downloading
- Example 2: Python Flask Web App - An application with an Ubuntu vs. Fedora comparison
- Example 3: Operating System Comparison - Configuring custom images and performance testing
Each example now uses the new, simplified API - you no longer need to provide image paths or OS variants!
๐จ Troubleshooting
โ "cloud-localds: command not found"
# Install the missing package
sudo apt install cloud-image-utils
# Or on RPM-based systems
sudo dnf install cloud-utils
โ Permission denied when accessing libvirt
# Add your user to the libvirt group
sudo usermod -a -G libvirt $USER
newgrp libvirt
# Restart the service
sudo systemctl restart libvirtd
โ Permission denied writing ~/.dockvirt/*.qcow2 or cidata.iso (qemu:///system)
When using the system libvirt (qemu:///system), VMs run as the qemu user and must be able to traverse your home and read VM files. On Fedora/SELinux you may also need proper labels.
Fix (safe to apply):
# Allow qemu to traverse your home
sudo setfacl -m u:qemu:x "$HOME"
# Give qemu read access on dockvirt files
sudo setfacl -R -m u:qemu:rx "$HOME/.dockvirt"
sudo find "$HOME/.dockvirt" -type f -name '*.qcow2' -exec setfacl -m u:qemu:rw {} +
sudo find "$HOME/.dockvirt" -type f -name '*.iso' -exec setfacl -m u:qemu:r {} +
# SELinux labels (Fedora/SELinux)
# IMPORTANT: Label only image files, not the entire directory
# If you previously labeled the whole tree, remove that rule first:
# sudo semanage fcontext -d -t svirt_image_t "$HOME/.dockvirt(/.*)?"
sudo semanage fcontext -a -t svirt_image_t "$HOME/.dockvirt(/.*)?\\.qcow2"
sudo semanage fcontext -a -t svirt_image_t "$HOME/.dockvirt(/.*)?\\.iso"
sudo restorecon -Rv "$HOME/.dockvirt"
Tips:
- Always connect virsh to the system libvirt with:
virsh --connect qemu:///system <subcommand>. - Alternatively, configure a libvirt storage pool (e.g.
/var/lib/libvirt/images/dockvirt) and store VM files there to avoid ACLs on$HOME.
โ qemu-img "Failed to get write lock"
This usually happens after an interrupted run that left a domain or disk around. Fix:
# Tear down the VM if it exists
dockvirt down --name <vm_name>
# Or auto-heal common leftovers
make heal
Then try dockvirt up again.
โ KVM not available
# Check if virtualization is enabled in your BIOS
egrep -c '(vmx|svm)' /proc/cpuinfo
# On WSL2, make sure Hyper-V is enabled
# In PowerShell as Administrator:
# Enable-WindowsOptionalFeature -Online -FeatureName Microsoft-Hyper-V -All
โ Port conflicts on Windows + WSL2
# Check which ports Windows is using
netstat -an | findstr LISTENING
# In WSL2, all VMs have isolated ports
dockvirt up --name app1 --domain app1.local --image nginx --port 80
dockvirt up --name app2 --domain app2.local --image apache --port 80
# Both run without conflicts!
๐ฉบ Dockvirt Doctor & Dev venv (PEP 668)
Use Dockvirt Doctor to diagnose and optionally fix environment issues. This is especially helpful on Homebrew Python (PEP 668 externally-managed environments).
# Quick diagnostics
make doctor
python3 scripts/doctor.py --summary
# Detailed logging + file log
python3 scripts/doctor.py --verbose --log-file ~/.dockvirt/doctor.log
# Auto-fix common issues (may require sudo and re-login for groups)
make doctor-fix
Avoid running make ... with sudo. Doctor already detects SUDO_USER and acts on your real home (/home/<user>), but invoking make with sudo may lead to confusing paths and permissions.
Development install with a virtualenv (PEP 668 friendly)
# Use your preferred Python (example shows 3.13)
PY=$(command -v python3.13 || command -v python3)
# Create a venv that can access system packages (e.g. python3-libvirt)
$PY -m venv --system-site-packages .venv-3.13
source .venv-3.13/bin/activate
# Install the project without forcing libvirt-python from pip
pip install -U pip setuptools wheel
pip install -e . --no-deps
pip install jinja2 click pyyaml
# Verify and diagnose
python -m dockvirt.cli --help
python3 scripts/doctor.py --summary
Ensure libvirt default network is active
sudo systemctl enable --now libvirtd
sudo virsh net-define /usr/share/libvirt/networks/default.xml || true
sudo virsh net-start default || true
sudo virsh net-autostart default
Tip: The CLI runs a preflight network check and will print hints if the default network is missing or inactive.
๐ค Automation Agent
Use the built-in Automation Agent to validate your setup end-to-end, including domain reachability. It can optionally apply safe fixes (ACL/SELinux for qemu:///system and /etc/hosts entries) using sudo.
# Summary mode (no sudo changes): tests examples, prints report
make agent
# Auto-fix mode (sudo): doctor --fix, default network, ACL/SELinux, /etc/hosts
make agent-fix
# Filter examples, skip host Docker build (image built inside VM)
PY=.venv-3.13/bin/python \
$PY scripts/agent.py run --example 1-static-nginx-website --skip-host-build
# Select OS variants to test
$PY scripts/agent.py run --os ubuntu22.04 --os fedora38 --skip-host-build
# Report location
cat agent_report.md
Optional local LLM remediation: you can enable a small local model (via Ollama) to propose and apply safe fixes automatically.
export DOCKVIRT_USE_LLM=1
# Optional model selection (default: llama3.2:3b)
export DOCKVIRT_LLM_MODEL=llama3.2:3b
make agent-fix
Note: Do not run sudo make agent-fix. The agent will request sudo where needed and stream commands in the console.
What it does:
- Creates VMs with
dockvirt upper example and OS variant. - Fetches VM IP via virsh leases and checks HTTP by IP.
- Verifies local DNS for domain (from
.dockvirt) and checks HTTP via domain. - Optionally appends to
/etc/hosts(auto mode) when a domain doesnโt resolve. - Cleans up VMs with
dockvirt down.
๐พ Generating Images and Packages
๐ฆ Distribution Packages (.deb/.rpm)
Note: Image generation is a planned feature, not yet implemented
# These commands are planned for future releases:
# dockvirt generate-image --type deb-package --output my-app.deb
# dockvirt generate-image --type rpm-package --output my-app.rpm
# For now, use standard VM deployment:
dockvirt up --name production-app --domain app.local --image nginx:latest --port 80
๐ฅง Raspberry Pi SD Card Image
Note: Raspberry Pi support is planned for future releases
# This feature is planned for future releases:
# dockvirt generate-image --type raspberry-pi --output rpi-dockvirt.img
# For now, use standard x86_64 deployment
๐ป PC Bootable ISO
Note: ISO generation is planned for future releases
# This feature is planned for future releases:
# dockvirt generate-image --type pc-iso --output production-server.iso
Example production-stack.yaml:
apps:
frontend:
image: mycompany/frontend:v2.1
domain: app.company.com
port: 3000
api:
image: mycompany/api:v2.1
domain: api.company.com
port: 8080
monitoring:
image: grafana/grafana:latest
domain: monitoring.company.com
port: 3000
config:
auto_start: true
ssl_enabled: true
backup_enabled: true
๐ข Podman Support
# Use Podman instead of Docker
export DOCKVIRT_RUNTIME=podman
dockvirt up --name my-app --image nginx:latest
# Or in the .dockvirt file
runtime=podman
name=my-app
image=nginx:latest
๐ ๏ธ Development
The repository contains a Makefile to facilitate the development process. See the CONTRIBUTING.md file to learn how to contribute to the project's development.
If you're developing locally inside this repository, prefer using the project virtualenv to avoid conflicts with system or Homebrew installations:
make install
.
venv-3.13/bin/dockvirt --help
# If your PATH resolves to another dockvirt (e.g., Homebrew), use the venv binary explicitly:
which dockvirt
./.venv-3.13/bin/dockvirt up
โ๏ธ Author
Tom Sapletta - An experienced programmer and open-source enthusiast. Passionate about automation and creating tools that make developers' lives easier.
๐ License
This project is licensed under the Apache 2.0 License. See the LICENSE file for details.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file dockvirt-0.1.9.tar.gz.
File metadata
- Download URL: dockvirt-0.1.9.tar.gz
- Upload date:
- Size: 39.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
11b08d1a59131e66237b9da0a9dff866060a60f49e29af2a2a8e86e166062c97
|
|
| MD5 |
6be2a9652d6ddc328ff3f54f4bd52314
|
|
| BLAKE2b-256 |
2eca4107f3fe234ba1d8f05f0d7656c70e903ac548e1238663b63d904293a1de
|
File details
Details for the file dockvirt-0.1.9-py3-none-any.whl.
File metadata
- Download URL: dockvirt-0.1.9-py3-none-any.whl
- Upload date:
- Size: 34.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
431b51e75f674f7d458bd21c7343f6a11614a3bda320a221d5b8c452cace1c6f
|
|
| MD5 |
e6b23af00557d232d06b1213b3c92333
|
|
| BLAKE2b-256 |
7343dbfeabc2ff820c281c05172b0b57b6d0d79a4d3d8f8f9d33961dd4637c51
|