Skip to content

DO-Solutions/do-win-image-builder

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

2 Commits
 
 
 
 
 
 
 
 

Repository files navigation

Running Windows on DigitalOcean

Build a custom Windows qcow2 image with do-win-image-builder on a one-time Linux builder droplet, upload it to DigitalOcean Custom Images, and launch Windows droplets from it. The Windows installation is fully automated — no browser interaction is required.

Important: Keep your session alive with screen

The Windows image build can take a long time (package installs, ISO download, OS installation, sysprep, and image upload). If your SSH connection drops, the build process will stop. Run the entire workflow inside a screen session on the builder droplet:

# After SSH into the builder droplet:
screen -S windows-build
# Run all setup steps inside this screen session.
# If disconnected, reattach with:
screen -r windows-build

Image building typically takes up to 1 hour. Uploading the finished image to DigitalOcean Custom Images takes around 1–3 hours depending on image size and region.

Overview

  • Create a one-time Linux builder droplet
  • Run the Windows image build script on that droplet (inside screen)
  • Windows installs automatically via autounattend.xml — noVNC is optional for monitoring or troubleshooting
  • Upload the finished image to DigitalOcean using an API token
  • Launch Windows droplets from the custom image
  • Connect via SSH (initial setup) and RDP (desktop access)

This is a one-time image-build step. After the custom image exists, you can reuse it to launch Windows droplets like any other custom image.

Build workflow

flowchart LR
    A["screen + setup.sh"] --> B["Prompts: upload, ISO, edition"]
    B --> C["Unattended QEMU install"]
    C --> D["sysprep + shutdown"]
    D --> E["HTTP serve + DO upload"]
    C -.->|optional| F["noVNC monitor"]
Loading

Step 1 — Create the Linux builder droplet

  • In the DigitalOcean control panel, go to Create → Droplets.
  • Choose your target region (e.g. NYC1 for the builder). Custom images are region-specific — upload and launch in the same region.
  • Select a Linux distribution (Ubuntu was used in the demo).
  • Choose a droplet size with enough CPU, memory, and disk for the Windows build:
    • At least 16 GB RAM and a dedicated CPU droplet are recommended.
    • Allow enough disk for the ISO plus the qcow2 image (default 64 GB).
  • Use password or SSH key authentication for the builder.
  • Name the droplet (e.g. windows-builder) and click Create Droplet.

Step 2 — Start a screen session and run the build script

SSH into the builder droplet, start a screen session, and run the build script as root:

screen -S windows-build

# Option A — one-liner
curl -sSL https://raw.githubusercontent.com/DO-Solutions/do-win-image-builder/dev/setup.sh | bash

# Option B — clone the repository
git clone --branch dev https://github.com/DO-Solutions/do-win-image-builder
cd do-win-image-builder
sudo bash setup.sh

The script installs required packages (QEMU/KVM, noVNC, dependencies).

Shortly after dependencies install, the script asks whether to upload to DigitalOcean when the build completes. If yes, provide the region, image name, and API token now so you can disconnect during the 1–3 hour upload. Pre-set these with environment variables for a fully unattended run:

export DO_UPLOAD=y DO_REGION=nyc3 DIGITALOCEAN_TOKEN="your-do-api-token"
sudo -E bash setup.sh

Detach without stopping the build: press Ctrl+A, then D. Reattach after reconnecting: screen -r windows-build.

Step 3 — Provide the Windows ISO

  • Host your Windows ISO in a DigitalOcean Spaces bucket (recommended) or any web-accessible URL.
  • When the script prompts for the ISO path/URL, paste the direct download link (or provide a local path).
  • If the ISO contains multiple editions, select Pro, Enterprise, Education, or Server (Home editions are excluded automatically).
  • The script downloads the ISO, VirtIO drivers, and Cloudbase-Init, then starts the virtual install.

Step 4 — Automated Windows installation

After you provide the ISO (and edition/locale if prompted), the script boots a QEMU VM and installs Windows fully unattended:

  • autounattend.xml handles partitioning, VirtIO driver injection, edition selection, and OOBE settings.
  • firstlogon.ps1 installs OpenSSH, Cloudbase-Init, and RDP, then runs sysprep and shuts down the VM.
  • The script waits for the VM to exit, then continues automatically.

