Automating legacy Windows app on a headless Ubuntu server. Is Wine/Xvfb the right choice?
Posted by No_Addendum4340@reddit | sysadmin | View on Reddit | 49 comments
Hi, all. I'mI'm working on automating a legacy Windows desktop application (built on an old Gupta SQLWindows framework) on a headless Ubuntu server. I finally got it working after repeatedly fixing dependencies, which has me questioning if this is the right approach.
I want to know if headless GUI automation via Wine is a standard industry pattern for this scenario, or if there is a better approach I overlooked?
Some more context:
Because of our infrastructure bias, the pipeline must run on Linux servers. To do this headlessly, I built out:
- Ubuntu Server running Xvfb to handle the graphical rendering layer
- 32-bit Wine prefix running an isolated, embedded Windows Python 3.10 instance
- Dropped down to raw Win32 API hooks
Initially, I tried using modern Python libraries like pywinauto and pandas for handling extracted data manipulation but this created more errors.
- I ran into UCRT crashes due to missing math hooks inside Wine. I had to take out pandas/numpy entirely and rewrite my script using the native Python csv module
- since Xvfb is an invisible memory display layer, traditional background macrotriggers threw COM errors because they can't grab physical system foreground focus. I had to switch to scan-code injection to bypass window focus constraints
- headless winetricks installers panic without a visual display engine, meaning I had to manually use cabextract to rip old Visual C++ components (mfc42.dll) out of Microsoft cabinet setup caches and register them by hand.
For those who've had to host legacy, closed-source Windows desktop apps on Linux infra, is wine+xvfb+win32 hardware sim the standard procedure?
Are there any better approaches? Assuming a rewrite of the source app and commercial RPA's (not enough use cases) are off the table what else can I do? ie: docker on windows server nodes?
Is there an open-source toolchain better suited for headless Windows-on-Linux UI interaction than raw Win32 API calls via Python
pdp10@reddit
This can mean different things. Which one of them are you doing? If you were calling the library, then presumably you wouldn't have as many challenges as you're facing.
The traditional answer is to let the Windows folks clean up their own messes.
No_Addendum4340@reddit (OP)
to clarify, i'm not loading or calling the application's internal business libraries or DLLs directly. since it's a closed source legacy app, i don't have the internal documentation, function headers, or entry points to hook into the backend code cleanly. i'm strictly doing window handle message hacking and virtual hardware simulation.
without going into the code, it’s essentially the lowest-level frontend UI macroing possible, rather than actual backend library linking.
NoradIV@reddit
No, what you did here is work around management who doesn't want to spend the money to do this properly.
Personally, the right choice would have been to walk away from this problem and let it be management's problem.
No_Addendum4340@reddit (OP)
honestly, i dont see any business justification to spend any money on this problem. for a one-off data-scraping script, it'd be a massive waste of resources.
i actually have both the time and interest to explore these weird low compatability problems. even if the team decides to stick with the local windows desktop automation, i've been able to learn a lot about handling these sorts of problems.
NightOfTheLivingHam@reddit
Wine isn't terrible, but honestly, I'd just run a windows VM to run the legacy app, especially when an update to wine or some obscure feature the poorly coded software calls that wine doesn't support causes a crash.
(copied from my other comment)
No_Addendum4340@reddit (OP)
Running a Windows VM is definitely a much better idea for native stability, and if this were a core business dependency, paying the licensing fee and spinning up a VM node would be a no-brainer
however, this is a lower-priority, 'nice-to-have' data scraping utility that doesn't justify a lot of budget. Prior to this, the script was running on a team member's local Windows machine, which required someone to manually kick it off and had their computer taken over for a few minutes while it executed. The goal of this R&D task was to see if we could automate it headlessly in the background to free up their workstation, without incurring new cloud licensing costs.
this was the main reason I leaned towards the wine + xvfb setup. since it's already working, i can keep the resource footprint light on our existing Linux server.
i completely agree with the long-term maintenance cost and update risks though. I'll be looking into sandboxing the working setup inside a docker container so any future host OS updates can't break the translation layer. thanks for the advice!
joshcdev@reddit
And if they claim they do not have the money for a Windows licence for the VM, it is time to do a cost analysis of replacing the system.
abitofg@reddit
The app is communicating with something else I assume ? Probably over the network ?
Use mitmproxy/wireshark to capture the traffic and create a script to execute what it does?
What you are describing sounds just as complicated, but much more fragile
No_Addendum4340@reddit (OP)
that's a clever idea and i'd love to be able to reverse engineer the app if it were talking to a web api. however, after taking a look at the app directory structure, it seems to be a legacy monolith.
The app's built on Centura/Gupta Team Developer 2.1 (from around 2001) and relies on dozens of local database drivers configured via a local sql.ini file.
but more importantly, the extraction logic isnt just dumping its data. there are a lot of .qrp files that query the backend, load the data locally to memory, and then pass it through proprietary legacy binaries to calculate and format the output.
since all this happens inside the local client memory space, idt capturing network traffic is the right move. and as an intern on a short timeline, reverse engineering a proprietary binary protocol from scratch is a bit outside my scope! the current implementation was the path of least resistance i found.
thanks for the response! definitely need to keep this in mind for any other tasks i might work on
ExceptionEX@reddit
Just fyi you run into issues trying to do this headlessly, much of winform relies on the rendered UI that often doesn't happen headlessly.
Doing this via wine may actually save you some headaches in that regard but I'm unsure what wine is going to do when it is running on a headless system.
To be honest this is such a wild edge case I can't offer anything meaningful but it does sound like an interesting issue.
I probably would solve it differently but who knows.
No_Addendum4340@reddit (OP)
I used xvfb on the ubuntu server to trick wine into thinking its plugged into a physical monitor. this forces the application to fully render everything directly inside the server's RAM. It handles the headless rendering fine which is how I was able to use win32api virtual hardware key events and win32gui lookups to refactor my script.
i agree its a weird edge case, i appreciate the input!
glassmkr_@reddit
What's the app actually doing - pulling data out, or running GUI-triggered business logic? Gupta apps usually sit on SQLBase or SQL Server. The answer changes whether Wine is the right layer at all.
No_Addendum4340@reddit (OP)
Tbh, I'm not sure what the app's doing under the hood at the db layer, essentially it's a vendor legacy black box for me.
The original team built a working Windows automation that clicks through the GUI menus to run these specific extraction reports, and my explicit assignment was just to see if that exact interactive workflow could be migrated over to our Linux servers to reduce our infrastructure footprint.
I'd love to be able to just bypass the gui and hit the sql server directly if we had access, but i'm assuming that this has been tried previously.
Ssakaa@reddit
Notably, is it really even worth doing this when you can extract/capture the queries and reimpliment the logic on top of them.
glassmkr_@reddit
Right, and Gupta apps usually have surprisingly few distinct queries underneath - the UI complexity hides simpler CRUD + computed fields + reporting. SQL Profiler against the DB while running the workflow once usually catalogs the whole set in an afternoon.
sakatan@reddit
Fucking NO!
The standard procedure is to make a home as close enough as possible to the apps' intended environment. Which is not to throw all the Linux'esque abbreviations at the wall and see what sticks - but to virtualize a Windows environment. Make a VM, pinch your nose and install Windows in that VM. Install whatever the application needs and make it run. Document. Wall it off in its own VLAN. Make backups.
You can use any kind of Linux Hypervisor if it makes you feel better. The business won't care one fucking bit that you kinda made it work in Linux. But they will care that this is a completely unmaintainable mess that will fuck them in the ass when you get hit by a bus and the next person will only have question marks in their eyes when they look at your rat king.
No_Addendum4340@reddit (OP)
Thanks! Yeah my first thought should've gone into running a Windows VM.
To give a bit more context on the scope: this isn't a core line-of-business app. It’s just a script to pull some daily data from the GUI because the vendor doesn't provide an API. We actually already have a stable Windows setup for it, but management asked me to see if we could migrate it over to our Linux box to reduce overhead which is what led me to this architecture.
My main question with the VM is just the trade-off: Is spinning up, licensing, patching, and monitoring an entire Windows Server VM just to run a single, lightweight data-scraping task worth the massive resource and management overhead? Or are there any better alternatives?
jimicus@reddit
Okay, I'm not sure how to put this delicately.
I have no idea what on Earth you are doing, but please, for the love of God, stop.
If your employer depends on this software to function, run it in Windows rather than fighting it in Linux and just accept it isn't your first choice of platform.
If it's so far legacy that it won't run on any modern version of Windows and your employer cannot scrape together the pennies to modernise it, run it on an old version, put it in its own little firewalled VLAN and limit access.
If none of the above is feasible, you need to have a very serious conversation with your senior management. Because what you're doing right now - making yourself the hero by persuading it to run in an environment it was never designed for - is taking an already massive technical debt and turning it into an existential threat for your employer because if you get sick, get run over by a bus or simply find better employment elsewhere they are turbofucked.
I am absolutely, 100% serious when I say that if I was your manager, I would be forcibly taking you off this project and having this conversation with the business owners on your behalf just to save you from yourself.
No_Addendum4340@reddit (OP)
Thanks for the response! I get the risk of legacy debt. To clarify the context, I'm interning and this was a specific R&D task handed down to me by my manager to see if we could migrate a data-scraping routine over to our Linux box. We already have a perfectly stable, native Windows automation for it in production right now.
This isn't a business critical service or anything, more of a QoL change.
FreakySpook@reddit
This is a side project I'd do in my spare time to see if I could get it going just for giggles because I find these sort of problems interesting, but yeah this is not a productive use of time trying to to actually do this for a prod environment that can potentially impact a businesses.
djthecaneman@reddit
I'm surprised you didn't go the Windows on a VM route from the beginning. Wine is great when it works, but I often have to keep Windows around for all the times that it doesn't. Whatever you do, you're going to need to document every step. So the fewer steps you need to document, the better.
Sure-Assignment3892@reddit
WINE is not a "standard industry" anything. Its an emulator that can be unstable as hell.
I wouldn't waste cycles on trying to get this to work in a commercial capacity. If upgrading is absolutely not an option, I'd run it on the latest supported OS possible; firewalled off from anything else.
HerissonMignion@reddit
It's not an emulator. It's a compatibility layer with windows executables and a dynamic loader to load them in memory and link them with compatible library calls. It's also a reimplementation of all standard windows libraries.
jimicus@reddit
You're splitting hairs here.
Yes: you're correct.
But the parent's point - that it can be unstable as hell - is still absolutely accurate regardless of how the underlying tech works.
Hotshot55@reddit
Is it really splitting hairs when the WINE acronym stands for 'WINE Is Not an Emulator'?
jimicus@reddit
Yes, because what we need to consider is not the underlying technology (which doesn't really matter two hoots to the wider business) but the baggage it brings with it.
And the baggage, in this case, is enormous. Even if OP can persuade it to work (which I'm happy to accept he can - for now, at least), he is taking an already substantial technical debt (business relies on an obsolete piece of software) and adding to it (which now runs on a platform it was never designed for, can't be supported by any Windows admin and won't be supported by most self-respecting Linux admins).
And Linux is a moving target at the best of times. Particularly with WINE. What's he going to do to handle breakage when the underlying stack gets updated? Lock down the OS so it never gets an update? Might as well run it on an old version of Windows and be done with in that case.
Up against these issues, the finer details of how WINE works under the hood aren't really relevant to the discussion.
gihutgishuiruv@reddit
Yes, because while WINE isn’t an emulator from a software engineering perspective, it absolutely “emulates” Windows from a systems & business perspective.
Emulation via dictionary definition of the word, if you will.
Ssakaa@reddit
It's not a hardware emulator like bochs, sure. It's an OS emulator, and a moderately incomplete one, but shims enough to do the trick sometimes.
flecom@reddit
Aren't the N and E in wine "Not Emulator"?
pdp10@reddit
The name is the least significant factor in what it is. The acronym was created during a time when "emulator" invoked the specter of game console low-level emulators. The Wine developers seemed to have wanted to distance themselves from emulation, considered to be disreputable and of dubious legality in the 1990s.
Sure-Assignment3892@reddit
Call it what you want.
It's garbage and not a corporate solution.
pdp10@reddit
Wine runs almost all Win32 games, which is certainly a harder use-case than non-driver business software. More backwards compatible than Windows, as well.
Wine isn't the blocker here; the desktop nature of the application is the blocker to turning it into a headless server-based application. We use Wine as part of our CI/CD for PE32/PE32+ executables, as it's far more convenient than messing with Windows. But we do that for non-GUI code of our own.
KimJongEeeeeew@reddit
I can just imagine the look on the face of the guy who ends up replacing you when you move on
NoshameNohonor@reddit
Who wouldn't love to inherit a business critical application running through WINE?
NightOfTheLivingHam@reddit
I have a client running on a library that uses winelib to run 16 bit legacy applications.
otvdm is what it's called.
Wine isnt terrible, but honestly, I'd just run a windows VM to run the legacy app.
AndyceeIT@reddit
TBF, finding a business critical application running on Server 2003 is not particularly comforting either.
Legacy software strikes again!
pppjurac@reddit
1x separate VLAN named "WINDOWS_APP_I_NEED"
X Windows VM with appropriate license
Open path to VLAN people that need that application
Create rdp link and small docx on how to connect and work with it
Document it in company wiki
Send it to users, finish.
Look up, it is time for lunch.
GoTo lunch.
KandevDev@reddit
fair, the succession problem is the real cost. ive seen this exact stack survive precisely as long as the engineer who built it. usually the right call is to time-box it: 'this lives until the vendor ships a real API or we find a replacement, whichever comes first', and budget the rebuild explicitly. if no end date exists, you're right, it becomes a liability.
KandevDev@reddit
wine + xvfb isnt standard but its not as crazy as the top reply suggests. for one-off automation of a legacy app the vendor wont modernize, its the lowest-effort path. the real risk is wine version drift - every ubuntu LTS bump can silently break compat. pin wine and ubuntu in docker if this runs in prod.
jimicus@reddit
I strongly disagree on the crazy front.
Can OP get it to work? Oh, quite possibly. I don’t dispute that.
Should OP get it to work? Hell, no. The immense likelihood is that nobody other than OP will ever be prepared to support it, which means when the day comes that OP can’t do that any more, his employer is in deep do do.
It is OP’s professional duty to do this properly or not at all.
SaltDeception@reddit
The r/ShittySysadmin posts write themselves…
fdeyso@reddit
It sounds like shitty management too.
AndyceeIT@reddit
As fun a rabbit hole this activity is, the industry approach for dealing with legacy software is to deal with the legacy software.
Large organisations treat legacy software as a serious risk, precisely because it violates security, support, and every other policy & standard relevant to IT.
If your hands are tied on that front, unfortunatelythere is no "good" way to achieve what you describe.
Expensive_Finger_973@reddit
This has to be the worst idea I have heard for a professional production setting in a long time.
Do not ever put that much kludge between business critical software and the native system requirments of said system.
Even if you get it to work, when it breaks, and it will, you are going to be in a world of hurt.
alpha417@reddit
I'd run a legacy windows qemu instance in prod long before i ever went this hideous route.
...and i do.
ididitlasterday@reddit
Winpodx
rejectionhotlin3@reddit
I foresee this becoming a common problem going forward. Wine / proton / other wine addons is kinda the best you're going to get for an emulation layer. The only other option is really a VM with windows. But your security posture will be yours to decide for your environment.
Ssakaa@reddit
Is reimplementing with less restrictive, os bound, tools.
wasabiiii@reddit
There is no perfect answer. There are numerous ways. Wine is a good one, if it works for your app. If not, a nested VM is another one. If you're on kubernetes, managing that nested VM on kubevirt is a neat idea. Or you might fall back to qemu.
If none of that can work you're out of luck.