maintenant: infrastructure monitoring in a single Go binary
Self-hosted monitoring for Docker, Kubernetes and uptime. Single Go binary, no agent config, live alerts. Drop a container, your stack is monitored.
At a glance
- What is it?
- maintenant is a self-hosted monitor that discovers Docker containers, Kubernetes workloads, endpoints, TLS certificates, cron jobs and CVEs on its own, then alerts you through fixed rules, a built-in MCP server for AI agents and a public status page. It ships as one container that idles under 30 MB of RAM, with no exporters and no PromQL.
- Who is it for?
- Adopt maintenant if you want to know whether your own infrastructure is up and what is burning, without assembling Prometheus, Grafana and a dozen exporters. Do not adopt it as a replacement for application metrics, because the README states plainly that Prometheus monitors your application and maintenant monitors your infrastructure.
- Can I use it commercially?
- Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 7 days ago.
- What is it written in?
- Mainly Go, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 20, 2026, and from our analysis. They are not legal advice.
Editorial analysis
The problem: ten components to answer one question
The README states the problem more sharply than most monitoring projects dare to. Monitoring your own infrastructure with the standard stack means running Prometheus, Grafana, Alertmanager, node-exporter, cAdvisor, blackbox-exporter, a certificate exporter, Loki, Promtail, Trivy and something for image updates. Ten-odd components, each with its own config, upgrades and dashboards, to answer one question: is my stack up, and what is burning?
maintenant answers that question with one container.
The mapping table in the README is the best single artefact for understanding the scope. Container state, health checks and restart loops come built in where you would otherwise assemble cAdvisor, node-exporter and alert rules you write yourself. CPU, memory, network and disk, per container and per host, replace cAdvisor, node-exporter and Grafana dashboards you build. HTTP and TCP endpoint checks, declared as Docker labels, replace blackbox-exporter plus a config file per target. TLS certificate expiry and chain validation replace ssl_exporter. Cron and heartbeat deadlines replace Pushgateway plus alert rules you write. Live container logs with stdout and stderr demuxed replace Dozzle, or Loki and Promtail. Image update detection with compose-aware update and rollback commands replaces Diun or Watchtower.
Two entries in that table are the ones no standard component covers. Network exposure audit, listing 0.0.0.0 binds, exposed database ports, host network and privileged containers, with nothing standard in the right-hand column. And CVE enrichment with a per-container risk score, which is marked as a Personal edition feature and replaces Trivy plus its exporter.
The alerting row is marked Pro and covers Discord, webhooks, email, Telegram, Slack and Teams with escalation, against Alertmanager in the alternative column. The public status page with incidents and subscribers, against Cachet, Uptime Kuma or a SaaS, is also in that table.
That is a substantial product surface for a single binary, and the release history suggests it is still moving quickly. The recent releases are v1.9.0 on 2026-10-15 for AI agents on alerts and updates per host, v1.8.1 on 2026-10-01 as a reliability and security release, and v1.8.0 on 2026-09-29 for Apache 2.0 and outbound heartbeats.
The licence history is worth noting too, because it changed recently. v1.8.0 is titled Apache 2.0, and the repository now carries both a LICENSE file and a COMMERCIAL-LICENSE.md, so the project has a dual licensing model with the Apache terms as the open source side. The primary language is Go, the default branch is main, and the homepage is maintenant.dev.
Getting it running, and the three deployment routes
The Docker route is a compose file and one command, and the compose file is unusually well commented about its own risks.
services:
maintenant:
image: ghcr.io/kolapsis/maintenant:latest
read_only: true
security_opt:
- no-new-privileges:true
tmpfs:
- /tmp:noexec,nosuid,size=64m
ports:
- "8080:8080"
environment:
MAINTENANT_ADDR: "0.0.0.0:8080"
MAINTENANT_DB: "/data/maintenant.db"
restart: unless-stoppedBring it up with:
docker compose up -dThen open http://localhost:8080, and the README's claim is that your containers are already there, with their health, restart loops, resources and logs, and nothing to configure.
The hardening in that file is not incidental. The root filesystem is read-only, no-new-privileges is set, and /tmp is a 64 MB tmpfs mounted noexec and nosuid. Three host paths are mounted read-only: the Docker socket, /proc, and /etc/os-release.
Two comments in the compose file explain the risks plainly. Publishing the UI and API has no authentication of their own, so the file says to put an auth reverse proxy in front, or bind 127.0.0.1:8080:8080. And mounting the Docker socket grants root-equivalent access to the host, and :ro does not restrict the Docker API, so for any exposed deployment the file recommends a read-only docker-socket-proxy instead.
Docker socket access is otherwise automatic. The entrypoint reads the mounted socket's group and grants it to the unprivileged user, on Compose and on Swarm, and a socket owned by group root needs DOCKER_GID=0.
The Kubernetes route is two commands.
kubectl create namespace maintenant
kubectl apply -f deploy/kubernetes/The in-cluster API is auto-detected, RBAC is read-only, there is namespace filtering, and Deployments, DaemonSets and StatefulSets are treated as first-class citizens.
The bare Linux route is a single script, and it is the one that surprises people because it needs no container runtime at all.
curl -fsSL https://install.maintenant.dev | sudo bashEndpoints, certificates and heartbeats work without any container runtime, and container monitoring switches on by itself the moment a runtime shows up. The binary is statically linked and the route covers systemd on amd64 and arm64. There is also a cloud-init path for hardened hosts on Hetzner Cloud, DigitalOcean, Scaleway, OVHcloud or Vultr.
Modes, environment variables and where the data lives
The .env.example file documents the runtime configuration more thoroughly than the README does, and the first decision it presents is the operating mode.
There are three. Embedded is the default, a web server and local runtime which also accepts remote agents when the edition allows it. Server is the same, but it refuses to start below the Personal edition. Agent reports to a server with no HTTP interface at all.
The rest of the file is a list of environment variables with their defaults and their reasons.
MAINTENANT_ADDR=127.0.0.1:8080
MAINTENANT_GRPC_LISTEN=127.0.0.1:8443
MAINTENANT_LOG_LEVEL=info
MAINTENANT_DB=./maintenant.dbThe listen address comment tells you to use 0.0.0.0 inside containers and 127.0.0.1 on the host. The gRPC listener is loopback by default, and the comment explains why that matters: remote agents cannot connect until you change it, and in a container you use 0.0.0.0:8443 and publish the port.
Storage is SQLite by default, with the MAINTENANT_DB path pointing at the file. An optional MAINTENANT_DATABASE_URL lets a server or embedded instance back its data set with a PostgreSQL you already operate, and the comment says the server and embedded modes only, refused in agent mode. SQLite remains the only agent storage.
Two other settings are worth knowing about. MAINTENANT_BASE_URL is the public base URL used for heartbeat ping URLs, status page email links and the MCP OAuth issuer, defaulting to the listen address. And MAINTENANT_ORGANISATION_NAME is the name displayed on the public status page.
The go.mod shows the storage layer behind that choice. Both mattn/go-sqlite3 and jackc/pgx/v5 are dependencies, along with golang-migrate for schema changes, and the Dockerfile sets SQLITE_TMPDIR to /data with an explicit comment explaining why: the hardened runtime mounts /tmp as a tiny tmpfs, which SQLITE_FULL-fails the one-time UUID conversion of large tables, so the temp files have to live on the data volume.
That is a small detail and it is exactly the kind of thing you hit on the first deployment if it is not handled.
Agents, the MCP server, and what an AI agent can actually do here
The tagline under the project name describes the intended flow: when something breaks, fixed rules catch it, the alert is pushed to you, and your AI agent investigates through the built-in MCP server.
The dependency list confirms the implementation. The modelcontextprotocol/go-sdk is a direct dependency, along with google.golang.org/grpc and protobuf, and the release v1.9.0 is titled AI agents on alerts and updates per host. The gRPC listener in the environment file exists because agents are enrolled over gRPC, and MAINTENANT_GRPC_URL is the URL shown to agents in the enrollment commands.
There is an examples/agent-webhook/ directory in the tree, which is presumably a worked example of hooking an agent into an alert, and a webhook surface for agents to be called back on.
The distinction the README draws between fixed rules and agents is worth stating plainly, because it is the difference between this being a monitoring tool and this being something else. The rules are deterministic. They catch the failure, they route the alert to Discord or email or a webhook, and they escalate. The agent is the part that investigates, and it does so through the MCP server, which means it queries the same state the dashboard shows rather than scraping it.
The repository also includes a commercial layer, and the tree shows how the boundary is drawn. There is COMMERCIAL-LICENSE.md alongside LICENSE, a LICENSE_PUBLIC_KEY build argument in the Dockerfile that is passed into the binary as publicKeyB64, a DEMO_MODE build argument, and a demo-mode environment variable. The .env.example mentions a licence cache held in the data directory.
So this is a project with an open source core and a paid edition structure, where some features are marked Personal and Pro in the comparison table. The CVE enrichment and per-container risk score are marked Personal, the alert routing and escalation and the public status page are marked Pro, and the operating mode check refuses to start a server below the Personal edition.
That matters for anyone evaluating it, because the edition boundary is enforced in the binary rather than only in the documentation.
How it positions itself against Prometheus, and what that means
The README has a callout box answering a question directly, and the answer is the most useful paragraph in the document.
The question is whether you still need Prometheus. The answer is that maintenant monitors your infrastructure while Prometheus monitors your application. There is no PromQL here, no custom exporters, no panels to design: maintenant already knows what a container, a certificate, an endpoint, a cron job and a CVE are, and starts watching them the moment they appear. If you ship business metrics and write your own queries, keep Prometheus for that. The two answer different questions, and plenty of people run both.
That is a credible position and it is a narrow one. The gap between infrastructure monitoring and application monitoring is real, and a tool that covers the first in one container is genuinely useful for a homelab or a small team that would otherwise run eleven services to answer the same question.
The comparison table at the end of the README makes the same case against three specific tools. Uptime Kuma, Portainer and Dozzle are compared on container auto-discovery, MCP server and agent-readiness. The implication is that the adjacent tools each cover one axis: Uptime Kuma does uptime checks and a status page without container auto-discovery, Portainer does container management with a dashboard but is not a monitoring system, and Dozzle does log viewing. The topic tags on the repository name the substitutes directly, with grafana-alternative, prometheus-alternative and uptime-kuma-alternative.
What the tool does not claim to replace is the query language and the long-term data store. There is no PromQL, which is also to say there is no ad-hoc exploration of historical series, no recording rules and no dashboard builder. The README is straightforward that you would design your own panels in Grafana for the Prometheus path.
For an evaluation, the honest question is therefore not which tool is better but whether your monitoring needs are answered by the question is my stack up, and what is burning, or by the question how has this metric behaved over the last year.
The infrastructure monitoring also includes several things that are not monitoring in the usual sense, and they are the more distinctive part. The network exposure audit looks for 0.0.0.0 binds, exposed database ports, host networking and privileged containers. Image update detection ships compose-aware update and rollback commands. TLS checking validates chains as well as expiry. Cron and heartbeat deadlines are treated as first-class monitored things, which is the sort of thing that is easy to miss and expensive when it slips.
Where maintenant is the wrong tool
There are three limits, and the first one is the one the compose file warns about in capital letters.
The first is that the UI and API have no authentication of their own. Both the README compose block and the repository's compose.yml carry the same warning: publishing the UI and API on all interfaces is fine on a trusted or private network to get started, but before exposing it to an untrusted network you must put an authentication reverse proxy in front, or restrict the bind to 127.0.0.1:8080:8080. There is a compose.authproxy.yml in the tree for that case.
That is a real deployment constraint rather than a documentation nit, and it interacts badly with the second limitation.
The second is the Docker socket. Mounting it grants root-equivalent access to the host, and the compose file is explicit that :ro does not restrict the Docker API, because the socket is a control interface rather than a file. The recommendation for any exposed deployment is a read-only docker-socket-proxy. So the tool that tells you about privileged containers and 0.0.0.0 binds is itself, by default, running with host-root-equivalent access.
The third is the scope of the data. Everything maintenant knows about your infrastructure arrives through the Docker API, through the Kubernetes API, or through checks it makes itself. It is not a log aggregator with a retention policy, it is not a metrics store, and it is not an APM. If you need to answer questions about what happened over time, the answer is that the dashboard is for now and Prometheus and Loki are for history, and the README says as much.
The honest alternative depends on which side of that line you are on. If your question is about your own infrastructure and you run a homelab or a small fleet, the standard stack is genuinely heavy and this is a fair trade. If you run a company-scale environment with existing Prometheus and Grafana, the honest answer is that this adds a second source of truth rather than replacing the first, and two monitoring systems disagreeing is worse than one.
For the specific job of uptime checks and a public status page, Uptime Kuma is the comparison the README names and it is a lighter, more focused tool with authentication built in. For container metrics with historical retention, cAdvisor and Prometheus are the answer and no amount of auto-discovery changes that.
What maintenant offers that those do not is the combination: infrastructure auto-discovery with no exporters, fixed rules that need no PromQL, alerting that lands where you already look, a status page, and an MCP server so an agent can investigate without you writing the integration. The cost is a single binary that needs host-level access, its own authentication story, and a licence-aware feature split between the open source core and the paid editions.
Editorial conclusion
Adopt maintenant if you want to know whether your own infrastructure is up and what is burning, without assembling Prometheus, Grafana and a dozen exporters. Do not adopt it as a replacement for application metrics, because the README states plainly that Prometheus monitors your application and maintenant monitors your infrastructure. Before you deploy, put an authentication reverse proxy in front of it, since the UI and API have no authentication of their own, and note the last push was on 2026-10-16 with release v1.9.0 from 2026-10-15.
Frequently asked questions
What does maintenant monitor?
It auto-discovers Docker containers, Kubernetes workloads, HTTP and TCP endpoints, TLS certificates, cron jobs and heartbeats, and reports container health, restart loops, CPU, memory, network and disk per container and per host. It also detects image updates, audits network exposure such as 0.0.0.0 binds and privileged containers, and enriches findings with CVE data in the Personal edition.
How do I run maintenant with Docker?
Use the compose file with the ghcr.io/kolapsis/maintenant:latest image and run docker compose up -d, then open http://localhost:8080. The compose file mounts the Docker socket, /proc and /etc/os-release read-only, sets a read-only root filesystem, no-new-privileges and a 64 MB noexec tmpfs, and stores the SQLite database on a data volume.
Does maintenant replace Prometheus?
No. The README states that maintenant monitors your infrastructure while Prometheus monitors your application, with no PromQL, no custom exporters and no panels to design. If you ship business metrics and write your own queries, the README says to keep Prometheus for that, and notes that plenty of people run both.
What are the maintenant operating modes?
Embedded is the default and runs a web server and local runtime which also accepts remote agents when the edition allows it. Server is the same but refuses to start below the Personal edition. Agent reports to a server and has no HTTP interface. The MAINTENANT_MODE environment variable selects between them.
What security work does I need to do before exposing maintenant?
The UI and API have no authentication of their own, so put an authentication reverse proxy in front of them or bind to 127.0.0.1:8080:8080. Mounting the Docker socket grants root-equivalent host access and the :ro flag does not restrict the Docker API, so for any exposed deployment the docs recommend a read-only docker-socket-proxy instead.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/kolapsis-maintenant)Was this useful?