The script prints a noVNC URL and VNC password. Open it only if you want to monitor progress or troubleshoot — no browser interaction is required for a successful build. If everything is working, ignore noVNC and let the build continue inside your screen session.

Do not destroy the builder droplet until the upload completes.

Step 5 — Upload the custom image to DigitalOcean

Upload preferences are collected at the start of the build (Step 2). When the VM shuts down, the script serves the qcow2 over HTTP and starts the scheduled upload automatically.

Option A — API upload (recommended)

  • Generate a DigitalOcean API token (Control panel → Account → API → Generate New Token).
  • For testing, full access works; for production, use the narrowest scope that allows custom image upload.
  • Answer y at the start-of-build prompt, or set DO_UPLOAD=y and DIGITALOCEAN_TOKEN beforehand.
  • The script uploads the image and polls until it is available.
  • After upload, the image appears under Backups & Snapshots → Custom Images.

Option B — Manual import

Skip API upload at the prompt. When the build finishes, the script prints manual instructions:

  1. Open Backups & Snapshots → Custom Images
  2. Click Import via URL
  3. Paste: http://<builder-droplet-ip>:8080/image.qcow2

The HTTP server keeps running until you stop it.

Step 6 — Launch a Windows droplet from the custom image

  • Go to Create → Droplets.
  • Select the same region where the custom image was uploaded.
  • Under Choose an image, select Custom images and pick your Windows image.
  • Choose a droplet plan with enough disk for the image (undersized disks will fail).
  • Authentication: use an SSH key — password login is not supported for droplets from this image.
  • Create the droplet.

Step 7 — Initial access and RDP setup

On first boot, Cloudbase-Init creates the doadmin administrator account and injects the SSH key you provided at droplet creation.

SSH into the new Windows droplet:

ssh -i /path/to/your/private_key doadmin@<droplet_public_ip>

Reset the administrator or doadmin password for RDP:

net user administrator <YourNewPassword>

Open your Remote Desktop client and connect to the droplet public IP using doadmin or Administrator and the password you set.

Important notes

  • One-time build: The Linux builder droplet is only needed to create the image. Delete it after upload succeeds.
  • Golden image: Customize the PowerShell scripts in scripts/ (e.g. firstlogon.ps1, Set-AdminSSHKeys.ps1) before running the build to bake in software and configuration.
  • Region: Custom images are tied to the upload region. Build and launch in the same region.
  • SSH key required: Windows droplets from this image require an SSH key at creation time.
  • Sizing: Pick adequate CPU, RAM, and disk for both the builder and the final Windows droplet.
  • Use screen: Always run the build inside screen so a dropped SSH session does not abort the process.
  • Unattended install: The build is automated end to end. noVNC is a troubleshooting aid, not a required step.

Advanced reference

Cheat sheet

  1. Ubuntu/Debian builder droplet — 16 GB RAM minimum, dedicated CPU, run as root
  2. screen -S windows-build, then run setup.sh
  3. Provide ISO URL; answer edition/locale prompts
  4. Walk away — install and sysprep are automated (~1 hour)
  5. Upload runs automatically if configured at start (~1–3 hours)
  6. noVNC URL is optional — use only to monitor or debug

What the image includes

  • Automated Windows setup: Generates autounattend.xml with VirtIO drivers, RDP, and Cloudbase-Init
  • SSH preconfigured: OpenSSH Server is installed, enabled, and port 22 is opened during the build
  • First-boot cloud-init: Cloudbase-Init sets the server hostname, injects SSH keys, and runs UserData and LocalScripts startup scripts when a droplet launches from the image
  • Edition detection: Reads WIM metadata, filters Home editions, and injects KMS generic keys for testing
  • Optional noVNC console: Monitor the unattended install or debug setup issues
  • DigitalOcean-compatible image: Produces a qcow2 image ready for DigitalOcean Custom Images (< 100 GB)
  • HTTP download: Serves the finished image over HTTP when the build completes
  • API upload: Optionally imports the image into DigitalOcean Custom Images via the API

