Compare commits

...

26 Commits
v4.04 ... v4.16

Author SHA1 Message Date
Kroese
e16af78828 feat: Check path to custom .iso (#1069) 2025-02-28 04:07:57 +01:00
Kroese
5ae6ecbe85 feat: Update download links (#1066) 2025-02-26 23:15:13 +01:00
Kroese
c9482fe3f0 build: Update qemu-docker to v6.18 (#1065) 2025-02-26 22:55:28 +01:00
Kroese
63a9d10a27 feat: Make app name configurable (#1058) 2025-02-25 15:15:48 +01:00
Kroese
009c2c7deb build: Update qemu-docker to v6.17 (#1056) 2025-02-25 06:05:42 +01:00
renovate[bot]
06434c02f4 chore(deps): update qemux/qemu-docker docker tag to v6.16 (#1054)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-02-24 04:16:07 +01:00
Kroese
32b92cc03a fix: Update download links (#1053) 2025-02-24 04:15:49 +01:00
Kroese
d799079040 docs: Readme (#1052) 2025-02-22 10:02:48 +01:00
Kroese
b57d34e11e fix: Update download links (#1051) 2025-02-22 09:53:17 +01:00
Kroese
61d7e0d3be feat: Fallback to Windows 11 if version unknown (#1042) 2025-02-17 18:59:40 +01:00
krzysiuu1998
e6d7495bac fix: Update compose.yml (#1040) 2025-02-17 09:07:25 +01:00
Kroese
faa7c58366 fix: Download links (#1035) 2025-02-15 04:49:24 +01:00
Kroese
c0f5cca574 docs: Add restart policy (#1028) 2025-02-10 00:26:49 +01:00
renovate[bot]
d86731dc24 chore(deps): update qemux/qemu-docker docker tag to v6.14 (#1024) 2025-02-06 02:12:20 +01:00
Kroese
bca8cb6817 build: Update qemu-docker to v6.13 (#1010) 2025-01-15 23:45:30 +01:00
ncheng89
d9c7983bb5 feat: Support more shared directories (#987)
* Support more shared directories

Control the sharing of more directories through environment variables instead of hard-coding more shared directories
2025-01-08 15:55:17 +01:00
James Nguyen
28f6e9c76b feat: Allow symlinks in shared folder (#1001) 2025-01-08 15:38:51 +01:00
Kroese
1081855571 feat: Update download links (#996) 2025-01-06 19:26:45 +01:00
Kroese
57193b0f59 fix: Follow download redirects (#981) 2024-12-20 18:32:26 +01:00
Kroese
6825b6a45a fix: Update download links (#980) 2024-12-20 15:43:37 +01:00
Kroese
c82725ec61 docs: Readme (#958) 2024-12-06 11:19:42 +01:00
Kroese
1f0cdc9bd1 build: Update qemu-docker to v6.11 (#946) 2024-12-03 12:12:47 +01:00
Kilian von Pflugk
9654a945fb docs: Add TUN device (#940) 2024-12-01 17:07:23 +01:00
renovate[bot]
a4fdfbdf91 chore(deps): update qemux/qemu-docker docker tag to v6.10 (#929) 2024-11-26 20:16:47 +01:00
Kroese
b84a2b60a9 feat: Additional download mirrors (#923) 2024-11-24 22:00:24 +01:00
Kroese
a5b4d7760d docs: Readme (#920) 2024-11-20 13:27:15 +01:00
9 changed files with 185 additions and 1011 deletions

View File

@@ -1,7 +1,7 @@
ARG VERSION_ARG="latest"
FROM scratch AS build-amd64
COPY --from=qemux/qemu-docker:6.08 / /
COPY --from=qemux/qemu:6.18 / /
ARG DEBCONF_NOWARNINGS="yes"
ARG DEBIAN_FRONTEND="noninteractive"
@@ -29,8 +29,7 @@ RUN set -eu && \
COPY --chmod=755 ./src /run/
COPY --chmod=755 ./assets /run/assets
ADD --chmod=755 https://raw.githubusercontent.com/christgau/wsdd/v0.8/src/wsdd.py /usr/sbin/wsdd
ADD --chmod=664 https://github.com/qemus/virtiso-whql/releases/download/v1.9.43-0/virtio-win-1.9.43.tar.xz /drivers.txz
ADD --chmod=664 https://github.com/qemus/virtiso-whql/releases/download/v1.9.44-0/virtio-win-1.9.44.tar.xz /drivers.txz
FROM dockurr/windows-arm:${VERSION_ARG} AS build-arm64
FROM build-${TARGETARCH}

View File

@@ -6,10 +6,12 @@ services:
VERSION: "11"
devices:
- /dev/kvm
- /dev/net/tun
cap_add:
- NET_ADMIN
ports:
- 8006:8006
- 3389:3389/tcp
- 3389:3389/udp
restart: always
stop_grace_period: 2m

View File

@@ -1,10 +1,11 @@
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: windows-pvc
spec:
accessModes:
- ReadWriteOnce
- ReadWriteOnce
resources:
requests:
storage: 64Gi
@@ -16,59 +17,61 @@ metadata:
labels:
name: windows
spec:
terminationGracePeriodSeconds: 120 # the Kubernetes default is 30 seconds and it may be not enough
containers:
- name: windows
image: dockurr/windows
ports:
- containerPort: 8006
protocol: TCP
- containerPort: 3389
protocol: TCP
- containerPort: 3389
protocol: UDP
securityContext:
privileged: true
env:
- name: VERSION
value: "11"
- name: RAM_SIZE
value: "4G"
- name: CPU_CORES
value: "2"
- name: DISK_SIZE
value: "64G"
volumeMounts:
- mountPath: /storage
name: storage
- mountPath: /dev/kvm
name: dev-kvm
- name: windows
image: dockurr/windows
env:
- name: VERSION
value: "11"
- name: RAM_SIZE
value: "4G"
- name: CPU_CORES
value: "2"
- name: DISK_SIZE
value: "64G"
ports:
- containerPort: 8006
- containerPort: 3389
- containerPort: 3389
protocol: UDP
securityContext:
capabilities:
add:
- NET_ADMIN
privileged: true
volumeMounts:
- mountPath: /storage
name: storage
- mountPath: /dev/kvm
name: dev-kvm
- mountPath: /dev/net/tun
name: dev-tun
terminationGracePeriodSeconds: 120
volumes:
- name: storage
persistentVolumeClaim:
claimName: windows-pvc
- name: dev-kvm
hostPath:
path: /dev/kvm
- name: storage
persistentVolumeClaim:
claimName: windows-pvc
- hostPath:
path: /dev/kvm
name: dev-kvm
- hostPath:
path: /dev/net/tun
type: CharDevice
name: dev-tun
---
apiVersion: v1
kind: Service
metadata:
name: windows
spec:
type: NodePort
ports:
- name: tcp-8006
port: 8006
- name: tcp-3389
port: 3389
- name: udp-3389
port: 3389
protocol: UDP
selector:
name: windows
ports:
- name: tcp-8006
protocol: TCP
port: 8006
targetPort: 8006
- name: tcp-3389
protocol: TCP
port: 3389
targetPort: 3389
- name: udp-3389
protocol: UDP
port: 3389
targetPort: 3389
type: NodePort

View File

@@ -37,19 +37,21 @@ services:
VERSION: "11"
devices:
- /dev/kvm
- /dev/net/tun
cap_add:
- NET_ADMIN
ports:
- 8006:8006
- 3389:3389/tcp
- 3389:3389/udp
restart: always
stop_grace_period: 2m
```
Via Docker CLI:
```bash
docker run -it --rm -p 8006:8006 --device=/dev/kvm --cap-add NET_ADMIN --stop-timeout 120 dockurr/windows
docker run -it --rm -p 8006:8006 --device=/dev/kvm --device=/dev/net/tun --cap-add NET_ADMIN --stop-timeout 120 dockurr/windows
```
Via Kubernetes:
@@ -84,7 +86,7 @@ kubectl apply -f https://raw.githubusercontent.com/dockur/windows/refs/heads/mas
### How do I select the Windows version?
By default, Windows 11 will be installed. But you can add the `VERSION` environment variable to your compose file, in order to specify an alternative Windows version to be downloaded:
By default, Windows 11 Pro will be installed. But you can add the `VERSION` environment variable to your compose file, in order to specify an alternative Windows version to be downloaded:
```yaml
environment:
@@ -96,8 +98,8 @@ kubectl apply -f https://raw.githubusercontent.com/dockur/windows/refs/heads/mas
| **Value** | **Version** | **Size** |
|---|---|---|
| `11` | Windows 11 Pro | 5.4 GB |
| `11l` | Windows 11 LTSC | 4.2 GB |
| `11e` | Windows 11 Enterprise | 5.8 GB |
| `11l` | Windows 11 LTSC | 4.7 GB |
| `11e` | Windows 11 Enterprise | 4.0 GB |
||||
| `10` | Windows 10 Pro | 5.7 GB |
| `10l` | Windows 10 LTSC | 4.6 GB |
@@ -176,7 +178,9 @@ kubectl apply -f https://raw.githubusercontent.com/dockur/windows/refs/heads/mas
### How do I run a script after installation?
To run your own script after installation, you can create a file called `install.bat` and place it in a folder together with any additional files it needs (software to be installed for example). Then bind that folder in your compose file like this:
To run your own script after installation, you can create a file called `install.bat` and place it in a folder together with any additional files it needs (software to be installed for example).
Then bind that folder in your compose file like this:
```yaml
volumes:

File diff suppressed because it is too large Load Diff

View File

@@ -1,10 +1,9 @@
#!/usr/bin/env bash
set -Eeuo pipefail
: "${APP:="Windows"}"
: "${BOOT_MODE:="windows"}"
APP="Windows"
SUPPORT="https://github.com/dockur/windows"
: "${SUPPORT:="https://github.com/dockur/windows"}"
cd /run

View File

@@ -76,8 +76,6 @@ startInstall() {
BOOT="$STORAGE/$file"
! migrateFiles "$BOOT" "$VERSION" && error "Migration failed!" && exit 57
fi
skipInstall "$BOOT" && return 1
@@ -202,10 +200,16 @@ abortInstall() {
detectCustom() {
local file base
local fname="custom.iso"
CUSTOM=""
file=$(find / -maxdepth 1 -type f -iname custom.iso | head -n 1)
[ ! -s "$file" ] && file=$(find "$STORAGE" -maxdepth 1 -type f -iname custom.iso | head -n 1)
if [ -d "/$fname" ]; then
error "The file /$fname has an invalid path!" && return 1
fi
file=$(find / -maxdepth 1 -type f -iname "$fname" | head -n 1)
[ ! -s "$file" ] && file=$(find "$STORAGE" -maxdepth 1 -type f -iname "$fname" | head -n 1)
if [ ! -s "$file" ] && [[ "${VERSION,,}" != "http"* ]]; then
base=$(basename "$VERSION")
@@ -489,6 +493,10 @@ setXML() {
local file="/custom.xml"
if [ -d "$file" ]; then
warn "The file $file has an invalid path!"
fi
[ ! -f "$file" ] || [ ! -s "$file" ] && file="$STORAGE/custom.xml"
[ ! -f "$file" ] || [ ! -s "$file" ] && file="/run/assets/custom.xml"
[ ! -f "$file" ] || [ ! -s "$file" ] && file="$1"
@@ -668,6 +676,11 @@ updateXML() {
sed -z "s/<AdministratorPassword>...............<Value \/>/<AdministratorPassword>\n <Value>$admin<\/Value>/g" -i "$asset"
fi
if [ -n "$EDITION" ]; then
[[ "${EDITION^^}" == "CORE" ]] && EDITION="STANDARDCORE"
sed -i "s/SERVERSTANDARD<\/Value>/SERVER${EDITION^^}<\/Value>/g" "$asset"
fi
return 0
}
@@ -677,8 +690,13 @@ addDriver() {
local path="$2"
local target="$3"
local driver="$4"
local desc=""
local folder=""
if [ -z "$id" ]; then
warn "no Windows version specified for \"$driver\" driver!" && return 0
fi
case "${id,,}" in
"win7x86"* ) folder="w7/x86" ;;
"win7x64"* ) folder="w7/amd64" ;;
@@ -698,7 +716,8 @@ addDriver() {
esac
if [ -z "$folder" ]; then
warn "no \"$driver\" driver found for \"$DETECTED\" !" && return 0
desc=$(printVersion "$id" "$id")
warn "no \"$driver\" driver available for \"$desc\" !" && return 0
fi
[ ! -d "$path/$driver/$folder" ] && return 0
@@ -731,6 +750,11 @@ addDrivers() {
local msg="Adding drivers to image..."
info "$msg" && html "$msg"
if [ -z "$version" ]; then
version="win11x64"
warn "Windows version unknown, falling back to Windows 11 drivers..."
fi
if ! bsdtar -xf /drivers.txz -C "$drivers"; then
error "Failed to extract drivers from archive!" && return 1
fi

View File

@@ -4,25 +4,26 @@ set -Eeuo pipefail
handle_curl_error() {
local error_code="$1"
local server_name="$2"
case "$error_code" in
1) error "Unsupported protocol!" ;;
2) error "Failed to initialize curl!" ;;
3) error "The URL format is malformed!" ;;
5) error "Failed to resolve address of proxy host!" ;;
6) error "Failed to resolve Microsoft servers! Is there an Internet connection?" ;;
7) error "Failed to contact Microsoft servers! Is there an Internet connection or is the server down?" ;;
8) error "Microsoft servers returned a malformed HTTP response!" ;;
6) error "Failed to resolve $server_name servers! Is there an Internet connection?" ;;
7) error "Failed to contact $server_name servers! Is there an Internet connection or is the server down?" ;;
8) error "$server_name servers returned a malformed HTTP response!" ;;
16) error "A problem was detected in the HTTP2 framing layer!" ;;
22) error "Microsoft servers returned a failing HTTP status code!" ;;
22) error "$server_name servers returned a failing HTTP status code!" ;;
23) error "Failed at writing Windows media to disk! Out of disk space or permission error?" ;;
26) error "Failed to read Windows media from disk!" ;;
27) error "Ran out of memory during download!" ;;
28) error "Connection timed out to Microsoft server!" ;;
35) error "SSL connection error from Microsoft server!" ;;
28) error "Connection timed out to $server_name server!" ;;
35) error "SSL connection error from $server_name server!" ;;
36) error "Failed to continue earlier download!" ;;
52) error "Received no data from the Microsoft server!" ;;
63) error "Microsoft servers returned an unexpectedly large response!" ;;
52) error "Received no data from the $server_name server!" ;;
63) error "$server_name servers returned an unexpectedly large response!" ;;
# POSIX defines exit statuses 1-125 as usable by us
# https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_08_02
$((error_code <= 125)))
@@ -100,7 +101,7 @@ download_windows() {
# Remove "Accept" header that curl sends by default
[[ "$DEBUG" == [Yy1]* ]] && echo "Parsing download page: ${url}"
download_page_html=$(curl --silent --max-time 30 --user-agent "$user_agent" --header "Accept:" --max-filesize 1M --fail --proto =https --tlsv1.2 --http1.1 -- "$url") || {
handle_curl_error $?
handle_curl_error "$?" "Microsoft"
return $?
}
@@ -117,14 +118,14 @@ download_windows() {
# Permit Session ID
curl --silent --max-time 30 --output /dev/null --user-agent "$user_agent" --header "Accept:" --max-filesize 100K --fail --proto =https --tlsv1.2 --http1.1 -- "https://vlscppe.microsoft.com/tags?org_id=y6jn8c31&session_id=$session_id" || {
# This should only happen if there's been some change to how this API works
handle_curl_error $?
handle_curl_error "$?" "Microsoft"
return $?
}
[[ "$DEBUG" == [Yy1]* ]] && echo -n "Getting language SKU ID: "
sku_url="https://www.microsoft.com/software-download-connector/api/getskuinformationbyproductedition?profile=$profile&ProductEditionId=$product_edition_id&SKU=undefined&friendlyFileName=undefined&Locale=en-US&sessionID=$session_id"
language_skuid_json=$(curl --silent --max-time 30 --request GET --user-agent "$user_agent" --referer "$url" --header "Accept:" --max-filesize 100K --fail --proto =https --tlsv1.2 --http1.1 -- "$sku_url") || {
handle_curl_error $?
handle_curl_error "$?" "Microsoft"
return $?
}
@@ -229,7 +230,7 @@ download_windows_eval() {
[[ "$DEBUG" == [Yy1]* ]] && echo "Parsing download page: ${url}"
iso_download_page_html=$(curl --silent --max-time 30 --user-agent "$user_agent" --location --max-filesize 1M --fail --proto =https --tlsv1.2 --http1.1 -- "$url") || {
handle_curl_error $?
handle_curl_error "$?" "Microsoft"
return $?
}
@@ -241,10 +242,10 @@ download_windows_eval() {
[[ "$DEBUG" == [Yy1]* ]] && echo "Getting download link.."
if [[ "$enterprise_type" == "iot" ]]; then
filter="https://go.microsoft.com/fwlink/?linkid=[0-9]\+&clcid=0x[0-9a-z]\+&culture=${culture,,}&country=${country^^}"
else
filter="https://go.microsoft.com/fwlink/p/?LinkID=[0-9]\+&clcid=0x[0-9a-z]\+&culture=${culture,,}&country=${country^^}"
filter="https://go.microsoft.com/fwlink/?linkid=[0-9]\+&clcid=0x[0-9a-z]\+&culture=${culture,,}&country=${country,,}"
if ! echo "$iso_download_page_html" | grep -io "$filter" > /dev/null; then
filter="https://go.microsoft.com/fwlink/p/?linkid=[0-9]\+&clcid=0x[0-9a-z]\+&culture=${culture,,}&country=${country,,}"
fi
iso_download_links=$(echo "$iso_download_page_html" | grep -io "$filter") || {
@@ -287,7 +288,7 @@ download_windows_eval() {
iso_download_link=$(curl --silent --max-time 30 --user-agent "$user_agent" --location --output /dev/null --silent --write-out "%{url_effective}" --head --fail --proto =https --tlsv1.2 --http1.1 -- "$iso_download_link") || {
# This should only happen if the Microsoft servers are down
handle_curl_error $?
handle_curl_error "$?" "Microsoft"
return $?
}

View File

@@ -71,6 +71,9 @@ addShare() {
echo " guest account = nobody"
echo " map to guest = Bad User"
echo " server min protocol = NT1"
echo " follow symlinks = yes"
echo " wide links = yes"
echo " unix extensions = no"
echo ""
echo " # disable printing services"
echo " load printers = no"
@@ -89,6 +92,13 @@ addShare "$share" "Data" "Shared" || error "Failed to create shared folder!"
[ -d "/data2" ] && addShare "/data2" "Data2" "Shared"
[ -d "/data3" ] && addShare "/data3" "Data3" "Shared"
IFS=',' read -r -a dirs <<< "${SHARES:-}"
for dir in "${dirs[@]}"; do
[ ! -d "$dir" ] && continue
dir_name=$(basename "$dir")
addShare "$dir" "$dir_name" "Shared $dir_name" || error "Failed to create shared folder for $dir!"
done
if ! smbd; then
error "Samba daemon failed to start!"
smbd -i --debug-stdout || true