https://github.com/pixelkarma/rqstdev
rqstdev is a lightweight single-host VM platform. It lets users create accounts, launch QEMU-based Linux VMs from a CLI, SSH into those VMs, and expose web services on per-VM subdomains and optional published web ports.
https://github.com/pixelkarma/rqstdev
Last synced: about 1 month ago
JSON representation
rqstdev is a lightweight single-host VM platform. It lets users create accounts, launch QEMU-based Linux VMs from a CLI, SSH into those VMs, and expose web services on per-VM subdomains and optional published web ports.
- Host: GitHub
- URL: https://github.com/pixelkarma/rqstdev
- Owner: pixelkarma
- Created: 2026-05-13T23:00:15.000Z (about 2 months ago)
- Default Branch: main
- Last Pushed: 2026-05-13T23:02:37.000Z (about 2 months ago)
- Last Synced: 2026-05-14T01:32:02.150Z (about 2 months ago)
- Language: Go
- Size: 82 KB
- Stars: 0
- Watchers: 0
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.MD
Awesome Lists containing this project
README
# rqstdev
`rqstdev` is a lightweight single-host VM platform. It lets users create accounts, launch QEMU-based Linux VMs from a CLI, SSH into those VMs, and expose web services on per-VM subdomains and optional published web ports.
`rqstdev` is a two-part system:
- `api`: the single-host Linux server that manages accounts, QEMU VMs, and web routing
- `cli`: the user-facing CLI for account management, VM management, SSH access, and published web ports
This README is the operator/developer setup overview for the current implementation.
## Server Requirements Overview
The current server target is a single Linux host.
Required software:
- `qemu-system-x86_64`
- `qemu-img`
- a front proxy for `80/443`:
- `nginx`, or
- Caddy
Useful but not strictly required:
- `sqlite3` for inspecting the database manually
- `curl` for testing the local API and proxy
Runtime assumptions:
- the host can run QEMU guests
- the host has a base QCOW2 image available for cloning
- `rqstdev-api` can bind its configured listen address
- `rqstdev-api` can also bind additional published web ports on the host when users enable them
## Build Commands
Workspace build:
```sh
go build ./...
```
Build the API:
```sh
cd api
go build ./cmd/rqstdev-api
```
Build the CLI:
```sh
cd cli
go build ./cmd/rqstdev
```
Cross-compile Linux binaries from macOS or another host:
```sh
cd api
GOOS=linux GOARCH=amd64 go build -o /tmp/rqstdev-api-linux ./cmd/rqstdev-api
cd ../cli
GOOS=linux GOARCH=amd64 go build -o /tmp/rqstdev-cli-linux ./cmd/rqstdev
```
## Server Configuration
The server binary reads a JSON config file. The current default flag is:
```sh
rqstdev-api --config /etc/rqstdev/config.json
```
Example configuration:
```json
{
"listen_addr": "0.0.0.0:18090",
"base_url": "http://api.rqst.dev",
"base_domain": "rqst.dev",
"db_path": "/home/user/rqstdev/data/rqstdev.sqlite",
"data_dir": "/home/user/rqstdev/data",
"vms_dir": "/home/user/rqstdev/vms",
"qemu_binary_path": "/usr/bin/qemu-system-x86_64",
"template_file": "/home/user/rqstdev/assets/default-disk.qcow2",
"template_cpu": 1,
"template_memory_mb": 1024,
"email_script_path": "/home/user/rqstdev/send-email-resend.py"
}
```
Field notes:
- `listen_addr` is the API bind address, not the public domain
- `base_url` should be the URL the CLI uses, usually the front-proxy hostname such as `http://api.rqst.dev` or `https://api.rqst.dev`
- `base_domain` is the VM hostname suffix, for example `rqst.dev`
- `db_path` is the SQLite database file
- `data_dir` is the server data root
- `vms_dir` is where per-VM runtime directories are created
- `qemu_binary_path` should point at the `qemu-system-x86_64` executable
- `template_file` should point at the base QCOW2 image used for cloning new VMs
- `template_cpu` and `template_memory_mb` are optional and define the single VM profile used for new machines
- `default_web_port` is optional and defaults to `80`
- `email_script_path` is optional; when set, it enables email-based login challenges and password reset delivery. See [scripts/send-email-resend.py](/Users/admin/Documents/Projects/rqstdev/scripts/send-email-resend.py)
## Proxy Model
The current proxy model is:
- `80/443` traffic goes through a front proxy to `rqstdev-api`
- `rqstdev-api` reads the incoming hostname and routes web requests to the correct VM backend
- additional published web ports are opened directly by `rqstdev-api` on the host
Important implication:
- the front proxy is only needed for standard web entry on `80/443`
- published ports like `vm-name.rqst.dev:3456` are handled by `rqstdev-api` binding port `3456` itself
That means:
- your proxy must preserve the original `Host`
- your proxy should send `X-Forwarded-Proto`
- your proxy should send `X-Forwarded-Port`
## Nginx Example
Example `nginx` config for `80`:
```nginx
server {
listen 80 default_server;
listen [::]:80 default_server;
server_name _;
location / {
proxy_pass http://127.0.0.1:18090;
proxy_set_header Host $http_host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Port $server_port;
proxy_set_header X-Real-IP $remote_addr;
}
}
```
Minimal HTTPS shape with your own certificate paths:
```nginx
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name api.rqst.dev *.rqst.dev;
ssl_certificate /path/to/fullchain.pem;
ssl_certificate_key /path/to/privkey.pem;
location / {
proxy_pass http://127.0.0.1:18090;
proxy_set_header Host $http_host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Port $server_port;
proxy_set_header X-Real-IP $remote_addr;
}
}
```
## Caddy Example
HTTP:
```caddy
:80 {
reverse_proxy 127.0.0.1:18090 {
header_up Host {host}
header_up X-Forwarded-Proto {scheme}
header_up X-Forwarded-Port {server_port}
}
}
```
HTTPS with your own site names:
```caddy
api.rqst.dev, *.rqst.dev {
reverse_proxy 127.0.0.1:18090 {
header_up Host {host}
header_up X-Forwarded-Proto {scheme}
header_up X-Forwarded-Port {server_port}
}
}
```
If you want Caddy to manage certificates automatically, use normal Caddy site addresses and DNS that point at the host.
## Additional Published Ports
Published ports are explicit and web-only in the current implementation.
Example CLI commands:
```sh
rqstdev port add myvm 3456:3456
rqstdev port list myvm
rqstdev port remove myvm 3456
```
Behavior:
- the mapping is stored in SQLite
- `rqstdev-api` opens the public port on the host
- requests to `vm-name.rqst.dev:3456` are routed to guest port `3456`
The front proxy does not manage these extra published ports.
## Runtime Layout
Each VM gets a runtime directory under `vms_dir`, for example:
```text
/home/user/rqstdev/vms//
```
Current runtime files include:
- `disk.qcow2`
- `qemu.pid`
- `qmp.sock`
- `serial.log`
## CLI Usage
Global option:
- `--account ` overrides the active account for a single command
Top-level commands:
```sh
rqstdev
rqstdev help
rqstdev signup
rqstdev login
rqstdev logout
rqstdev invites
rqstdev invites accept
rqstdev invites refuse
rqstdev list
rqstdev add [vm-name] [guest-web-port]
rqstdev delete [vm-name] [--force]
rqstdev poweron [vm-name]
rqstdev poweroff [vm-name]
rqstdev kill [vm-name]
rqstdev ssh [user@]vm-name
rqstdev ssh-copy-id [user@]vm-name
rqstdev port add [vm-name] :
rqstdev port remove [vm-name]
rqstdev port list [vm-name]
```
Account commands:
```sh
rqstdev account
rqstdev account create
rqstdev account add [local-alias]
rqstdev account remove
rqstdev account default
rqstdev account use
rqstdev account transfer
rqstdev account forgot
rqstdev account user invite [user|admin]
rqstdev account user revoke
```
Behavior notes:
- `rqstdev` with no command opens the interactive root flow
- when a VM name is omitted for VM, SSH, and port commands, the CLI prompts you to select one
- `rqstdev add` defaults the guest web port to `80`
- `rqstdev delete` requires typing `DELETE` unless `--force` is provided
- `rqstdev ssh vm-name` defaults to `root`
- `rqstdev ssh-copy-id vm-name` defaults to `root` and lets you choose a public key from the default `~/.ssh` directory or enter a custom path
- `rqstdev invites` with no subcommand opens the interactive invite list
- `rqstdev account` with no subcommand lists remote accounts
- `rqstdev account user invite` defaults the invited role to `user`
## Notes
- VM web services are user-managed inside the guest
- `rqstdev` does not automatically provision a web server inside the VM
- SSH access is through the CLI path, for example `rqstdev ssh myvm`