Installation options

Custom configuration — export environment variables before running setup.sh. When using sudo, pass them through with -E:

export HTTP_PORT=9090 QCOW2_SIZE=32G
sudo -E bash setup.sh

Or inline with the curl one-liner:

HTTP_PORT=9090 QCOW2_SIZE=32G curl -sSL https://raw.githubusercontent.com/DO-Solutions/do-win-image-builder/dev/setup.sh | bash

Configuration options

Parameter Description Default
TMP_DIR Working directory for the build (qcow2, ISOs, logs) ./do-win-image-builder
QCOW2_IMAGE Output disk image path $TMP_DIR/image.qcow2
QCOW2_SIZE Size of the qcow2 image (must stay under 100 GB for DO custom images) 64G
HOST_RESERVED_MB RAM left for the host; the rest goes to the VM (minimum 2560) 4096
HTTP_PORT Port for serving the finished image 8080
VIRTIO_URL Download URL for the VirtIO drivers ISO Fedora virtio-win stable URL
CLOUDBASE_INIT_URL Download URL for Cloudbase-Init Cloudbase.it stable MSI URL
REPO_URL Git repo cloned when running the curl one-liner https://github.com/DO-Solutions/do-win-image-builder
REPO_BRANCH Branch checked out for setup scripts dev
DO_METADATA Metadata endpoint for droplet IP and region http://169.254.169.254/metadata/v1
DO_UPLOAD Upload via API when build completes (y/n); skips the upload prompt when set (prompted at start)
DO_REGION Region slug for custom image import; defaults to droplet region (prompted at start)
DO_IMAGE_NAME Name for the custom image in DigitalOcean win-custom-YYYYMMDD
DIGITALOCEAN_TOKEN API token for uploading the finished image (skips the token prompt) (unset)

QCOW2_SIZE must remain under 100 GB uncompressed for DigitalOcean Custom Images.

Supported Windows editions

Version Detected slug Notes
Windows 10 w10 Pro, Enterprise, Education
Windows 11 w11 Pro, Enterprise, Education
Windows Server 2016 2k16 Standard, Datacenter
Windows Server 2019 2k19 Standard, Datacenter
Windows Server 2022 2k22 Standard, Datacenter
Windows Server 2025 2k25 Standard, Datacenter

Home editions are excluded automatically. The script reads WIM metadata from your ISO, prompts you to pick an edition when multiple are available, and injects the matching KMS generic setup key when known.

Expected console output

Example output
── Step 1: Install Dependencies ──
[ OK ]  Dependencies installed.

── Step 2: DigitalOcean Custom Image ──
Upload to DigitalOcean via API when the build completes? [y/N] y
[ OK ]  Will upload to DigitalOcean when the build completes (region: nyc3, name: win-custom-20260703).

── Step 3: Prepare Working Directory ──
[ OK ]  Image created: ./do-win-image-builder/image.qcow2

── Step 4: Installation ISO ──
[INFO]  Detected: Windows Server 2022
[ OK ]  Edition: Windows Server 2022 Standard (WIM index 2, KMS key injected)

── Step 5: Boot QEMU VM ──
[ OK ]  QEMU running (PID 12345).

── Step 6: noVNC Web Console ──
[ OK ]  noVNC is running.
  Open in your browser (optional — for monitoring/troubleshooting):
  http://<droplet-ip>:6080/vnc.html?autoconnect=true&password=<generated>

── Step 7: Serve Image ──
[INFO]  Windows is installing unattended.
[INFO]  Waiting for the VM to shut down...
[ OK ]  VM has shut down.
[ OK ]  Image ready: ./do-win-image-builder/image.qcow2 (12G)
[ OK ]  HTTP server running (PID 12346)
[INFO]  Starting scheduled DigitalOcean upload (region: nyc3, name: win-custom-20260703)...
[ OK ]  Custom image "win-custom-20260703" is ready in nyc3.

About

Build an automated, DigitalOcean-ready Windows qcow2 custom image on a Linux droplet, upload it via API, and launch Windows droplets with SSH and RDP preconfigured.

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors