Nobody needs an RMM in a homelab. My estate is managed with Ansible, and seventeen Linux hosts do not need remote monitoring and management on top of that. I deployed NetLock RMM at the end of last year anyway, out of curiosity, and because it is privacy-focused and European it sits on the same shelf as Nextcloud and the rest of the sovereignty stack this site keeps returning to.
Because I did not need it, it never got any focus. I installed the agents, had a look at what was available, decided the platform deserved a deeper look than I had time for, and parked it. The same thing happened with GLPI on the service desk side, for the same reason: why would I raise tickets to myself? The standing plan was to wire the two together eventually, RMM feeding a service desk, automated through n8n workflows or agents.
This month that plan stopped being an idea. I am testing and building a self-hosted AI helpdesk, and RMM sits at the core of managed IT services, so I came back to NetLock with a specific question: how does the self-hosted option hold up against the big name commercial offerings?
What I thought I was looking at
The console did not make a strong first case for itself.
Seventeen devices registered and reporting. Zero events in twenty four hours. Patching disabled in every operating system block of the only real policy. No devices bound to any group despite two groups existing. No scripts, no jobs, no maintenance windows. No ticketing anywhere in the interface. No vulnerability view of any kind.
Meanwhile the project’s own website advertises ticketing, patch management, software deployment and remote access. The gap between the two was stark, and a tidy explanation wrote itself: a deployment that technically works and does nothing, an install nobody ever finished, and a product that is probably thinner than its marketing.
The standard homelab fix at this point is the one you are already thinking of. Compose down, delete the volumes, re-create, see if it comes back right. Hold that thought, because it turns out to matter more than anything else in this post.
The first crack in that story
Before reaching for the redeploy I set my diagnostic agent digging in the database, because an empty console tells you what is rendered, not what exists.
There were more than thirty tables prefixed ticket_. Tickets, comments, attachments, departments, SLA definitions, time entries, customer contacts, webhooks, templates. All present, all empty. That is not the schema of a product without ticketing. That is the schema of a full service desk that has never had a row written to it.
So I looked at the compiled console rather than the interface, and found the components too. Pages for tickets, contacts, customers, departments, statistics, time tracking. Ten routes, and a dedicated settings page whose entire job is turning the ticket system on.
The feature was not missing. It was sitting behind a single flag, and I had been reading the interface as if what I could see was what the product had.
Turning it on did not work either
There is a global setting, ticket_system_enabled, and it was zero. I set it to one. Nothing appeared.
This is the part worth being precise about, because it is the mechanism everything else in this post hangs on.
Every account in this product carries a permissions object, stored as JSON. Mine had ninety two keys in it, and not one of them mentioned tickets. Not disabled, not set to false. Absent.
The console checks a key like tickets_enabled before it renders the menu entry, and a missing key evaluates the same as a denial. My account had been created by the older version I originally deployed at the end of last year. Ticketing shipped in a later release, and nothing migrated my permissions object when it arrived. NetLock is in active development, features have shipped steadily since, and Watchtower had been quietly keeping my containers current the whole time. The product kept moving for months. My account never found out.
I added the keys the console looks for, logged out, logged back in, and there was a full service desk. Empty, but an empty queue that then fills up is telling you about defects in the estate rather than about demand, so empty is the right starting state.
Then a page started logging me out
Encouraged, I went to enable patch management, in the mode that reports available updates without installing them. That mode is worth knowing about in its own right: if your hosts already run unattended upgrades, two things patching the same box will fight over the package lock.
The patch management page began throwing me out of the session entirely.
Same cause, worse symptom. The page checks patch_management_enabled, my account did not have it, and instead of hiding a menu item this page threw an unhandled exception. In a server-rendered app that kills the connection, and killing the connection ends your session. Nothing was written to the container logs, which is why the logs had been no help all afternoon.
At that point I stopped fixing one page at a time. The agent pulled every permission-shaped key the console binary refers to and compared the list against my account. Forty four were missing: application control, custom fields, device control, software deployment, reports, file server, relay server, and a dozen settings pages including licensing, maintenance, SSO and white labelling. Any one of them potentially doing to my session what patch management had.
The agent enabled the lot. The console I had considered thin that morning now shows more working surface than I believed the product had in total.
The redeploy that would have hidden everything
Now back to that held thought.
A full remove and re-create would have fixed all of this. A fresh install creates a fresh admin account, and a fresh admin account gets the complete permission set. Ten minutes of Docker, problem gone, and I would have credited the redeploy, called the whole thing a glitch, and moved on.
That is the trap, and it is bigger than this product. The fix that works can still be the fix that hides the cause. Wipe-and-redeploy is the default reflex for exactly the class of problem whose cause deserves ten minutes of attention first, and because the reflex usually works, the cause almost never gets found.
How good projects get written off
This is the part worth generalising, and it is not really about me, and only partly about NetLock.
On the morning of the revisit, my console was showing maybe a third of the product. A console showing a third of the product is indistinguishable from a product that only does a third of what it promises. Every conclusion I nearly drew was reasonable on the evidence in front of me. The evidence was silently wrong, and nothing in the system was capable of saying so: no error, no log line, no banner saying your account predates these features.
Self-hosted projects carry a risk here that SaaS platforms never face. A cloud console cannot drift from its own feature set, because the vendor runs the only instance and every user sees the current product. A self-hosted install can sit for months while the project moves on, and the verdicts that follow, the quick look, the drive-by evaluation, the “seemed limited” comment in a forum thread, land on the project’s reputation rather than on the install’s configuration. A genuinely good project gets discounted over a missing migration, and small European open-source teams live and die on exactly those first impressions.
NetLock does still have real gaps. The absence of antivirus integration beyond Microsoft Defender management is the one I feel most, and it is a fair criticism to weigh against the commercial platforms. But the list of gaps I could have written on the morning of the revisit was mostly not a list of gaps at all, and it is a safe bet that other self-hosted projects are being judged on the same false evidence right now, including by people much less inclined to go looking in the database first.
The diagnostic
So when a self-hosted tool that has lived through upgrades looks thinner than its documentation claims, the order of checks is:
- Look at the schema, not the screen. Empty tables that exist tell you the feature shipped. If thirty tables are named after a feature you cannot find, the feature is not the problem.
- Look for the components in the build. Compiled routes and page names tell you whether the code is present in the version you are actually running, which is a different question from what the changelog says.
- Then look at your own account. Compare the permission keys the application refers to against the keys your account holds. Absent is the failure mode to hunt for, because absent produces no error and no log line.
- Only then conclude the feature is missing or paywalled. That was my first conclusion, and it was three layers too early.
There is a related trap in the same family. A tool with a working scheduler is not the same as a tool that has scheduled anything. The vulnerability view in this product had never populated, and I read that as a broken background job. It was not broken. The CVE feed pull is an action on a page, and nobody had ever pressed it. Nothing had failed, because nothing had started.
This is also the mirror image of a problem I have written about from the other direction. In a Microsoft estate the danger is the permissions you forgot you granted, accumulating quietly until something reaches data it should not. Here it was the permissions I was never granted. Both are invisible for the same reason: nobody generates an alert for an entitlement that simply sits there.
One war story worth stealing
While updating a policy stored as JSON in a column, I used MySQL’s load_file() to read the new value from a file. It returned NULL, because the path was outside secure_file_priv, and MySQL does not error when that happens. The update succeeded, wrote NULL into the column, and blanked the policy.
It was restored in a minute, because the first thing I had done was dump the existing value to a file. That habit cost ten seconds and saved the evening. Back up the column before you touch it, every time, even when the change is obviously safe, because load_file() failing silently is exactly the class of thing you do not predict.
Where this lands
I came within one reflex of discounting a genuinely good project over configuration it had no way to warn me about. The capability was there the whole time, gated behind an account that had quietly fallen behind the product, and the gate produced silence instead of errors.
If you run self-hosted infrastructure, something on your network is probably in this state right now. Silence is not evidence of absence. It is usually evidence that nobody has asked the right question yet, and asking it costs minutes. Writing a project off costs someone else a lot more.

ReadTheManual is run, written and curated by Eric Lonsdale.
Eric has over 20 years of professional experience in IT infrastructure, cloud architecture, and cybersecurity, but started with PCs long before that.
He built his first machine from parts bought off tables at the local college campus, hoping they worked. He learned on BBC Micros and Atari units in the early 90s, and has built almost every PC he’s used between 1995 and now.
From helpdesk to infrastructure architect, Eric has worked across enterprise datacentres, Azure environments, and security operations. He’s managed teams, trained engineers, and spent two decades solving the problems this site teaches you to solve.
ReadTheManual exists because Eric believes the best way to learn IT is to build things, break things, and actually read the manual. Every guide on this site runs on infrastructure he owns and maintains.
Enjoyed this guide?
New articles on Linux, homelab, cloud, and automation every 2 days. No spam, unsubscribe anytime.




