diff --git a/Dockerfile b/Dockerfile index 2cae925..d15e875 100644 --- a/Dockerfile +++ b/Dockerfile @@ -10,6 +10,7 @@ RUN apt-get update \ wget \ ovmf \ socat \ + nginx \ procps \ iptables \ iproute2 \ @@ -20,10 +21,18 @@ RUN apt-get update \ ca-certificates \ netcat-openbsd \ qemu-system-x86 \ + && novnc="v1.4.0" \ + && wget https://github.com/novnc/noVNC/archive/refs/tags/$novnc.tar.gz -O /tmp/novnc.tar.gz -q \ + && tar -xf /tmp/novnc.tar.gz -C /tmp/ \ + && cd /tmp/noVNC-$novnc \ + && mkdir -p /usr/share/novnc \ + && mv app core vendor package.json *.html /usr/share/novnc \ && apt-get clean \ && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* COPY ./src /run/ +COPY nginx.conf /etc/nginx/sites-enabled/novnc.conf + RUN chmod +x /run/*.sh VOLUME /storage diff --git a/docker-compose.yml b/docker-compose.yml index 8a818c6..3ca3fb6 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,22 +1,20 @@ version: "3" services: - qemu: - container_name: qemu - image: qemux/qemu-docker:latest - environment: - DISPLAY: "vnc" - RAM_SIZE: "1G" - CPU_CORES: "1" - DISK_SIZE: "16G" - BOOT: "https://dl-cdn.alpinelinux.org/alpine/v3.19/releases/x86_64/alpine-virt-3.19.0-x86_64.iso" - devices: - - /dev/kvm - device_cgroup_rules: - - 'c *:* rwm' - cap_add: - - NET_ADMIN - ports: - - 2222:22 - - 5900:5900 - stop_grace_period: 2m - restart: unless-stopped + qemu: + container_name: qemu + image: qemux/qemu-docker + environment: + RAM_SIZE: "1G" + CPU_CORES: "1" + DISK_SIZE: "16G" + BOOT: "https://dl-cdn.alpinelinux.org/alpine/v3.19/releases/x86_64/alpine-virt-3.19.0-x86_64.iso" + devices: + - /dev/kvm + device_cgroup_rules: + - 'c *:* rwm' + cap_add: + - NET_ADMIN + ports: + - 8006:8006 + stop_grace_period: 2m + restart: unless-stopped diff --git a/nginx.conf b/nginx.conf new file mode 100644 index 0000000..5a4988f --- /dev/null +++ b/nginx.conf @@ -0,0 +1,49 @@ +server { + + listen 8006 default_server; + listen [::]:8006 default_server; + + autoindex on; + server_name _; + tcp_nodelay on; + server_tokens off; + + error_log /dev/null; + access_log /dev/null; + + include /etc/nginx/mime.types; + + location / { + + gzip on; + gzip_vary on; + gzip_proxied any; + gzip_comp_level 5; + gzip_min_length 500; + gzip_disable "msie6"; + gzip_types text/css text/javascript text/xml text/plain text/x-component application/javascript application/json application/xml application/rss+xml font/truetype font/opentype application/vnd.ms-fontobject image/svg+xml; + + add_header Cache-Control "no-cache"; + + root /usr/share/novnc; + index vnc.html; + + if ($request_uri = "/") { + return 301 /?resize=scale&autoconnect=true; + } + + } + + location /websockify { + + proxy_pass http://127.0.0.1:5700/; + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection 'upgrade'; + proxy_read_timeout 61s; + proxy_connect_timeout 61s; + proxy_send_timeout 61s; + + } + +} diff --git a/readme.md b/readme.md index 14f5efb..64b872b 100644 --- a/readme.md +++ b/readme.md @@ -1,4 +1,4 @@ -

QEMU in Docker
+

