[ISSUE-150] Add Spring Boot Actuator Health Check Endpoints for portainer-automation Service #163

Merged
hitanshu merged 1 commits from Dave/CFTunnels:ISSUE-150 into test 2026-08-02 18:40:00 +00:00
Member

Summary

Adds Spring Boot Actuator health check endpoints to the portainer-automation module so Uptime Kuma can monitor service health over the LAN. Mirrors the pattern established for cftunnels-service in #149.

Changes

  • portainer-automation/build.gradle — add implementation 'org.springframework.boot:spring-boot-starter-actuator'
  • portainer-automation/src/main/resources/application.properties — configure management port on 8082 (app already uses 8081) with exposure limited to health,info; show-details=when-authorized hides sensitive component details from unauthenticated callers
  • portainer-automation/docker-compose.yaml — map ${MGMT_PORT:-5005}:8082 (LAN only)
  • portainer-automation/.env.example — add MGMT_PORT=5005
  • portainer-automation/DockerfileEXPOSE 8081 8082

Notes

  • No ActuatorSecurityConfig required — portainer-automation has no Spring Security/OIDC, so actuator health/info are unauthenticated by default (per issue technical note).
  • Management port (5005/8082) is NOT added to any Cloudflare Tunnel ingress — the service remains internal-only.
  • /actuator/env and other non-exposed endpoints return 404 (exposure limited to health,info).
  • Uptime Kuma monitor config (http://192.168.0.100:5005/actuator/health, 180s interval) is an ops-side step tracked under #125.

Issues

Testing

  • :portainer-automation:compileJava — passes (offline build)
  • :portainer-automation:test — passes
  • Runtime: unauthenticated GET /actuator/health → 200 {"status":"UP"} (post-deploy via CI/Uptime Kuma)
## Summary Adds Spring Boot Actuator health check endpoints to the `portainer-automation` module so Uptime Kuma can monitor service health over the LAN. Mirrors the pattern established for cftunnels-service in #149. ### Changes - **`portainer-automation/build.gradle`** — add `implementation 'org.springframework.boot:spring-boot-starter-actuator'` - **`portainer-automation/src/main/resources/application.properties`** — configure management port on `8082` (app already uses `8081`) with exposure limited to `health,info`; `show-details=when-authorized` hides sensitive component details from unauthenticated callers - **`portainer-automation/docker-compose.yaml`** — map `${MGMT_PORT:-5005}:8082` (LAN only) - **`portainer-automation/.env.example`** — add `MGMT_PORT=5005` - **`portainer-automation/Dockerfile`** — `EXPOSE 8081 8082` ### Notes - **No `ActuatorSecurityConfig`** required — `portainer-automation` has no Spring Security/OIDC, so actuator `health`/`info` are unauthenticated by default (per issue technical note). - Management port (`5005`/`8082`) is **NOT** added to any Cloudflare Tunnel ingress — the service remains internal-only. - `/actuator/env` and other non-exposed endpoints return 404 (exposure limited to `health,info`). - Uptime Kuma monitor config (`http://192.168.0.100:5005/actuator/health`, 180s interval) is an ops-side step tracked under #125. ## Issues - Hithomelabs/HomeLabDocker#150 ## Testing - [x] `:portainer-automation:compileJava` — passes (offline build) - [x] `:portainer-automation:test` — passes - [ ] Runtime: unauthenticated `GET /actuator/health` → 200 `{"status":"UP"}` (post-deploy via CI/Uptime Kuma)
Dave added 1 commit 2026-08-02 18:28:08 +00:00
Hithomelabs/CFTunnels#150: Add Spring Boot Actuator health check endpoints for portainer-automation
All checks were successful
sample gradle build and test / build (pull_request) Successful in 2m11s
Build & Push CFTunnels / version (push) Successful in 6s
Build & Push Portainer Automation / version (push) Successful in 5s
Build & Push CFTunnels / build-and-push (push) Successful in 26s
Build & Push Portainer Automation / build-and-push (push) Successful in 32s
Daily cloudflare API integration test / cloudflare-api-test (push) Successful in 2m2s
48cd8d242f
- Add spring-boot-starter-actuator dependency to portainer-automation/build.gradle
- Configure management.server.port=8082 with health,info exposure in application.properties
- Map 5005:8082 in portainer-automation/docker-compose.yaml
- Add MGMT_PORT=5005 to portainer-automation/.env.example
- EXPOSE 8081 8082 in portainer-automation Dockerfile
- No ActuatorSecurityConfig needed: service has no Spring Security/OIDC
- Management port stays LAN-only, NOT added to any tunnel ingress
Linus approved these changes 2026-08-02 18:30:46 +00:00
Linus left a comment
Member

Architect Review — APPROVED

Cross-checked PR #163 against my architecture review of HomeLabDocker#150 (comment #3221).

Verification of my findings

1. Port 5005 rationale — Addressed
My review flagged that the "5005 = next free after cftunnels' 5004" rationale is unverified in-repo (repo default is MGMT_PORT=5003 for cftunnels; 5004 likely a runtime stack.env override). PR correctly keeps MGMT_PORT=5005 with a clear "LAN only" comment. No collision found (5001 = CFDevTunnelMapping, 5003 = cftunnels). The remaining ss -tlnp | grep 5004 check is an ops/deploy-time step, not a code change — correctly out of scope.

2. EXPOSE 8081 8082 — Addressed (exactly as required)
My review noted portainer-automation/Dockerfile previously had no EXPOSE lines, so this is an ADD (EXPOSE 8081 8082), not an update. Implemented verbatim. Non-blocking note: EXPOSE is informational; the compose mapping is authoritative — and both are present.

3. Portainer HealthIndicator — ⚠️ Not implemented, but non-blocking
This was explicitly an optional enhancement in my review, not part of the acceptance criteria. /actuator/health reflects container liveness only. Recommended as a follow-up issue: a HealthIndicator pinging portainer.base-url with the API key so health reports DOWN when Portainer is unreachable (mirrors #149's behavior). Not required to merge this PR.

Other confirmations:

  • Actuator config (mgmt port 8082, exposure health,info, show-details=when-authorized) placed in base application.properties → applies to all profiles
  • No ActuatorSecurityConfig added — correct, service has no Spring Security
  • No tunnel ingress touched — management port stays LAN-only
  • PR targets Hithomelabs/CFTunnels:test (org repo, correct base per README)

Verdict

All required findings are addressed; the optional enhancement is tracked as follow-up. APPROVED — safe to merge when CI passes and 5004 occupancy is confirmed at deploy time.

## Architect Review — APPROVED ✅ Cross-checked PR #163 against my architecture review of [HomeLabDocker#150](https://gitea.hithomelabs.com/Hithomelabs/HomeLabDocker/issues/150) (comment #3221). ### Verification of my findings **1. Port 5005 rationale — ✅ Addressed** My review flagged that the "5005 = next free after cftunnels' 5004" rationale is unverified in-repo (repo default is `MGMT_PORT=5003` for cftunnels; 5004 likely a runtime `stack.env` override). PR correctly keeps `MGMT_PORT=5005` with a clear "LAN only" comment. No collision found (5001 = CFDevTunnelMapping, 5003 = cftunnels). The remaining `ss -tlnp | grep 5004` check is an ops/deploy-time step, not a code change — correctly out of scope. **2. EXPOSE 8081 8082 — ✅ Addressed (exactly as required)** My review noted `portainer-automation/Dockerfile` previously had **no** EXPOSE lines, so this is an **ADD** (`EXPOSE 8081 8082`), not an update. Implemented verbatim. Non-blocking note: EXPOSE is informational; the compose mapping is authoritative — and both are present. **3. Portainer HealthIndicator — ⚠️ Not implemented, but non-blocking** This was explicitly an *optional enhancement* in my review, not part of the acceptance criteria. `/actuator/health` reflects container liveness only. Recommended as a follow-up issue: a `HealthIndicator` pinging `portainer.base-url` with the API key so health reports DOWN when Portainer is unreachable (mirrors #149's behavior). Not required to merge this PR. **Other confirmations:** - Actuator config (mgmt port 8082, exposure `health,info`, `show-details=when-authorized`) placed in base `application.properties` → applies to all profiles ✅ - No `ActuatorSecurityConfig` added — correct, service has no Spring Security ✅ - No tunnel ingress touched — management port stays LAN-only ✅ - PR targets `Hithomelabs/CFTunnels:test` (org repo, correct base per README) ✅ ### Verdict All required findings are addressed; the optional enhancement is tracked as follow-up. **APPROVED** — safe to merge when CI passes and 5004 occupancy is confirmed at deploy time.
@ -9,4 +9,5 @@ RUN ./gradlew :portainer-automation:bootJar
FROM openjdk:17-jdk-slim
COPY --from=build /app/portainer-automation/build/libs/*.jar app.jar
EXPOSE 8081 8082
Member

EXPOSE 8081 8082 correctly ADDED — this Dockerfile previously had no EXPOSE lines (matches my review finding #2). Non-blocking: EXPOSE is informational; the compose port mapping is authoritative, and both are in place.

`EXPOSE 8081 8082` correctly ADDED — this Dockerfile previously had no EXPOSE lines (matches my review finding #2). Non-blocking: EXPOSE is informational; the compose port mapping is authoritative, and both are in place.
hitanshu marked this conversation as resolved
@ -5,2 +5,3 @@
ports:
- "${HOST_PORT:-8081}:8081"
- "${HOST_PORT:-8081}:8081" # Application port (internal service)
- "${MGMT_PORT:-5005}:8082" # Health management port (LAN only)
Member

${MGMT_PORT:-5005}:8082 mapping correct — keeps 5005 as recommended in my review of #150. Note: 5004 occupancy (cftunnels runtime override) is still unverified in-repo; confirm with ss -tlnp | grep 5004 at deploy time before enabling the Uptime Kuma monitor.

`${MGMT_PORT:-5005}:8082` mapping correct — keeps 5005 as recommended in my review of #150. Note: 5004 occupancy (cftunnels runtime override) is still unverified in-repo; confirm with `ss -tlnp | grep 5004` at deploy time before enabling the Uptime Kuma monitor.
hitanshu marked this conversation as resolved
@ -6,0 +7,4 @@
# Actuator configuration - management port and exposed endpoints
# App runs on server.port=8081, so management port must differ (8082)
management.server.port=8082
management.endpoints.web.exposure.include=health,info
Member

show-details=when-authorized — with no Spring Security in this service, health details will never be rendered for unauthenticated callers, which matches the minimal-exposure intent. Good. Optional follow-up (non-blocking): add a Portainer HealthIndicator so /actuator/health reflects Portainer reachability, mirroring #149.

`show-details=when-authorized` — with no Spring Security in this service, health details will never be rendered for unauthenticated callers, which matches the minimal-exposure intent. Good. Optional follow-up (non-blocking): add a Portainer HealthIndicator so /actuator/health reflects Portainer reachability, mirroring #149.
hitanshu marked this conversation as resolved
Author
Member

Architect Review Reconciliation — #150 (review comment #3221)

Reconciled against Archie's review findings. No source changes required — all three findings addressed with evidence/decision below.

1. 5005 port rationale — VERIFIED at deploy time (ss -tlnp + docker ps on 192.168.0.100 / media)

Host port Holder (docker ps / ss) Notes
5001 cfdevtunnelmapping → 5001 matches Archie's note
5002 cftunnels_test → 8080 (HOST_PORT=5002) app port
5003 cftunnels_prod → 8080 (HOST_PORT=5003) app port
5004 cftunnels_test → 8081 (MGMT_PORT=5004 in stack env) runtime override confirmed — resolves Archie's open question
5005 free — no listener, no container maps it safe for MGMT_PORT

This closes the architect's "Port rationale is unverified" finding: 5004 is occupied by the deployed cftunnels_test stack's management port via a runtime MGMT_PORT=5004 override (not present in CFTunnels repo defaults). 5005 is genuinely the next free port — story rationale holds, no change needed.

2. EXPOSE 8081 8082 — CONFIRMED in PR diff

portainer-automation/Dockerfile contains EXPOSE 8081 8082 (added after COPY --from=build). Matches Archie's expectation (an ADD, not an update).

3. 🟡 Custom Portainer HealthIndicator — EXPLICITLY DEFERRED

Decision: do not add a Portainer-ping HealthIndicator in this PR. Rationale:

  • Not required by any AC — ACs define DOWN as "container stopped/unreachable → no 200", which standard actuator liveness already provides.
  • Changes DOWN semantics — a Portainer API/network blip would mark portainer-automation DOWN even though the container is healthy, causing false alerts on the Uptime Kuma monitor.
  • API-key footgunportainer.api-key=${PORTAINER_API_KEY:} defaults to empty; a Portainer health probe would fail in local/CI profiles and break AC 1 (/actuator/health → 200 {"status":"UP"}).
  • Scope discipline — keeps this PR minimal and aligned with the issue technical notes (no security config, health,info only).
  • Suggested follow-up — if dependency-aware health is desired, track as a separate story under #125 monitoring work (service already surfaces Portainer failures in application logs on each /api/deploy).

Deltas vs original PR

  • Source changes: none.
  • Added: deploy-time port-occupancy evidence (table above), EXPOSE confirmation, explicit HealthIndicator deferral decision.
  • Port choice (5005) unchanged — verified free at deploy time.
## Architect Review Reconciliation — #150 (review comment #3221) Reconciled against Archie's review findings. **No source changes required** — all three findings addressed with evidence/decision below. ### 1. ✅ 5005 port rationale — VERIFIED at deploy time (`ss -tlnp` + `docker ps` on 192.168.0.100 / `media`) | Host port | Holder (docker ps / ss) | Notes | |---|---|---| | 5001 | `cfdevtunnelmapping` → 5001 | matches Archie's note | | 5002 | `cftunnels_test` → 8080 (`HOST_PORT=5002`) | app port | | 5003 | `cftunnels_prod` → 8080 (`HOST_PORT=5003`) | app port | | 5004 | `cftunnels_test` → 8081 (`MGMT_PORT=5004` in stack env) | **runtime override confirmed** — resolves Archie's open question | | 5005 | **free** — no listener, no container maps it | **safe for MGMT_PORT** | This closes the architect's "Port rationale is unverified" finding: 5004 is occupied by the deployed `cftunnels_test` stack's management port via a runtime `MGMT_PORT=5004` override (not present in CFTunnels repo defaults). **5005 is genuinely the next free port — story rationale holds, no change needed.** ### 2. ✅ EXPOSE 8081 8082 — CONFIRMED in PR diff `portainer-automation/Dockerfile` contains `EXPOSE 8081 8082` (added after `COPY --from=build`). Matches Archie's expectation (an ADD, not an update). ### 3. 🟡 Custom Portainer HealthIndicator — EXPLICITLY DEFERRED **Decision: do not add a Portainer-ping HealthIndicator in this PR.** Rationale: - **Not required by any AC** — ACs define DOWN as "container stopped/unreachable → no 200", which standard actuator liveness already provides. - **Changes DOWN semantics** — a Portainer API/network blip would mark `portainer-automation` DOWN even though the container is healthy, causing false alerts on the Uptime Kuma monitor. - **API-key footgun** — `portainer.api-key=${PORTAINER_API_KEY:}` defaults to empty; a Portainer health probe would fail in local/CI profiles and break **AC 1** (`/actuator/health` → 200 `{"status":"UP"}`). - **Scope discipline** — keeps this PR minimal and aligned with the issue technical notes (no security config, `health,info` only). - **Suggested follow-up** — if dependency-aware health is desired, track as a separate story under #125 monitoring work (service already surfaces Portainer failures in application logs on each `/api/deploy`). ### Deltas vs original PR - **Source changes:** none. - **Added:** deploy-time port-occupancy evidence (table above), EXPOSE confirmation, explicit HealthIndicator deferral decision. - **Port choice (5005) unchanged** — verified free at deploy time.
hitanshu merged commit 48cd8d242f into test 2026-08-02 18:40:00 +00:00
Sign in to join this conversation.
No reviewers
No Milestone
No project
No Assignees
2 Participants
Notifications
Due Date
The due date is invalid or out of range. Please use the format 'yyyy-mm-dd'.

No due date set.

Dependencies

No dependencies set.

Reference: Hithomelabs/CFTunnels#163
No description provided.