Skip to content
← All writing
September 22, 2026 · 14 min read

Five open-source tools later, I think I'm dependent — and I can't tell if that's a problem

  • open-source
  • self-hosted
  • dokploy
  • mailcow
  • postgres
  • devops
  • indie-developer
  • infrastructure

The thought that started this

A few nights ago I was looking at my VPS dashboard — containers running, everything green — and a thought showed up that I didn't enjoy.

I didn't build most of this.

Dokploy is deploying my apps. Mailcow is running my email. Postgres is holding every row of data I care about. Novu is installed and ready to handle my notifications. WAHA is the piece I'm in the middle of wiring up right now. Five pieces of open-source software, none of which I wrote, all of which my setup is increasingly built around.

Three of these are properly running. Two aren't finished yet, and I'll be specific about which as I go.

For the past few months, adopting these has been some of the most fun I've had as a developer. Every one of them taught me something I didn't know before — DNS records I'd never touched, container networking I'd only read about, notification workflows I'd previously just hardcoded and hoped for the best. I learned more in three months of wiring open-source tools together than in a long stretch of only writing application code.

But somewhere in there, "I'm learning this" quietly became "I'm running this in production." And that's a different sentence.

So here's the honest question I'm sitting with, and the reason I'm writing this post: am I building on a solid foundation, or have I just accumulated five dependencies I can't get out of?

I want to think it through properly rather than let it sit in the back of my head as vague anxiety. And I suspect I'm not the only developer who has hit this exact feeling.

How I got here, one tool at a time

None of this was planned as a stack. It accumulated.

Dokploy came first. I had a VPS and I was tired of the deploy dance — SSH in, pull, rebuild, restart, hope. Dokploy gave me a self-hosted PaaS on top of my own box: connect a repo, it builds the container, Traefik routes it, TLS certificates just happen. It's the Heroku experience without the Heroku bill, running on hardware I already pay for.

Postgres was never really a decision. It's the database. If there's one thing on this list I have never once worried about, it's this one — and I'll come back to why that matters.

Mailcow was the rabbit hole I wrote about a while back. A YouTube video made me wonder whether a regular developer could run their own mail server, and it turned into a week and a half of DNS records, SPF, DKIM, DMARC, port conflicts with my existing reverse proxy, and the very specific frustration of an email that sends successfully and then silently vanishes. I came out of it with working mail on my own domain and a much better mental model of how email actually works.

Novu arrived because I kept writing the same thing over and over. Every project needs to notify someone about something — email here, an in-app message there, maybe something else tomorrow — and I kept rebuilding that logic badly, per project. Novu is notification infrastructure: workflows, channels, templates, one place where "tell the user this happened" lives instead of five scattered send calls sprinkled through the codebase.

That's the plan, anyway. In reality I've installed it and got it set up, and then stopped there. The end-to-end flow — a real event in my own application travelling through Novu and coming out the other side as a notification a real person receives — isn't built yet. It's a running service waiting for the wiring.

WAHA is the one I'm actively working on right now. It puts an HTTP API in front of WhatsApp so you can send and receive messages programmatically from your own server. For anyone building for a market where WhatsApp is how people actually communicate — which is most of the world outside a few countries — that's a genuinely useful thing to have within reach.

I'm learning it little by little rather than trying to swallow it whole, which is the same way Mailcow eventually went from "mostly broken" to "actually running." That's deliberate: I'd rather have one thing finished properly than four things half-configured. So WAHA is the focus, and once it's genuinely done — done the way Mailcow is done — I'll go back and build the full Novu use case against the infrastructure I'll have by then.

Look at that list and there's an obvious pattern. Each tool replaced something I was either paying for, doing manually, or rebuilding from scratch every time. Each one, individually, was clearly a good decision.

Which is exactly how you end up with five of them and a slightly uneasy feeling.

What I was actually buying

It's worth being precise about the trade, because "I use open source" hides what is really happening.

In every one of these cases, I traded money and someone else's operational burden for my own time and attention.

A managed email service costs a monthly fee and someone else wakes up when it breaks. Mailcow costs me nothing per month and I wake up when it breaks. A hosted notification service handles its own scaling; a self-hosted instance is a container I'm responsible for. The dollars went down. The number of things with my name on the pager went up.

And I got a third thing, which is the part I would genuinely pay for: I now understand how these systems work. Not "I read the docs" understand — "I broke it at 1am and fixed it" understand. That knowledge doesn't disappear if I later switch tools. It's the most durable thing I got out of any of this.

So the ledger isn't bad. But it does explain the uneasy feeling: I took on real operational responsibility, and the anxiety is my brain correctly noticing that.

The reframe that actually helped

Here's where I landed, and it changed the question for me.

I never removed the dependency. I changed what I can do when it goes wrong.

When I used managed services, I was dependent too — I just didn't feel it, because the dependency was invisible. I depended on a company's pricing staying reasonable, their free tier continuing to exist, their roadmap not deprecating the thing I built on, their support queue moving when I filed a ticket. I had zero ability to fix any of it. I also had zero ability to break it, which is why it felt safe.

Self-hosting open source flips both halves. Now I can break it — which is what the anxiety is about. But I can also fix it. The code is on my disk. If a maintainer walks away tomorrow, the version I'm running keeps running. Nobody can change the pricing on software that's already on my server, and nobody can deprecate an API I control.

That's not a small difference. With SaaS, a bad day means waiting. With self-hosted open source, a bad day means reading logs — which is worse in the moment and much better over a year.

So "I feel dependent on open source" is, I think, partly a category error. The dependency was always there. What changed is that it's now visible, and visible risk feels bigger than invisible risk even when it is smaller.

That doesn't make the worry meaningless. It just means I was measuring the wrong thing.

The thing actually worth measuring: exit cost

Counting dependencies is useless. Five tools isn't inherently riskier than two — it depends entirely on what happens if each one disappears.

So I went through mine one at a time and asked a blunt question: if this project died today, what does my next week look like?

Postgres — this isn't a real scenario. Decades old, enormous community, used by a large share of the internet. If Postgres is in trouble, my problems are not about Postgres. Exit cost: effectively no risk.

Dokploy — the youngest and least battle-tested thing I run. But here's the thing: it's a convenience layer over Docker and Traefik, which is where the actual work happens. If it vanished, I'd lose a nice UI and some automation, and I'd fall back to compose files and a reverse proxy config. That's an annoying weekend, not a rewrite. Exit cost: low, precisely because it sits on standard pieces.

Mailcow — this one hurts more, because email is stateful and I'd be moving live mailboxes. But the data is standard IMAP and the protocols underneath are older than I am. I'd be migrating to a different mail server, not reinventing mail. Exit cost: genuinely painful, bounded, survivable.

Novu — right now, close to nothing, because I haven't finished wiring it in. Nothing of mine actually depends on it yet. Once the end-to-end flow exists, my notification logic lives inside it and the cost becomes moderate: I'd be rebuilding workflows, though notifications are ultimately "call this provider with this template," which is a known shape.

That gap is worth sitting with, because it's the most useful thing on this list. The cheapest moment to ask the exit-cost question is before you finish integrating, and that's exactly the moment nobody asks it. I'm there with Novu today. Which means I can still decide to keep my application code talking to a thin interface of my own instead of sprinkling vendor-specific calls everywhere — and that single decision is most of the difference between "moderate" and "painful" later.

WAHA — and here the honest answer changes.

WAHA is the one where the real risk isn't the open-source project at all. It's WhatsApp. WAHA is a wrapper around a platform I have no relationship with, no contract with, and no influence over. If WhatsApp changes how it treats unofficial clients, the quality of WAHA's code is irrelevant. That's not an open-source dependency risk — it's a platform risk wearing an open-source jacket.

That's the one I would actually think carefully about before putting anything business-critical behind it — and since it's the thing I'm building right now, that's not a hypothetical. It's the decision in front of me this week. Knowing it going in doesn't stop me building; it just means I keep the WhatsApp-shaped part of my code small and replaceable, rather than letting it spread.

Which gives me a much better answer than "am I too dependent?" The answer is: four of these five are fine, and the fifth is fine as long as I'm honest about what it really depends on.

The check I run now before adding anything

Out of all of this I've ended up with a short set of questions I ask before a new tool gets into the stack. Nothing clever, but it catches the bad ones.

What does this own that I couldn't rebuild? If it's holding unique state — my mail, my data — it's a serious commitment. If it's automating something I already know how to do by hand, it's a convenience, and convenience is cheap to replace.

Can I get my data out, in a format something else can read? If the answer is "there's an export button," I'm fine. If the answer is "it's in a proprietary schema, good luck," that's not a tool, that's a hostage situation.

Is it a layer over standards, or is it the standard? Dokploy sits on Docker. Mailcow sits on Postfix and Dovecot. When the wrapper dies you still have the thing underneath. Tools that invent their own universe are much harder to leave.

How loud does it fail? This is the one I learned the hard way with email. A system that fails obviously is safe. A system that fails silently — accepts your request, returns success, and quietly does nothing — will cost you a weekend before you even know there's a problem.

Who is actually maintaining it? Not stars. Recent commits, issues getting real responses, more than one person with commit access. A single-maintainer project can be excellent, but I should know that's what I'm choosing.

If a tool passes those, I stop worrying about the dependency count.

What I'm actually building with all this

The reason any of this matters to me is that these tools aren't hobby experiments sitting in isolation. I'm trying to assemble something specific.

I want a complete production ecosystem that one indie developer can actually run. Not a toy setup, and not an enterprise stack that needs a platform team behind it — the full path from an idea to something live and maintained, covering development, deployment, data, communication, notification and automation, built almost entirely on free and self-hostable tools, running on hardware that costs less per month than a couple of SaaS subscriptions.

Right now that is very much a work in progress, and the method is honestly just brainstorming and experimentation. I pick a gap, try the leading open-source option, break it a few times, figure out where it fits, and see what that changes about everything else. Some of it will turn out to be wrong. Mailcow taught me that DNS is unforgiving and that silent failures are the real enemy. Dokploy taught me how much friction a good deploy pipeline actually removes. Each piece shifts my understanding of the next one.

Concretely, here's where the queue stands. Deployment, data and email are done and running. WhatsApp messaging through WAHA is what I'm building at the moment, and I'm taking it slowly on purpose. After that, the full notification path through Novu — properly end to end, against whatever the infrastructure looks like once WAHA is finished, rather than as a service sitting there half-connected.

And there's a reason I keep writing this down instead of just building quietly.

When I started, the information I needed was scattered across outdated blog posts, half-finished documentation, and videos that skipped the part where things go wrong. I lost a lot of hours to that. If you're learning this — if you're trying to figure out how to run real infrastructure without a company's credit card behind you — I want these posts to be the resource I didn't have. Not a marketing page for any one tool, but a working, honest account of what fits together, what it costs, and where it hurts.

Free, powerful, self-hostable tooling is genuinely good enough now for a solo developer to run production infrastructure. That wasn't true a few years ago. I think more people should know it's true today.

So — am I overthinking it?

Mostly yes. Slightly no.

Yes, because the dependency I was worried about isn't new. I was dependent before, on companies whose decisions I couldn't see and couldn't influence. What I have now is dependency I can inspect, fix, fork and leave. That's the better version, even though it feels heavier — and it feels heavier precisely because I can finally see it.

Yes, because most of what I run sits on top of decades-old standards. The wrapper is replaceable. The foundation isn't going anywhere.

And slightly no, because the worry was pointing at something real, just not where I thought. The risk was never "too many open-source tools." It was one specific tool whose actual dependency is a platform I don't control, plus the general truth that I traded money for attention — and attention is the scarcer resource.

The version of the question I'd ask now isn't "am I too dependent on open source?" It's: for each thing I depend on, do I know what my exit looks like? Where I can answer that, the anxiety goes away. Where I can't, it's telling me something useful.

I'd genuinely like to hear how you think about this

This post is a question more than a conclusion, and I don't think I have it fully worked out.

If you've self-hosted your way into a stack and felt this — or if you went the other way, tried it, and decided the operational burden wasn't worth it — I want to hear it. Especially if you disagree with where I landed.

This blog doesn't have comments yet, which, given what I just wrote about not adding infrastructure you don't need, feels about right for now. So I'm taking the discussion to LinkedIn instead — I'm sharing a post about this, and that's where the conversation can happen. Come argue with me there.

And if you're at the start of this — trying to build a real production setup on your own, without a budget — stick around. I'm documenting the whole thing as I go, including the parts that don't work.