π³ A containerised web UI for deploying Veeam β from customising a Software Appliance ISO, to provisioning a full multi-VM topology on a hypervisor, to generating the exact REST wiring script. Docker is the only dependency.
Warning
Credential-bearing admin tool β protect access.
autodeploy-web now ships with a built-in admin login (single-password, bcrypt-hashed, signed session cookie + CSRF; see Authentication). It is on by default: first launch sends you to /setup to set a password. Once in, an operator can create build jobs, download all output files (including generated kickstart/config files that may contain passwords), manage uploaded media, and trigger deployments with hypervisor + appliance credentials.
Still, do NOT expose this service directly to the internet. Serve it behind a TLS-terminating reverse proxy (Caddy, Traefik, Nginx) and ideally a VPN β plain HTTP means the session cookie travels unencrypted. The remote-kickstart route GET /ks/<output-id>/<file>.cfg is unauthenticated by design (Anaconda/GRUB can't log in): it serves only .cfg files under an unguessable job UUID and refuses the credential-bearing config snapshot β but it means those kickstart files are readable by anyone who can reach the port and knows the UUID, so keep the service on a trusted network.
autodeploy-web bundles three Veeam deployment workflows behind one web UI:
-
π οΈ Customise a Veeam ISO β a browser front-end for the BaptisteTellier/autodeploy PowerShell script. Fill a form (hostname, network, accounts, MFA, license, β¦) and generate a customised Veeam Software Appliance / VIA ISO with the kickstart and GRUB tweaks baked in β no PowerShell or WSL on your host, just Docker.
-
π Deploy a topology β provision a whole multi-VM Veeam architecture (VSA + VIA proxies + hardened repositories, optionally HA) onto Proxmox, Hyper-V, vSphere, Nutanix AHV or XCP-ng, with optional remote kickstart and automatic Veeam REST wiring (proxies, repositories, S3, license, HA cluster) β no Terraform, no Packer.
-
π Craft the REST API β describe a topology in a form and get the exact, runnable Veeam REST wiring sequence as PowerShell or curl. Render-only: copy/paste and run it yourself against appliances you deployed by hand. Same call sequence the Deploy page uses.
# 1. Download the compose file
curl -O https://raw.githubusercontent.com/BaptisteTellier/autodeploy-web/main/docker-compose.yml
# 2. Drop your Veeam source ISO into ./data/iso/
# (the app creates the other sub-folders on first start)
mkdir -p ./data/iso && cp /path/to/VeeamSoftwareAppliance_*.iso ./data/iso/
# 3. Start
docker compose up -d
# 4. Open http://localhost:8080That's it. Fill the form, click Generate ISO, watch the live log, download the result.
Optional drop-in files:
| Folder | What to put there |
|---|---|
./data/license/ |
Veeam .lic file β needed for LicenseVBRTune and for license install during Deploy / Craft API |
./data/conf/ |
unattended.xml + veeam_addsoconfpw.sh + conftoresto.bco β needed for the RestoreConfig feature |
Change the host port or build concurrency by copying .env.example β .env:
| Variable | Default | Description |
|---|---|---|
PORT |
8080 |
Host port |
WORKER_CONCURRENCY |
1 |
Parallel ISO builds β raise carefully (disk-bound) |
AUTH_DISABLED |
false |
Turn off the built-in admin login (only if bound to localhost or behind your own authenticating proxy) |
ADMIN_PASSWORD_HASH |
β | Pre-provision the admin login with a bcrypt hash (skips the first-run setup screen) |
ADMIN_PASSWORD |
β | Pre-provision with a plaintext password (hashed at startup; prefer ADMIN_PASSWORD_HASH) |
A single-admin session login is on by default. On first load you're taken to a
one-time setup page (/setup) to create an admin password; after that you sign
in at /login and log out from the top-bar menu. Sessions last 30 days with no
idle timeout (a signed cookie that survives restarts), so you rarely re-enter it.
What it protects. Without a login, anyone who can reach the web UI β or a
malicious web page you visit while the app is reachable (a "drive-by" / CSRF) β can
drive the tool: upload and run an arbitrary autodeploy.ps1 (remote code
execution on the server), start ISO builds and hypervisor deployments, and read
the credentials baked into saved configs. The login plus a SameSite=Strict
session cookie and a same-origin check on state-changing requests close that off.
Where the credential lives. A single file, <data>/auth.json (with the compose
setup, ./data/auth.json on the host β mode 0600). It holds a bcrypt hash of
the password and a random HMAC secret used to sign sessions. It is never in the
image and never leaves the box.
Headless / air-gapped provisioning. Pre-set the password with
ADMIN_PASSWORD_HASH (a bcrypt hash β generate with
docker run --rm httpd:alpine htpasswd -nbBC 12 x 'yourpassword' | cut -d: -f2) or,
less securely, ADMIN_PASSWORD (plaintext, hashed at startup). Either skips the
setup screen.
Turning it off. Set AUTH_DISABLED=true only when the app is bound to
localhost or sits behind your own authenticating reverse proxy. Never expose
autodeploy-web to an untrusted network without authentication.
There is no email recovery (it's a single-operator tool with no mail server) β you reset it from the host, which you control:
- Delete the credential file and restart β the app returns to first-run setup:
Open the app and you'll be sent to
docker compose down rm ./data/auth.json # the bcrypt hash + session secret docker compose up -d/setupto create a new password. This also rotates the session secret, so every existing session is invalidated. - Or provision a new password via the environment and restart β put
ADMIN_PASSWORD=new-password(orADMIN_PASSWORD_HASH=<bcrypt>) in your.env/ composeenvironment:anddocker compose up -d. The environment value takes precedence overauth.json.
(If auth is running under a bare docker run, do the same against the host path you
mounted at /data, e.g. rm /srv/autodeploy/data/auth.json.)
To pull a new version later: docker compose pull && docker compose up -d.
autodeploy-web is a single-operator infrastructure tool: by design it runs PowerShell, builds bootable ISOs, and drives hypervisors. Treat it like the credential-bearing admin console it is.
- Run it on a trusted network, authenticated. The admin login (above) is the
primary control. Only disable it (
AUTH_DISABLED=true) behindlocalhostor your own authenticating proxy. - Prefer HTTPS. Serve it behind a TLS-terminating reverse proxy (or set
X-Forwarded-Proto: https); the session cookie is then flaggedSecureautomatically. Over plain HTTP on a LAN the cookie stays usable but unencrypted. - Secrets are stored in cleartext under
/databecause the build must bake them into the appliance: Veeam admin/SO passwords, MFA secrets, recovery token, VCSP and S3 keys live in./data/configs/*.json, in each job's./data/output/<id>/job-config.json, and (transiently) in the build config. Keep./dataon a protected volume, restrict its filesystem permissions, and don't back it up to untrusted storage. (The job-config snapshot is not downloadable through the UI, but it is on disk.) Saved deploy/Craft templates never contain secrets. - The
autodeploy.ps1override (Settings β upload/update) is remote code execution by design β an uploaded script runs on the server for every build. Only trusted operators should have access (hence the login). - The VSA REST API console proxies arbitrary calls to a deployed appliance using a server-side session β a deliberate power tool, scoped to that deployment.
- Remote-kickstart
.cfgis served unauthenticated at/ks/<output-id>/<file>.cfgβ a netbooting appliance (anacondainst.ks=) cannot sign in. Access control is the unguessable output UUID in the URL, and only.cfgfiles are served (never the config snapshot or any other artefact). Because a.cfgcontains the credentials it bakes into the appliance, treat the deployment network as trusted during boot. This is the single route exempt from the login. - Hypervisor / VBR TLS. Connections to Proxmox, vSphere, Hyper-V, Workstation, Nutanix, XCP-ng and a target VBR verify TLS unless you tick that connection's Skip TLS verification box (default on for typical self-signed lab certs). Connections to a freshly-deployed VSA always skip verification because its self-signed certificate cannot be known in advance.
- Web fonts are self-hosted (
static/fonts/, no external CDN), so the UI works fully offline / air-gapped.
The container packages the Go web server and the unmodified autodeploy.ps1 together, so the PowerShell script runs identically to how it would on Windows + WSL:
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β container : ghcr.io/baptistetellier/autodeploy-web:latest β
β β
β ββββββββββββ HTTP βββββββββββββ spawn ββββββββββββββ β
β β browser βββββββββΆ β Go binary ββββββββββΆ β pwsh + β β
β β (form) β :8080 β + web UI β exec β autodeploy β β
β β β ββββSSE β β ββstdout β .ps1 β β
β ββββββββββββ βββββββββββββ ββββββββββββββ β
β β β β
β βΌ βΌ β
β /data/configs/ xorriso (native)β
β /data/iso/ βββΆ /data/output/ β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
- ISO customisation is delegated to
autodeployβ the PowerShell script is the authoritative source of all build logic (kickstart, GRUB, MFA, VCSP, license). The Go server just renders the form, writes the JSON config, and spawnspwsh autodeploy.ps1, streaming its output to the browser over SSE. A tiny/usr/local/bin/wslshim forwards the script'swsl xorriso β¦calls to the nativexorriso. The PS1 is never modified, and the form's JSON export is 100 % compatible with running the script directly on Windows. - Deploy & Craft API are pure-Go: the hypervisor drivers (
internal/hypervisor) and the Veeam REST client (internal/veeam) + wiring orchestration (internal/wiring) talk directly to your infrastructure β no PowerShell involved. - Auto-updated β a daily workflow watches for new releases of
autodeploy.ps1and opens a bump PR, which rebuilds the image automatically.
Everything lives under a single ./data:/data mount, so all state survives a container recreate / image upgrade:
Path under ./data/ |
Purpose |
|---|---|
iso/ |
Source ISOs β drop your Veeam ISO here (15β20 GB each) |
output/ |
Generated ISOs + per-job config/kickstart files, downloadable from the UI |
license/ |
Veeam .lic files |
conf/ |
Restore-config files (unattended.xml, .bco, β¦) |
configs/ |
Saved ISO-build JSON presets (drop PS1-compatible JSONs here too) |
deploy-presets/ |
Saved Deploy / Craft templates |
jobs.db |
SQLite ISO-job history (survives restarts) |
deployments.db |
SQLite deployment history (survives restarts) |
settings.json |
App settings (history limit) |
The top navigation exposes everything the app does. Each page is detailed below.
The main ISO-build form (expert mode) β every autodeploy.ps1 configuration field on one page:
- Appliance type (VSA / VIA-Proxy / VIA-HR / β¦), hostname, network (DHCP or static IP / subnet / gateway / DNS), NTP, timezone.
- Veeam accounts (admin / SO) with password generators and complexity validation, MFA, GUID generator.
- License baking (LicenseVBRTune), config restore (RestoreConfig), High-Availability, single-disk, GRUB timeout, and the rest of the PS1 options.
- Preset save/load, β¬οΈ Import / β¬οΈ Export JSON (round-trips with the PowerShell script), and live field validation.
- Choose full custom ISO or config-only (just the
.cfg/kickstart, no ISO rebuild). Click Generate β watch the live build log (SSE,xorrisoline-by-line) β download from Output.
A guided, step-by-step version of the same configuration, with inline help tips on every field. Produces the identical job as New job β friendlier for first-time users; switch to New job for the dense all-in-one form.
Manage the files the app works with: upload source ISOs, license files, and restore-config files into ./data, and see what's present. Saves copying files onto the host by hand.
Browse and download every job's results β the generated ISO and all per-job config/kickstart files. Browsing and downloads go through the authenticated /media/output/<jobid>/<filename>/content route (requires a session).
It also doubles as a live kickstart server (a lightweight Packer alternative). Every .cfg file gets a π Link button exposing the dedicated unauthenticated kickstart URL β a netbooting appliance can't sign in, so this route is deliberately on the auth allow-list (it serves only .cfg files under the unguessable job UUID and refuses the credential-bearing config snapshot):
http://<server>/ks/<jobid>/<filename>.cfg
β¦which you append to an Anaconda boot to install over the network:
# Modern Anaconda (RHEL 8+): inst.ks=http://<server>/ks/<jobid>/vbr-ks.cfg
# Older Anaconda: ks=http://<server>/ks/<jobid>/vbr-ks.cfg
Worked example β from the ISO's GRUB shell (UEFI): boot the appliance ISO, press c, type three lines (Enter after each):
linuxefi /images/pxeboot/vmlinuz inst.stage2=hd:LABEL=VeeamJeOS inst.ks=http://192.168.1.10:8080/ks/<jobid>/proxy-ks.cfg ip=dhcp quiet inst.assumeyes
initrdefi /images/pxeboot/initrd.img
boot
boot(line 3) is mandatory β the first two lines only load kernel + initrd; nothing starts untilboot.ip=dhcpbrings networking up so Anaconda can fetch the HTTP kickstart. For a static address useip=<ip>::<gw>:<mask>:<host>::none. (The Deploy page generates this automatically for fixed-IP nodes.)linuxefi/initrdefiare UEFI; on legacy BIOS uselinux/initrd.- This endpoint (
/ks/<output-id>/<file>.cfg) is unauthenticated by design (so Anaconda can read it during boot, before any login is possible) β it serves only.cfgfiles under an unguessable job UUID and refuses the credential-bearing config snapshot. Still, keep autodeploy-web on a trusted LAN.
Upload and manage Veeam .lic files. They're used when LicenseVBRTune bakes a license into an ISO, and picked from a dropdown for license install over REST during Deploy and Craft API.
Two histories, both persisted in SQLite and survive restarts:
- ISO-creation jobs β every build with state, timestamps, and a per-row delete.
- Deployments β every Auto-Deploy run, with Created / Finished date-time columns, a β» retry of β¦ link when a run is a retry of another, and per-row actions: retry (re-run end-to-end), re-wire (re-run only the REST wiring against existing VMs), and π delete (removes the record only β does not touch the VMs). A run interrupted by a restart is reloaded as failed ("interrupted by a restart"). Opening a deployment shows its live log and a node table with each machine's IP (static IPs immediately; DHCP IPs stream in as they resolve).
Provision and wire a complete topology in one shot.
Hypervisor support (a dropdown selects the back-end):
| Back-end | Status | Remote kickstart |
|---|---|---|
| Proxmox VE | β validated | β
QEMU sendkey |
| Microsoft Hyper-V (WinRM) | β validated | β
Msvm_Keyboard |
| VMware vSphere / vCenter | β validated | β USB scan codes |
| Nutanix AHV | π§ͺ experimental | β no key-injection API |
| XCP-ng | π§ͺ experimental | β no key-injection API |
| VMware Workstation (WinRM + vmrun) | β validated | β VNC |
The experimental back-ends implement the full lifecycle but haven't been validated on real infrastructure. On AHV / XCP-ng (no console key-injection) you must deploy a pre-customised ISO rather than remote kickstart.
Flow:
- Pick a topology β VSA Β· VSA+Proxy Β· VSA+HR Β· VSA+Proxy+HR Β· VSA-HA+HR Β· VSA-HA+Proxy+HR. Click οΌ on any VIA slot to add more proxy/HR nodes.
- Connection β hypervisor host/credentials, entered in the form (nothing stored). VMs are created UEFI/OVMF (Secure Boot off for the unsigned ISO), with role-derived disks (VSA 2Γ256 GiB, VIA 2Γ128 GiB; single-disk 1Γ128 GiB) and editable CPU/RAM.
- Per-node output β choose which build output each VM uses; a summary card verifies the plan. Each node needs a distinct fixed IP (or DHCP) β the form blocks launch on duplicate IPs.
- Boot mode β Customised ISO (most robust; embedded kickstart self-runs) or Remote kickstart (boots an original ISO and injects the role-aware GRUB command over the console; fixed-IP nodes get a static
ip=arg automatically). - Post-boot wiring (Veeam REST) β registers every proxy & hardened repo, installs the license, and builds the HA cluster, waiting for each node to answer; bounded by a configurable timeout. VSA credentials come from the chosen output.
Pre-flight checks warn before launch when config and options don't match (e.g. GRUB timeout β€ boot-wait under remote kickstart; a VSA output not built with HA on an HA topology).
Advanced options & behaviour:
| Feature | Behaviour |
|---|---|
| Customised-ISO boot | Per-VM ISO attached & booted; embedded kickstart self-runs; no keystrokes. Most robust. |
| Remote kickstart | Injects a role-aware GRUB command over the console to fetch the kickstart over HTTP. c halts the GRUB countdown; a boot-wait (default 10 s) lets slow OVMF reach GRUB. Not on AHV/XCP-ng. |
| Static IP vs DHCP | Fixed-IP β static ip=<ip>::<gw>:<mask>:<host>::none auto-generated (works without DHCP). DHCP β IP resolved from the guest agent before wiring. |
| Post-boot wiring | Registers proxies & hardened repos over REST (:9419), waits per node, bounded timeout, re-auths on token expiry, parallelised across nodes. |
| License install (REST) | Installs a /data/license/*.lic after boot (needed under remote kickstart, which boots unlicensed); warns if a license was baked into the output. |
| HA cluster | HA topologies only β needs a DNS name + a free VIP. Config backup is redirected to the first hardened repo, the Default repo removed, then the 2-node cluster is formed. |
| node_exporter | Enables the Prometheus metrics endpoint (optional TLS + basic auth). |
| Syslog | Forwards VBR events to a syslog target (host / port / UDPΒ·TCPΒ·TLS). |
| S3 / object storage | Creates the cloud credential then the repo (Amazon S3 or S3-compatible). Endpoint auto-prefixed with https://; the bucket folder is created first (idempotent); optional take-over of a bucket already used by another server; optional Linux mount-server pin (one of the VIA-Proxy nodes). |
| Copy to deploy / presets | Prefill the whole form from a past deployment (Copy) or a saved deploy template. |
Adding a Cloud Connect service provider is not exposed by the VBR REST API (1.3-rev2) β use
Add-VBRCloudServiceProvideron the appliance.
The deploy detail page streams a live log with a per-node step badge (created β installing β ready / failed).
The Hyper-V back-end drives the host over WinRM (HTTP 5985, Basic auth by default). On the Hyper-V host, in an elevated PowerShell:
Enable-PSRemoting -Force
# Required β the client uses Basic over 5985 (without these: "401 - invalid content type"):
winrm set winrm/config/service/auth '@{Basic="true"}'
winrm set winrm/config/service '@{AllowUnencrypted="true"}'If the connection times out, a NIC is probably on the Public profile (WinRM's rule only opens on Domain/Private):
Get-NetConnectionProfile # NetworkCategory : Public ?
Set-NetConnectionProfile -InterfaceAlias "Ethernet" -NetworkCategory PrivateScope the WinRM rule to the Docker host's LAN IP (container traffic is NAT-ed to it), and verify:
Set-NetFirewallRule -Name "WINRM-HTTP-In-TCP" -RemoteAddress 192.168.1.50 # your Docker host
Test-NetConnection <hyperv-host> -Port 5985 # from the Docker hostUse a local administrator in the Deploy form.
Warning
AllowUnencrypted="true" sends WinRM payloads (incl. credentials) in clear text. Acceptable on an isolated lab segment scoped to one source IP; otherwise use HTTPS (5986) β tick Use HTTPS and configure an HTTPS listener with a certificate.
Note
WinRM streams the 15β20 GB ISO as base64 (slow). Pre-stage the original ISO in the host's ISO path so FindISO skips the upload.
The VMware Workstation back-end drives a Windows host over WinRM (same transport as Hyper-V β see the WinRM setup steps above). The container authors a .vmx, calls vmrun.exe and vmware-vdiskmanager.exe to create and start VMs, then injects the remote-kickstart GRUB command over VNC (RemoteDisplay.vnc). Status: π§ͺ experimental.
Prerequisites on the Windows host:
- VMware Workstation 17 / "26H1" installed. Default path:
C:\Program Files\VMware\VMware Workstation(older installs may be underC:\Program Files (x86)\...). The form's Install directory field drives bothvmrun.exeandvmware-vdiskmanager.exeβ adjust it if your install is non-standard. - WinRM enabled β follow the same elevated-PowerShell steps as the Hyper-V section.
- A bridged virtual network (e.g.
VMnet0). On hosts with multiple NICs (Wi-Fi, Ethernet, other VMware/Hyper-V virtual adapters) do not leave VMnet0 on Automatic bridging β open Virtual Network Editor and pin VMnet0 to the physical NIC on your deploy LAN. Auto-bridging frequently picks the wrong adapter, which shows up as the installer failing to reach the kickstart server withcurl: (7) β¦ No route to host.
Deploy-form fields (the ws_* panel, shown when Provider = VMware Workstation): WinRM host / port / user / password, HTTPS + skip-TLS toggles, install directory, VM base directory, ISO directory, virtual network (vmnet), VNC host, VNC base port.
Two settings that matter most:
- VNC host β must be the host's LAN IP (reachable from outside Docker), not
localhost/127.0.0.1. The container connects to VMware's VNC listener from a different network namespace. Open the host firewall for the VNC port range (base port 5910, +1 per VM). - Kickstart base URL (
ks_base_url) β must be reachable from the bridged VM (i.e. the Docker host's LAN IP + the web UI port). Allow inbound on that port in the host firewall.
Black screen in the Workstation GUI (expected behaviour): VMs are started headless via WMI so they survive the WinRM session β they run in Windows session 0, which has no interactive desktop. If you open the VM through "Open all background virtual machines" in the Workstation tray, the console window renders black. This does not mean the install failed. To watch the real console, point a VNC viewer at <host-LAN-IP>:5910 (base 5910 + VM index).
On a deployment's detail page (/deploy/{id}), the header button Open REST API opens an interactive REPL against that deployment's primary VSA: pick a method (GET / POST / PUT / DELETE), type a path (e.g. /api/v1/serverInfo) and an optional JSON body, hit Send, and see the status code + pretty-printed response. The button toggles to Close REST API session.
- No credentials to re-enter β the container authenticates to the VSA using the admin password already baked into the deployment's output config (same source as the wiring).
- Server-side proxy β your browser never talks to the VSA directly (it has a self-signed cert and may be on a different network); every call is proxied through the container, which already reaches the VSA.
- Persistent β the request/response history is kept in
localStorageand the session survives closing the modal, reloading the page, and a container restart (it silently re-authenticates). - Self-cleaning β sessions live in memory, expire after 30 min idle, and are dropped automatically when the deployment is removed or deleted.
β οΈ This is a power/debug tool: it issues authenticated calls against the live VSA with all HTTP methods (includingDELETE). Consistent with the app's LAN-only, no-auth model β use with care.
The same wiring as the Deploy page, but render-only β for appliances you deployed by hand. Fill a Deploy-style form (pick a topology, οΌ add proxy/HR nodes, enter each node's IP/hostname/pairing code, connection, and the advanced options), click Generate, and get the exact REST call sequence as a runnable PowerShell or curl script (toggle, copy, download wire.ps1 / wire.sh).
The generated script is genuinely runnable: OAuth token capture, wait-for-session loops, per-host connectionCertificate β computed SSH fingerprint β add-host, license install (paste base64 β normalised automatically; the field explains how to produce it), node_exporter / syslog / S3 / HA. It mirrors the live internal/veeam client call-for-call (guarded by tests). Save/load templates (secrets excluded) are stored in /data/deploy-presets.
Craft API never makes live requests itself β it only generates a script you run yourself. The script is one-shot (no idempotent re-runs); generate it against freshly deployed appliances.
App-wide settings: the history limit (max finished ISO jobs and deployments kept, default 20, auto-pruned), updating the bundled autodeploy.ps1 from GitHub, and language (EN / FR).
- π Single admin login β one shared password, no multi-user accounts or roles. Serve it over HTTPS (reverse proxy) for any exposure beyond localhost; the remote-kickstart
/ks/β¦route stays unauthenticated by design. - π§ͺ Deploy: only Proxmox VE and Hyper-V are production-validated. vSphere / Nutanix AHV / XCP-ng are implemented but untested on live infrastructure; AHV/XCP-ng can't do remote kickstart (use a pre-customised ISO).
β οΈ Hyper-V/Workstation Pro ISO upload over WinRM is slow (base64) β pre-stage the ISO soFindISOskips the upload.β οΈ Remote-kickstart keystroke injection is best-effort β no console feedback over the hypervisor API; the customised-ISO boot mode is the most reliable.- π Craft API scripts are one-shot β they don't include the live wiring's find-before-add idempotency, so run them against fresh appliances.
- The PS1's hard-coded behaviours (e.g. NTP failure aborts the build) apply unchanged.
Already have JSON configs? β¬οΈ Import JSON in the UI β the schema is identical. See docs/migration-from-ps1.md.
make vendor # download htmx / alpine / tailwind into static/
make build # go build β bin/autodeploy-web
make test # go test ./...
make image # docker build
make dev-up # docker compose up --buildDocker is the recommended and supported way to run autodeploy-web. If you must
run it directly on a VM or bare server instead β locked-down host, no-Docker
policy, or you want a systemd-managed service β there's a complete,
copy-paste, no-experience-required walkthrough for both Linux and Windows:
β‘οΈ docs/native-vm-install.md β install the Go
binary, PowerShell 7, xorriso/rsync, the wsl/cmd shims and
autodeploy.ps1, then wire it up as a service.
All ISO customisation logic (kickstart, GRUB, MFA, VCSP, license) is done by BaptisteTellier/autodeploy. This project provides the Docker packaging, web UI, and the Deploy / Craft API layers.
MIT β see LICENSE.
Made by Baptiste TELLIER for the Veeam community.