Seamless Windows Apps on openSUSE with WinBoat

I have previously shared how I hav been able to acheive nearly seamless integration of openSUSE in a Microsoft Office 365 Environment using different applicaitons or Codeweavers Crossover Linux for Microsoft Office 365. I have essentially achieved running a Linux desktop in a Windows environment but for one (arguably three) application(s) that is holding me to keeping a dedicated Windows machine for just one application. For clarification, the other two applications could just be run on the rare occasion in a traditional VM. I rarely need them but they are good to have available. The day has now arrived where I now have achieved a kind of Windows freedom… sort of… on my daily driving Framework Laptop 13 running openSUSE Tumbleweed. Never having to use the Windows 11 Desktop to get critical portions of my job completed is a dream come true.

With my role at my company, I occasionally need reliable access to one Windows-only applications, the Milestone XProtect Smart Client for our facility NVR system, Rufus for creating bootable USB drives and this HuionTablet for managing or configuring a Bluetooth multi-function keypad. Rather than dual-booting, which is completely out of the question or continuing to maintain a separate Windows machine, I turned to WinBoat, an open-source tool that runs a full Windows VM inside a Docker container with KVM acceleration and seamless FreeRDP integration. So, I am sort of Windows-less and not exactly. I can say, I am Windows Desktop free

Bottom Line Up Front: It’s a bit fiddly but when it works, it works fantastically well. I don’t have this completely dialed in but it is 90% there. I want to publish my process, what I tweaked and how I am ensuring that I don’t have any serious security issues along with my wishlist in features. Overall, I’m about 90% happy with it but I’m not sure if the work that needs to be done is on the WinBoat side or the FreeRDP side.

Background

Winboat lets Windows apps appear as native Linux windows on my openSUSE Tumbleweed, KDE Plasma desktop. I’ve been testing WinBoat for a few weeks now, and while the core experience is excellent, the setup on a rolling-release distro like Tumbleweed with an active firewall required a few tweaks. This article documents my journey: from initial trials, through network conflicts, shared folder integration, to my final configuration.

Trying Out WinBoat

WinBoat is straightforward to install on Linux. It provides both AppImage and RPM packages. I chose the RPM for better integration with openSUSE’s package manager. I have used both but in this case, I do prefer the RPM.

https://github.com/TibixDev/winboat/releases

After installation, the WinBoat dashboard guides you through creating the Windows container. I opted for Windows 11 IoT Enterprise LTSC 2024 (evaluation ISO, seems like you can’t just outright buy a license). I chose this because it’s stripped down, and receives only security updates, and has a 10-year support lifecycle which is perfect for a fixed-function environment like mine.

As far as to the installation process is concerned, since I’m using the LTSC version of Windows 11, I don’t have to provide too many resources: 6 cores and 8 GB of RAM and I do not leave WinBoat running and I also do not auto start the container. I also want to be able to access my local home folder so I have selected to Share my home folder. Sharing the home folder does not work without making a tweak, more on that later.

Screenshot of WinBoat configuration settings showing options for RAM allocation, CPU cores, shared home folder, auto start container, and FreeRDP port.

The Docker Network Conflict

Early on, I noticed I couldn’t reach the internal network of my Texas facility (172.18.0.0/16) from my laptop. Pinging internal addresses returned “host unreachable.” I didn’t notice this immediately because of how Tailscale somehow masked this problem but if I shut off Tailscale or if I wanted to access another Tailscale account, I lost my connection to the Texas facility.

The culprit?

Docker had created a custom bridge network on exactly the same subnet: br-eeea193cd282 with gateway 172.18.0.1. Linux routing preferred the local Docker bridge over sending packets out my Wi-Fi interface. I found this by typing in the terminal ip route show.

172.17.0.0/16 dev docker0 proto kernel scope link src 172.17.0.1 linkdown
172.18.0.0/16 dev br-eeea193cd282 proto kernel scope link src 172.18.0.1 linkdown
172.18.0.0/16 via 192.168.6.254 dev wlp170s0 proto static metric 100 

Diagnosis

ip route show revealed the conflicting route: 172.18.0.0/16 dev br-eeea193cd282 …

ip route get 172.18.5.10 confirmed packets were being sent to the local bridge which confirmed that I was unable to access anything in that Texas facility. Docker was hijacking my network!

Fix

Temporarily remove the route, first view the routes to verify there is an offending route: sudo ip route show

default via 10.91.168.90 dev wlp170s0 proto dhcp src 10.91.168.136 metric 600  
10.91.168.0/24 dev wlp170s0 proto kernel scope link src 10.91.168.136 metric 600  
172.17.0.0/24 dev docker0 proto kernel scope link src 172.17.0.1 linkdown
172.18.0.0/24 dev br-eeea193cd282 proto kernel scope link src 172.18.1.1

To remove the troublesome route:

sudo ip route del 172.18.0.0/16

Identify the offending network: docker network ls

NETWORK ID     NAME              DRIVER    SCOPE
7e2f9dd951d7   bridge            bridge    local
1372b373621f   host              host      local
a3b08262916a   none              null      local
321ce7d8c762   winboat_default   bridge    local

