Docs Install
Docker, Kubernetes and Coolify
Monitor Node.js apps running in Docker containers, Kubernetes pods or Coolify deployments: two Dockerfile lines, replicas named as one service, no root needed.
The host install assumes a machine: root, systemd, and a daemon that reads the kernel. An image on a cluster that nobody logs into has none of those. For a Node.js app inside a container, the agent goes into the image instead. It needs no root, runs no daemon, and opens no port.
In a Dockerfile
Launchpad → Install → Container gives you these lines, with your install's address and key already filled in:
ADD https://your-install/agent/bootstrap.cjs /opt/obscenter-agent/bootstrap.cjs
ADD https://your-install/agent/agent.cjs /opt/obscenter-agent/agent.cjs
ENV NODE_OPTIONS="--require /opt/obscenter-agent/bootstrap.cjs"
ENV OBSCENTER_URL="https://your-install"
ENV OBSCENTER_KEY="agt_…"
ENV OBSCENTER_SERVICE="checkout"
ENV OBSCENTER_GROUP="prod"
- Add both files to the image.
NODE_OPTIONSpoints at the bootstrap, not at the agent. The bootstrap loads the newest agent on disk, and fetches the current one for the next start. A restart is therefore enough to move to a new version. - Point it at your install with
OBSCENTER_URLandOBSCENTER_KEY. - Name the deployment.
OBSCENTER_SERVICEandOBSCENTER_GROUPmake every replica one service, instead of one new "machine" per pod.OBSCENTER_INSTANCEnames the replica and defaults to the container's hostname.
Fetch on every start
ADD fetches once, at build time. For a Dockerfile deploy where you never rebuild by hand, the Fetch on every start variant adds a small wrapper, prestart.sh, as the entrypoint. It fetches the current agent before your process starts, then hands over with exec. A failed download keeps the files already there, and never stops the container from starting. If your image already has an ENTRYPOINT, put the wrapper in front of it instead of replacing it. Set OBSCENTER_NO_UPDATE=1 to skip the fetch.
Kubernetes
On Kubernetes, nothing needs to be baked into your image. An init container writes both files onto a shared emptyDir volume, and every pod start begins with the current agent. The Kubernetes button shows the full pod spec. The parts that matter:
initContainers:
- name: obscenter-agent
image: curlimages/curl:8.10.1
command: ["sh", "-c"]
args:
- curl -fsS https://your-install/agent/bootstrap.cjs -o /agent/bootstrap.cjs || : > /agent/bootstrap.cjs;
curl -fsS https://your-install/agent/agent.cjs -o /agent/agent.cjs || true
containers:
- name: your-app
env:
- name: NODE_OPTIONS
value: "--require /agent/bootstrap.cjs"
- name: OBSCENTER_KEY
valueFrom: { secretKeyRef: { name: obscenter, key: agent } }
- name: OBSCENTER_INSTANCE
valueFrom: { fieldRef: { fieldPath: metadata.name } }
The || : > on the first line matters most. If --require points at a missing file, Node refuses to start. A failed download therefore leaves an empty file, which loads and does nothing. An outage of your install then costs measurement, never availability. Keep the key in a Secret, and take the instance name from the pod name.
What a container cannot see
From inside a container, /proc describes the machine, not the container. The node's processors, memory and disks are not the container's, and a number taken from in there would be the machine's number attributed to the wrong thing. So the container page uses the cgroup instead: memory against its limit, the CPU limit, and how much the container was throttled. Other processes, the disks, the network interfaces and the other containers stay invisible. To see the machine itself, install the host agent on it. The console cannot open a shell inside a container.
The Containers page
Backend → Containers lists the groups that report from inside containers. It shows the replicas answering in the last ten minutes, the services in each group, their traffic, and who installed them. A group card shows the agent version, when it was first seen, and the machine it runs on when that machine is also monitored. Memory is coloured as a share of its limit, and throttling is flagged from 1%. An amber agent version means the image runs an older agent than your install serves. One more restart catches it up. The services themselves appear under Services and traces, like any other.
Coolify
Install → Coolify covers one common setup end to end: a Dockerfile deploy on Coolify behind Traefik.
- Paste the lines it gives you into the Dockerfile, above your
CMD. They addprestart.sh, the bootstrap and the agent, and set the wrapper as the entrypoint. - Put the environment in Coolify's Environment Variables, not in the Dockerfile:
OBSCENTER_URL,OBSCENTER_KEY,OBSCENTER_SERVICE,OBSCENTER_GROUPandNODE_OPTIONS. The key is a credential, and the names belong to the deployment, not to the image. - Redeploy. Every start fetches the current agent, so there is nothing to rebuild later.
Traefik needs no changes. The client address survives the chain through Cloudflare and Traefik, and the agent reads it. A failed download never stops a deploy. The browser side is separate: the agent injects the tag into the pages the service serves, so there is nothing to paste into your HTML. In Coolify, changed variables apply on the next deploy, not on a restart of the running container.
Did it work
- Backend → Containers: the deployment appears under its group, with a green agent version.
- Backend → Services: the service appears with its routes and timings within a minute of the first request.
- Nothing at all usually means the environment did not reach the process. The container's own log says whether the agent loaded and whether it reached your install.