I started a small tech agency during a break from my university math program and took on a project to build an AI agent for a local business's WhatsApp leads. What I expected to be a few Python scripts has turned into a dockerized VPS running custom Python services, n8n, Chatwoot, Dozzle, Uptime Kuma, Caddy, backups, and additional automation.
The AI logic was relatively quick. The difficult part has been the infrastructure and operations. Every time I solve one problem, I seem to create another: logs lead to a dashboard, the dashboard leads to uptime monitoring, monitoring raises questions about whether the monitor should run on a separate VPS, and then health reports and automated snapshots get added too.
I do have a Git monorepo with client-specific branches and separate production and feature workflows, but the VPS itself is not yet managed as code. Its files are scattered across locations such as /opt and my home directory, and the Dockerfiles, Caddy configuration, and secrets have grown more complicated than I expected.
For people who manage infrastructure for clients alone, how do you decide which tools are truly necessary, keep the setup reproducible, and prevent technical debt and tool sprawl from consuming all your development time?
5 Answers
DevOps rarely feels finished because reliability work exposes more reliability work. The way to protect your sanity is to set explicit boundaries: supported services, backup and recovery targets, maintenance windows, and what is outside the client’s plan. Fewer systems to operate is usually better than adding another dashboard to monitor the existing dashboards.
This sounds less like a monitoring problem and more like solving hypothetical problems too early. For one client, a VPS, Docker Compose, basic backups, logs, and one reliable alerting mechanism may be enough. Every additional service creates another upgrade path, failure mode, and thing you may have to troubleshoot at night. Start with the smallest setup that meets the client’s actual requirements, then expand when a real need appears.
You can turn this work into a reusable service by defining tiers. A basic client might get the application, backups, and simple downtime alerts. Larger plans can add a help desk, workflow automation, advanced monitoring, and higher availability. That keeps you from building the premium architecture for every client before they actually need it.
The first priority is to make the current setup reproducible, not to add more services. Put the Docker Compose files, Dockerfiles, Caddy configuration, deployment scripts, and every non-secret VPS configuration file in Git. Keep secrets in a proper secret store or protected environment files. A useful goal is being able to rebuild the server from a fresh VPS in an hour or two.
That also makes onboarding much easier. A new person should be able to follow a documented process instead of receiving a collection of files and hoping they run.
Treat the VPS as infrastructure code. Use something like Ansible or another provisioning tool to install packages, create directories, deploy Compose files, configure services, and apply permissions. Keep a separate, cheaper development or staging VM so changes are tested before production. Docker helps keep local and production environments closer, but it does not replace version control and documented deployment steps.

The 80/20 rule helps here: solve most of the problem with a small amount of effort, and only invest further when the remaining pain is recurring or costly.