Then run docker network inspect <id> were <id> is the NETWORK ID from the list. The output will further confirm the offending network route.

The next step will be to permanently prevent recurrence by reconfiguring Docker’s address pools.

I added this segment into /etc/docker/daemon.json

{
  "bip": "10.200.0.1/24",
  "default-address-pools": [
    {"base": "10.200.0.0/16", "size": 24}
  ]
}

Since you may have some lines in your json file, I thought I would provide additional context, my full daemon.json looks like this:

{
"log-level": "warn",
"log-driver": "json-file",
"log-opts": {
"max-size": "10m",
"max-file": "5"
},
"selinux-enabled": true,
"bip": "10.200.0.1/24",
"default-address-pools": [
{
"base": "10.200.0.0/16",
"size": 24
}
]
}

You may have to adjust your file accordingly.

Once the adjustments are complete, restart Docker:

sudo systemctl restart docker

This forces the default docker0 bridge onto 10.200.0.0/24 and allocates future custom networks (like WinBoat’s) from safe 10.200.x.0/24 ranges. After removing the old conflicting network, facility access was restored.

Docker vs. Podman

WinBoat recently added Podman support, which is tempting on openSUSE Tumbleweed (where Podman is the preferred container runtime). Podman is daemonless, rootless by default, and generally lighter on battery life which is certainly important for laptop use. I considered switching, especially since I already use Distrobox (which works great with Podman). However, one feature held me back: USB passthrough.

WinBoat’s USB device forwarding (critical for Rufus and other Windows only configuration tools I use) currently only works with Docker. Podman support for this is on the roadmap but not yet implemented. For now, Docker remains the practical choice despite its small idle overhead.

Shared Home Folder

One aspect that was very important is being able to access my local file system for access to applications or files. I keep a small repository of Windows applications locally. I may also toy around with running Microsoft Office 365 through WinBoat to see how it performs in comparison with Crossover Linux. In order to be able to do this, I had to Removing Privileged Mode in the default WinBoat docker-compose.ymal. Although it should the privileged: true should grant near-full host access, it seemingly disallows the shared home folder. After testing, I found everything worked fine without it:

  • KVM acceleration via /dev/kvm device passthrough
  • USB devices via explicit /dev/bus/usb binding
  • Shared home directory access

I simply commented out the line:

    # privileged: true

My final relevant docker-compose.yml section (heavily inspired by the WinBoat defaults but customized):

name: winboat
volumes:
  data:
services:
  windows:
    image: ghcr.io/dockur/windows:5.14
    container_name: WinBoat
    environment:
      VERSION: 11l
      RAM_SIZE: 8G
      CPU_CORES: "4"
      DISK_SIZE: 32G
      USERNAME: wolfnf
      PASSWORD: password
      HOME: ${HOME}
      LANGUAGE: English
      USER_PORTS: "7148"
      HOST_PORTS: "7149"
      ARGUMENTS: -qmp tcp:0.0.0.0:7149,server,wait=off
    cap_add:
      - NET_ADMIN
    # privileged: true
    ports:
      - 127.0.0.1:47270-47279:8006/tcp
      - 127.0.0.1:47280-47289:7148/tcp
      - 127.0.0.1:47290-47299:7149/tcp
      - 127.0.0.1:47300-47309:3389/tcp
      - 127.0.0.1:47300-47309:3389/udp
    stop_grace_period: 120s
    restart: no
    volumes:
      - /home/wolfnf/winboat:/storage
      - ${HOME}:/shared
      - /dev/bus/usb:/dev/bus/usb
      - ./oem:/oem
    devices:
      - /dev/kvm

Key notes

  • All ports are bound to 127.0.0.1 only—no external exposure. This provides some protection against bad actors trying to infect your system with malware which is known to have happened.
  • restart: no prevents automatic startup at boot.
  • Combined with openSUSE’s active firewall (which blocks everything by default), this keeps the attack surface minimal.

Experience

Overall, the seamless mode works remarkably well once everything has been configured properly. I have tried both Windows 11 Pro and Windows 11 LTSC and they really work about the same except resources are much lighter with LTSC. With Windows is installed and the guest agent is running, the Windows applications I need that do not work through Crossover Linux, like Milestone XProtect, Rufus and this HuionTablet configuration tool launch as individual windows that behave like native Wayland apps. That is, running on KDE Plasma using the Wayland graphics platform the applications register on the task manager with the proper icons. All things considered, the docker embeded VM doesn’t seem to chew to chew up as many resources as I would have thought. Though, I am using the LTSC version and I don’t believe I am running the entire desktop environment, but I could be wrong on that. My evidence for that is if I open a full RDP session into the Windows Desktop performing the exact same task, the ram usage is closer to 3.6 GB instead of around 2.8 GB. More testing should be done here.

Screenshot of the WinBoat application interface showing the status of the Windows 11 LTSC 2024 container, with metrics for CPU, RAM, and Disk usage.

A note on the icons, Plasma will automatically group all of the FreeRDP-WinBoat applications so you will have to unselect that option by right clicking on the task manager icon > More > Allow this program to be grouped (KDE Plasma, not sure any other Desktop Environment).

