From 284ba2ea157d5348763d05ecbeae6e38db5f2efa Mon Sep 17 00:00:00 2001
From: Europium 63
Date: Wed, 28 Oct 2026 00:30:40 -0700
Subject: [PATCH] Inspector 0.9.1: guide explains VPN apps and Portainer setup;
dependency and token fixes
---
CHANGELOG.md | 27 +++
INSTALL.md | 1 +
compose.yml | 3 +
src/inspector/__init__.py | 2 +-
src/inspector/assets/guide/guide.html | 181 +++++++++++++++---
.../assets/guide/settings-portainer.png | Bin 41961 -> 42953 bytes
src/inspector/dashboard.py | 17 +-
src/inspector/main.py | 10 +-
8 files changed, 206 insertions(+), 35 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 1ad3566..80b835e 100755
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -7,6 +7,33 @@ Version numbers follow [Semantic Versioning](https://semver.org/spec/v2.0.0.html
---
+## [0.9.1] — 2026-10-28
+
+### Fixed
+
+- **A dependency on a disabled container no longer blocks recovery forever.** If
+ `depends_on` named a container that is disabled in Inspector, the dependent app was
+ never restarted. Inspector now only waits for dependencies it is watching, and the
+ container page warns when the selected dependency is disabled.
+- **`PORTAINER_API_TOKEN` now reaches the container.** The public `compose.yml` didn't
+ pass it in, so setting it as a Portainer stack variable had no effect. Existing
+ stacks need the line `- PORTAINER_API_TOKEN=${PORTAINER_API_TOKEN:-}` added under
+ `environment:` (Stacks → inspector → Editor).
+- The "depends_on … is disabled or not found" warning was logged on every check
+ (since 0.8.0). It is now logged once, and again only when the container settings
+ change.
+
+### Changed
+
+- Guide: new sections **6. Apps behind a VPN container** (why depends_on matters, how to
+ spot a VPN-routed app, setup, what Inspector does) and **7. Portainer stack redeploy**
+ (why it's needed, what a redeploy does to the whole stack, requirements, where to find
+ every value, adding the token, the other settings, Test connection errors).
+- Clearer form hints: `vpn_routed` only affects logging; `depends_on` works for any
+ dependency; where to find the endpoint ID.
+
+---
+
## [0.9.0] — 2026-10-28
### Added
diff --git a/INSTALL.md b/INSTALL.md
index 36a40a7..97ec467 100755
--- a/INSTALL.md
+++ b/INSTALL.md
@@ -56,6 +56,7 @@ TZ=America/Los_Angeles
| `INSPECTOR_PORT` | Port on your server for the dashboard. Change it if `8080` is taken. | No (default `8080`) |
| `INSPECTOR_TAG` | Version to run, e.g. `0.8.0`. See [Updating](#4-updating). | No (default `latest`) |
| `PUID` / `PGID` | User and group that own Inspector's files. Unraid users often use `99` / `100` so the files match other appdata. | No (default `1000` / `1000`) |
+| `PORTAINER_API_TOKEN` | A Portainer access token. Only needed if you use **Portainer stack redeploy** for VPN-routed apps; see the in-app guide (Help → Portainer). | No |
## 3. Deploy and sign in
diff --git a/compose.yml b/compose.yml
index 487e495..dac2070 100755
--- a/compose.yml
+++ b/compose.yml
@@ -14,6 +14,8 @@
# INSPECTOR_TAG Image version to run (default "latest"; e.g. 0.8.0 to pin).
# PUID / PGID User/group Inspector runs as (default 1000/1000).
# Unraid users often prefer 99 / 100.
+# PORTAINER_API_TOKEN Portainer access token, only if you use stack redeploy
+# (Settings -> Portainer in the dashboard).
#
# No config file to create, no docker group ID to look up: Inspector creates
# its config on first start and detects Docker socket permissions by itself.
@@ -36,3 +38,4 @@ services:
- INSPECTOR_PASSWORD=${INSPECTOR_PASSWORD:-}
- PUID=${PUID:-1000}
- PGID=${PGID:-1000}
+ - PORTAINER_API_TOKEN=${PORTAINER_API_TOKEN:-}
diff --git a/src/inspector/__init__.py b/src/inspector/__init__.py
index 3e2f46a..d69d16e 100755
--- a/src/inspector/__init__.py
+++ b/src/inspector/__init__.py
@@ -1 +1 @@
-__version__ = "0.9.0"
+__version__ = "0.9.1"
diff --git a/src/inspector/assets/guide/guide.html b/src/inspector/assets/guide/guide.html
index e46ee8e..c7e8ccd 100755
--- a/src/inspector/assets/guide/guide.html
+++ b/src/inspector/assets/guide/guide.html
@@ -78,10 +78,12 @@
3. The Status page4. Notifications5. Managing containers
- 6. Events history
- 7. Other settings
- 8. "Requires restart" fields
- 9. Troubleshooting
+ 6. Apps behind a VPN
+ 7. Portainer stack redeploy
+ 8. Events history
+ 9. Other settings
+ 10. "Requires restart" fields
+ 11. Troubleshooting
@@ -175,7 +177,7 @@ Each card shows:
under Apps). Pushover: enter your application API token and your user key.
Click Send test. You should get a message on your phone within seconds. If it fails,
the reason appears next to the button.
-
Click Save, then restart Inspector once (see section 8),
+
Click Save, then restart Inspector once (see section 10),
because turning a channel on or off is a "requires restart" field.
You'll get one alert when a container first fails, when Inspector restarts it, and when it
@@ -220,32 +222,159 @@ Inspector to act on it.
Bottom of a container's page: an app behind a VPN container with an HTTP check and stack-redeploy recovery.
-
Apps behind a VPN container
-
If an app shares a VPN container's network (network_mode: container:vpn or similar), set these on the app's page:
+
+
+
+
6. Apps behind a VPN container
+
Why these apps need special handling
+
A common setup routes download and indexer apps through a VPN container. Those apps don't get a
+network of their own: their compose file says network_mode: container:<vpn> (or
+service:<vpn>) and all their traffic goes through the VPN container. That causes
+two problems for a watchdog:
+
+
When the VPN breaks, every app behind it breaks at the same time. Restarting the apps
+ does nothing while the tunnel is down. Without help, Inspector would restart each app over and
+ over, use up their hourly restart limits, and flood you with alerts, all for a problem in a
+ different container.
+
When the VPN container is recreated (an image update, or someone redeploys its stack),
+ it gets a new container ID. The apps still point at the old one, so a normal restart fails with
+ errors like "No such container" or "joining network namespace". The only fix is
+ to recreate the apps too, which is what a Portainer stack redeploy does
+ (section 7).
+
+
How to tell if an app is behind a VPN
+
+
In Portainer open Stacks → your stack → Editor and look for
+ network_mode: container:… or network_mode: service:… on the app.
+
Or open Containers → the app: under Network it shows the VPN container instead
+ of a normal network, and it has no ports of its own (they're published on the VPN container).
+
+
Setting it up
-
Dependencies → depends_on: pick the VPN container, and turn on vpn_routed.
- Inspector checks the VPN first and waits for it to recover before touching the app.
-
Recovery → recovery_action: choose Restart, then redeploy stack if that fails
- and enter the stack name exactly as Portainer shows it. When the VPN container gets
- recreated, a plain restart of the app fails; redeploying the stack reconnects it.
+
Add the VPN container to Inspector and keep it enabled (restart on UNHEALTHY and NOT
+ RUNNING is a good start). Inspector can only wait for containers it is watching: if the VPN
+ container is disabled, its apps are recovered normally, as if there were no dependency, and the
+ container page shows a warning.
+
On each app behind it, set Dependencies → depends_on to the VPN container.
+
Turn on vpn_routed. This only changes the log: Inspector writes down when it holds off
+ on the app because the VPN is down. The waiting itself comes from depends_on.
+
Add an HTTP check (section 5) using your server's IP and the
+ port published on the VPN container, and tick UNREACHABLE. Docker often still reports
+ these apps as healthy when the tunnel is down; the HTTP check notices.
+
Under Recovery, choose Restart, then redeploy stack if that fails and enter the
+ stack name. This needs the Portainer connection from section 7.
-
Stack redeploys need the Portainer connection in Settings → Portainer:
+
What Inspector then does
+
Every check, it looks at the VPN container first. While the VPN is anything other than healthy
+(or starting, or running without a health check), the apps that depend on it are not restarted;
+Inspector fixes the VPN first. Once the VPN is healthy again, the apps are handled normally: a
+restart first, and a stack redeploy if the restart fails or doesn't help.
+
depends_on isn't only for VPNs. Use it for any "B needs A" pair, such as an
+app and its database: Inspector won't restart the app while its database is down.
+
+
+
+
7. Portainer stack redeploy
+
Why Inspector needs Portainer
+
Inspector talks to Docker directly, so it can restart or start a container. It can't
+recreate one: that needs the container's compose definition, which lives in Portainer. A
+stack redeploy asks Portainer to do exactly what its Update the stack button does. That's
+how VPN-routed apps get reattached to a recreated VPN container. You only need this if you use one
+of the two "redeploy" recovery actions.
+
A redeploy affects the whole stack. Portainer pulls the latest images
+and recreates every container in that stack, not just the failing app, so all of them blink
+off for a moment. That's why Restart, then redeploy stack if that fails is the recommended
+choice: most problems are fixed by the plain restart, and the redeploy is only used when that
+doesn't work.
+
Requirements
+
+
The app must belong to a stack that was created in Portainer. In Stacks, stacks
+ created elsewhere (for example with docker compose on the command line) are marked
+ Limited, and Portainer can't redeploy them.
+
An access token for a Portainer user who can manage that stack. An administrator's token is
+ the simplest.
+
+
+
Step 1: find the values
+
+
Setting
Where to find it
+
base_url
The address you open Portainer at, without anything after the port:
+ usually http://<server-ip>:9000 or https://<server-ip>:9443.
+ Use the server's IP, not localhost: Inspector runs in its own container.
+
endpoint_id
On Portainer's Home page, click your environment (often
+ local). The browser address then ends like #!/2/docker/dashboard: the
+ number after #!/ is the endpoint ID (here 2).
+
stack name
Stacks list, Name column, spelled exactly the same.
+ This goes on each app's container page, not on the Portainer page.
+
verify_ssl
Leave off for http:// and for Portainer's built-in
+ self-signed certificate on 9443. Turn on only if Portainer has a real certificate.
+
API token
Click your username (top right) → My account →
+ Access tokens → Add access token. Name it inspector and copy the
+ token straight away: Portainer shows it only once.
+
+
+
Step 2: give Inspector the token
+
Recommended: an environment variable. The token then never lands in
+config.yml or its backups.
-
In Portainer, open My account → Access tokens and create a token.
-
Easiest and safest: add it to the Inspector stack as an environment variable (for example
- PORTAINER_API_TOKEN) and redeploy Inspector. Or choose Saved in config.yml
- and paste it in.
-
In Settings → Portainer, add an environment with Portainer's URL and endpoint ID
- (usually 1 or 2; it's the number in the URL when you open the environment in Portainer).
- Click Test connection: it should list your stacks.
-
Turn Portainer on and save.
+
In Portainer open Stacks → inspector → Editor.
+
Check that the compose file has this line under environment: (it's in the
+ compose file from version 0.9.1 on; add it if your stack is older):
+ - PORTAINER_API_TOKEN=${PORTAINER_API_TOKEN:-}
+
Under Environment variables click Add an environment variable: name
+ PORTAINER_API_TOKEN, value the token.
+
Click Update the stack. Inspector restarts with the token available.
+
+
Alternative: save it in Inspector. In the next step choose Saved in config.yml
+and paste the token. It is masked in the dashboard, but anyone who can read Inspector's config
+folder (or a backup of it) can read the token.
+
+
Step 3: connect Inspector
+
+
Open Settings → Portainer. Under Add environment, give it a name (your own
+ label, e.g. home) and fill in base_url, endpoint_id and verify_ssl.
+
API token stored as: Environment variable with the name
+ PORTAINER_API_TOKEN, or Saved in config.yml with the token.
+
Click Test connection. It should list the stacks on that endpoint; check that your
+ app's stack is there. Then Save new environment.
+
At the top of the page turn enabled on, pick the default_environment, and
+ Save Portainer.
+
On each app's container page, set the recovery action and stack name
+ (section 6). Leave portainer_environment on Default unless
+ you connected more than one Portainer.
Settings → Portainer with one environment; the token comes from an environment variable.
+
+
The other settings on the page
+
+
Setting
What it does
+
default_environment
Which connection apps use when they don't pick one. With a
+ single environment you can leave it on Automatic.
+
stack_redeploy_cooldown_seconds
Minimum time between two redeploys of the same
+ stack (default 300). Several apps often share a stack; this stops them triggering a redeploy
+ each.
+
post_redeploy_wait_seconds
How long Inspector waits after a redeploy for the
+ stack to come up before judging it again (default 90).
+
+
+
If Test connection fails
+
+
Message
Fix
+
environment variable … is not set
The compose line from step 2 is missing, or
+ the stack wasn't updated after adding the variable.
+
the API token was rejected
Token copied wrong, deleted, or from a user without
+ access. Create a new one.
+
no stacks found on endpoint N
Wrong endpoint ID; check the number in the
+ Portainer address again.
+
request failed …
Wrong address or port, http vs https
+ mixed up, or localhost used instead of the server IP. With https and a
+ self-signed certificate, turn verify_ssl off.
+
-
6. Events history
+
8. Events history
The Events tab is a day-by-day timeline of failures, restarts, recoveries, mutes, and
maintenance. Use Prev day / Next day to look back.
@@ -253,7 +382,7 @@ maintenance. Use Prev day / Next day to look back.
-
7. Other settings
+
9. Other settings
Settings → Inspector loop.
@@ -266,14 +395,14 @@ maintenance. Use Prev day / Next day to look back.
Maintenance
A daily quiet window (e.g. 02:00–05:00) so nightly backups or updates don't trigger restarts. Turn on maintenance_window on each container that should follow it.
Notification mute
Turns the per-container Mute notifications buttons on or off, and sets how long a mute lasts.
Uptime Kuma
Connection to your Uptime Kuma status page, used by container reachability checks.
Connection to Portainer, used to redeploy stacks. See section 7.
At the bottom of every settings page is a strip showing where the config file lives and
whether Inspector can write to it.
-
8. "Requires restart" fields
+
10. "Requires restart" fields
Most changes apply on the next check. Fields marked
REQUIRES RESTART (like turning a notification channel or the
dashboard on or off) only take effect after Inspector restarts:
@@ -285,7 +414,7 @@ dashboard on or off) only take effect after Inspector restarts:
-