QEMU
@@ -32,15 +32,13 @@ services: container_name: qemu image: qemux/qemu-docker environment: - DISPLAY: "vnc" BOOT: "https://dl-cdn.alpinelinux.org/alpine/v3.19/releases/x86_64/alpine-virt-3.19.0-x86_64.iso" devices: - /dev/kvm cap_add: - NET_ADMIN ports: - - 2222:22 - - 5900:5900 + - 8006:8006 stop_grace_period: 2m restart: unless-stopped ``` @@ -48,7 +46,7 @@ services: Via `docker run` ```bash -docker run -it --rm -e "DISPLAY=vnc" -e "BOOT=http://example.com/image.iso" -p 5900:5900 --device=/dev/kvm --cap-add NET_ADMIN qemux/qemu-docker +docker run -it --rm -e "BOOT=http://example.com/image.iso" -p 8006:8006 --device=/dev/kvm --cap-add NET_ADMIN qemux/qemu-docker ``` ## FAQ @@ -166,7 +164,7 @@ docker run -it --rm -e "DISPLAY=vnc" -e "BOOT=http://example.com/image.iso" -p 5 Please note that in this mode, the container and the VM will each have their own separate IPs. The container will keep the macvlan IP, and the VM will be reachable via the DHCP IP. - * ### How do I pass-through a disk? + * ### How do I pass-through a disk? It is possible to pass-through disk devices directly by adding them to your compose file in this way: diff --git a/src/display.sh b/src/display.sh index 7bd3253..6c2fc6c 100644 --- a/src/display.sh +++ b/src/display.sh @@ -3,20 +3,22 @@ set -Eeuo pipefail # Docker environment variables -: "${GPU:="N"}" # GPU passthrough -: "${DISPLAY:="none"}" # Display type +: "${GPU:="N"}" # GPU passthrough +: "${VGA:="virtio"}" # VGA adaptor +: "${DISPLAY:="web"}" # Display type case "${DISPLAY,,}" in vnc) - DISPLAY_OPTS="-display vnc=:0 -vga virtio" + DISPLAY_OPTS="-display vnc=:0 -vga $VGA" ;; web) - addPackage "novnc" "web-based VNC client" - ln -sfn /usr/share/novnc/vnc_lite.html /usr/share/novnc/index.html - DISPLAY_OPTS="-display vnc=:0 -vga virtio" + DISPLAY_OPTS="-display vnc=:0,websocket=5700 -vga $VGA" ;; + none) + DISPLAY_OPTS="-display none -vga none" + ;; *) - DISPLAY_OPTS="-display $DISPLAY -vga none" + DISPLAY_OPTS="-display $DISPLAY -vga $VGA" ;; esac @@ -24,8 +26,10 @@ if [[ "$GPU" != [Yy1]* ]] || [[ "$ARCH" != "amd64" ]]; then return 0 fi -DISPLAY_OPTS="-display egl-headless,rendernode=/dev/dri/renderD128 -vga virtio" -[[ "${DISPLAY,,}" == "vnc" || "${DISPLAY,,}" == "web" ]] && DISPLAY_OPTS="$DISPLAY_OPTS -vnc :0" +DISPLAY_OPTS="-display egl-headless,rendernode=/dev/dri/renderD128 -vga $VGA" + +[[ "${DISPLAY,,}" == "vnc" ]] && DISPLAY_OPTS="$DISPLAY_OPTS -vnc :0" +[[ "${DISPLAY,,}" == "web" ]] && DISPLAY_OPTS="$DISPLAY_OPTS -vnc :0,websocket=5700" [ ! -d /dev/dri ] && mkdir -m 755 /dev/dri diff --git a/src/entry.sh b/src/entry.sh index 1568105..979e2b0 100755 --- a/src/entry.sh +++ b/src/entry.sh @@ -18,7 +18,7 @@ cd /run trap - ERR if [[ "${DISPLAY,,}" == "web" ]]; then - websockify -D --web /usr/share/novnc/ 8006 localhost:5900 2>/dev/null + nginx -e stderr fi info "Booting image using $VERS..."