I have a multi-monitor setup on my home, lab and office workstations, under the General Configuration, I set Multi-Monitor Support to “Multimon” over Span or None. My reasoning for this is that Multimon tends to handle my screen layout better than Span which will often put the application window off into a non-visible are of my display and none will force the applications to snap to a monitor of WinBoat or FreeRDPs choosing (not sure what is making the decision). That particular mode can be somewhat amusing when you go to resize a window and in the process the window shoots to another display. Somewhat amusing…

Screenshot of the WinBoat application configuration interface, showing settings for RDP session, display scaling, application scaling, multi-monitor support, smartcard passthrough, RDP monitoring, and experimental features.

I do prefer to keep RDP Monitoring active as it provides a little indicator when the RDP Session is active. I find that good for troubleshooting and I haven’t had any performance issues with this setting.

What I Like

I have no more reason to run a Windows desktop in the workplace. I am able to do everything, effectively, from my Linux Desktop. Sure, it is a bit of trickery, running Windows 11 LTSC in a docker image with a bit of KVM acceleration.

With WinBoat tweaked for my preferences, I am able to run the occasional Windows application as needed to accomplish very specific tasks, in this case, accessing the Windows only NVR software or writing Windows specific installation images to a USB drive. Both of these applications require that USB Passthrough be enabled which is considered an experimental feature. I have not had any issues with this particular feature but that is something to be noted.

The performance of WinBoat is far better than using straight KVM or Virtual Box for working within Windows. There do appear to be some issues with FreeRDP but it is not always an issue. The solution is to stop and restart the container.

Criticisms

Oh boy. I am not poopooing on this at all, it is still in Beta so I know that things will improve but I do have some issues with WinBoat. After setting it up and tweaking it, just the way I like, it still has its hiccups. I want to emphasize that I am largely incredibly happy with WinBoat and these are nitpicks, not show stoppers and I am very glad that I am able to use this on my Linux distribution of choice.

When I starting an application, there is no feedback tell me that the application is starting. This is further compounded by having issues with my multimonitor arrangement where I am not always able to launch the application. For some reason, when I am using the Multi-Monitor support settings of “multimon” or “span”, the application will just not launch. Often, my fix is just setting it to “none” and the applications will launch. It’s certainly puzzling.

Newly installed applications don’t show up in the Apps list, even after hitting refresh, which, it should be noted is a really cool animation. It seems I have to stop and restart WinBoat for the new application to register.

Weirdness with window boarders

I do have instances where the RDP Session is noted as Active on the WinBoat application window with no active RDP session with which to interact. It’s an odd behavior that I am not able to reliably recreate. The fix for it is to stop the container and restart it from the home section of the WinBoat application window.

WinBoat lacks a straight forward way to integrate Windows application into the native (KDE Plasma) menu. It is or at least should be possible but it is not a straight forward or robust solution. It should be noted that this probably wouldn’t work well for me since I often keep the container off. I actually don’t have a good solution for this implementation, maybe some sort of tray icon to toggle the WinBoat container with a favorites menu from there but that seems like a lot of work for a small convenience.

Final Thoughts

WinBoat has proven surprisingly stable and far more performant than expected on my openSUSE Tumbleweed, Framework Laptop 13. The seamless integration makes using Windows applications feel mostly natural on my Wayland desktop whether it is in single display mode or with four monitors in an admittedly oddly stacked arrangement. The main application I need this for, Milestone XProtect runs smoothly, and Rufus works perfectly with USB passthrough. While there were initial hurdles, such as the Docker network conflict, the fixes were straightforward and I learned a thing. Behind Tumbleweed’s firewall, and without auto-start gives me confidence in the setup’s security posture is resilient enough to continue to use. I am also leaning much heaver towards using the LTSC version as it has most of the Windows 11 cruft stripped out. As an aside, LTSC really should be the default Windows 11 Pro experience and there should be toggles for adding the additional “consumer” bits but that would make too much sense.

For anyone needing occasional Windows app access on Linux without the overhead of an [arguably] full VM or dual-boot, WinBoat is worth trying. Having just an application window and not the fully desktop is a chef’s kiss. If you plan to try this out be prepared for a few container networking gotchas, especially if your organization uses private RFC 1918 ranges that overlap Docker’s defaults. If you are not running with a firewall, you really should take the time to enable one and work through any issues that may arise from it. I would also recommend you still use WinBoat as a last-resort solution, not because I think there is anything wrong with it but the increased overhead of running a VM is not insignificant.

I am very happy WinBoat is a thing and it makes me wonder, how much more difficult would it be to do the same thing but with MacOS applications? Not that there is much of anything on Mac worth running, but it would be nice to have the option.

References

WinBoat GitHub: https://github.com/dockur/winboat
dockur/windows repository: https://github.com/dockur/windows
openSUSE Tumbleweed: https://get.opensuse.org


Discover more from CubicleNate.com

Subscribe to get the latest posts sent to your email.


Comments

One response to “Seamless Windows Apps on openSUSE with WinBoat”

Leave a Reply

Discover more from CubicleNate.com

Subscribe now to keep reading and get access to the full archive.

Continue reading