Apps — installed#
The Installed tab of Services → Apps shows one card per container declared in the configuration tree, plus one per enabled feature module. Each card is a merge of three separate facts: what the configuration declares, what podman reports, and — when the catalogue entry says how to ask — whether the app is actually answering. Those three can disagree, and the card is designed to show it when they do rather than to pick one.
Everything here comes from GET /api/apps/installed, polled every 15 s on this page.
What the agent merges#
collectInstalled() in agent/apps.go does the work:
- Read the
container namesubtree from the configuration. Every declared container becomes a card, whether or not it is running. - Read
show container— which ispodman ps --all— and index it by name. - For each declared container, extract the image, whether
disableis present, whetherallow-host-networksis present, its address on the container network, its environment and its volumes. - Match the image against the catalogue, ignoring the tag, so upgrading an app does not orphan the integrations its entry declares.
- When the entry declares a health probe and the app is running, probe it.
Two details in step 3 matter in practice:
- Environment values whose name looks like a credential are masked before they leave
the agent. Any variable whose name contains
PASS,TOKEN,KEY,SECRETorAUTHcomes back as••••••••. The operator set it; they do not need it read back, and a screenshot of this page should not carry it —maskIfSecretinagent/apps.go. - Volumes are rendered as
source → destination, joined from the two nodes VyOS keeps them in.
The four states#
| Badge | Condition | What to do |
|---|---|---|
running | The podman status line starts with Up. | Nothing. |
not answering | Running, and the health probe returned false. | The app is up but its port is silent — check its logs. |
stopped | The configuration carries disable on this container. | Deliberate; start it from the app page. |
drift | Declared, not disabled, and not running. | Something failed. |
Up is checked as a prefix rather than as presence, because show container is
podman ps --all and an exited container is listed too, with a status like
Exited (1) 3 hours ago. Treating presence in the table as "running" reported crashed
apps as healthy.
Drift — declared, enabled, not running — is the case worth naming. It usually means the image is missing, a required environment variable is unset, or the container crashed on start. The app page says the same thing in a banner and points at the Logs tab, which will name which.
Health probing#
A probe is a TCP connect to the declared port with a 2-second timeout, plus — when the
catalogue entry gives a path — one HTTP GET with a 3-second timeout that does not follow
redirects. That is all it is, deliberately: an app-specific API call would claim
knowledge of an app's internals that this product does not have —
probeApp in agent/catalog.go.
| Outcome | Reported as |
|---|---|
| Connect refused or timed out | not answering, "no answer on 10.99.0.10:3000" |
| Connected, no path declared | answering, "listening on 10.99.0.10:3000" |
| Path declared, HTTP under 500 | answering, "HTTP 200" |
| Path declared, HTTP 500 or above | not answering, "HTTP 502" |
| Path declared, connection open but HTTP silent | answering, "port open, HTTP did not answer" |
Results are cached for 10 seconds so a polling page does not open a TCP connection to every app on every render.
Two cases produce no verdict at all, only a note, and both are honesty rather than caution:
Pass ?probe=0 to skip probing entirely. The navigation sidebar does exactly that,
because it only needs the nav labels — ui/src/components/Layout.tsx.
An installed card#
| Row | Source |
|---|---|
| Image | the tail of the image reference; hover for the whole thing |
| Address | the container's address, or host network |
| Status | podman's own status string, or disabled in config, or declared, not running |
| Health | the probe note, when there is one |
When the catalogue entry declares a web interface and the container has an address, the
card grows an Open ↗ link. The URL is built from the entry's scheme (default http),
the container's real address, its port — omitted when it is 80 — and its path. Nothing
about that URL is guessed: it is assembled from the entry plus the address the router
actually gave the container.
The card title is the catalogue name; the container's own name appears as the panel meta when the two differ, which happens whenever you renamed the container at install time.
Feature modules#
Enabled feature modules appear as their own cards above the containers, with built-in
feature as the meta and one of two badges:
| Badge | Means |
|---|---|
enabled | The flag is set in the agent's state; nothing is configured on the router yet. |
configured | The feature has live configuration in the tree — the page would show even without the flag. |
Installed in the API response is flag OR config_present, and that is what the
navigation obeys. Hiding a page while its feature is configured would be lying about the
router — mergeFeatureState in agent/apps.go.
The navigation entry#
An installed app whose catalogue entry declares nav_label gets its own entry in the
left navigation, under a heading of Installed, with the entry's icon and a link to
its app page. A small amber dot appears beside it when the app is declared but not
running; running-and-healthy is the silent case.
Of the 36 container entries, 31 declare a nav label. The sidebar refreshes this list every 30 s and also immediately when a feature is installed or uninstalled, because feature installs do not pass through staging and would otherwise wait out the poll.
The empty state#
A router with nothing installed shows the three commands that constitute a minimal install, which is also the shape every plan takes:
set container network apps prefix 10.99.0.0/24
set container name adguard image docker.io/adguard/adguardhome:latest
set container name adguard network apps address 10.99.0.10See also#
- Apps — the catalogue and the install flow.
- One app — the detail page each card links to.
- Apps — images — the images those containers run from.
- Dashboard — the same states, abbreviated to seven rows.
Checked against agent/apps.go,
agent/catalog.go,
agent/catalog.json,
ui/src/pages/Apps.tsx,
ui/src/components/Layout.tsx,
ui/src/lib/api.ts.