Repository navigation
feat(servers): panel host stack status and safe updates - #51
Merged
Merged
Conversation
buildComponentUpdateSteps returns the pre-download gate and the steps of the selected components. wrapComponentUpdateSteps adds the shell header and the done marker. buildComponentUpdateScript composes the two with the same output, so the SSH update path is unchanged, and the panel host update can run the Traefik steps as they are. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
buildHostStackRows turns the versions read on the panel host into one row per component: panel, docker, traefik, postgres and redis. Each row reports its installed and target version, whether it is outdated, and how it can be updated: from the Web Server Update dialog (panel), from the panel itself (traefik, redis), or only in the maintenance window (docker, postgres). Postgres is compared by major version, and a major change is reported as needing a migration. Values that cannot be read are unknown, never outdated. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
updateHostStackComponents runs one bash script on the panel host. It replaces Traefik with the steps the SSH update path already uses, and updates the Redis service to the pinned image with stop-first and rollback. Redis is pulled before anything changes. The Redis update waits until the swarm reports the update as completed and redis-cli answers PONG, within a timeout; a rollback, a pause, a refused update or a timeout fails the run. A second update is refused while one is running. readHostStackRows reads the installed versions with read-only docker commands and the panel's own update check, which has a timeout. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…s page settings.hostStack returns the rows of the panel host components. It is limited to local host access (owner or admin) and returns nothing on cloud. settings.updateHostStack is a subscription that runs the Traefik and Redis updates on the panel host and streams their logs. It refuses docker, postgres and panel with the next step, refuses while a panel update or another host update is running, and writes an audit entry. Both procedures are classified in the procedure access map; the update is dangerous, like the other host settings changes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A "Panel host (this server)" card sits above the server cards. Its Components button opens the panel host rows with the installed and target versions, the status and the action for each component. Traefik and Redis can be updated from the dialog after a confirmation, with a warning that Traefik is recreated and the admin site is unreachable for a few seconds. Docker and Postgres show the maintenance-window command, and the panel row opens the Web Server Update dialog. The card is hidden for users who cannot manage the panel host. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ostgres Docker and Postgres are always updated in the maintenance window, so their rows keep the reason and the exact installer command even when they are current. The card can then show the command at any time. Traefik and Redis rows carry neither, since the panel runs them. A Postgres row whose version cannot be read gets no command, because the image it would keep is unknown. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The rows the panel can update always show a checkbox. It is enabled only when the component is outdated, so an up-to-date component cannot be selected by accident. Manual rows show their reason and command, and unknown rows show the reason they could not be read. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The host components update replaces Traefik and restarts Redis from a script run by this panel. A panel update restarts the panel container, which would stop that script in the middle of the change. The update mutation now refuses while the host components update runs, the same way the host update refuses while a panel update runs. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ainer The installer mounts the socket read-only, but the generated container for remote servers and the panel host dropped the :ro flag. Keep the same mount in both places, so an update does not change how Traefik sees the daemon. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The panel host's Traefik publishes 443 only, but the generated container and the installer always published 80 as well. A replacement would have opened port 80 without anyone asking for it. Read the current publication before the old container stops and reuse it for the new one and for the restore; a fresh install still publishes 80. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The settings router reads the host stack constant and update guard, so the module mocks in the settings boundary tests must provide them. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ontainer did not have it A replacement container is created with the default bridge network. The live Traefik had no bridge attachment, so the update added one it did not have before. Detach bridge after the new container runs, but only when the container being replaced was not on it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
An empty array expanded under set -u fails on bash 3.2, which the macOS CI runner uses. Use the guarded form, so port 80 is passed only when it is published. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…d of refusing The operator update used to stop before any change when the installed Postgres major version differed from the pinned one. It now prints "Postgres <N> stays. A major upgrade is a separate migration; this update does not change it." and continues: - no Postgres backup, no Postgres pre-pull and no Postgres swap in that run - Redis, Traefik, the panel and the Docker Engine step run as before - when the majors match, the backup and the swap behave as before postgres_ready now checks the image the service actually runs. Checking the pinned image would never find a kept older Postgres, so the Docker Engine health check would roll the upgrade back. Tests: the refusal test now expects the skip line, no backup, no swap and the other steps in order. A new Docker Engine upgrade test covers a kept Postgres. The fake docker ps honors the ancestor filter for dokploy-postgres, so the readiness check against the pinned image fails that test. Docs: docs/server-maintenance.md is a new operator guide. The install guide describes the new Postgres behaviour. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The operator guide now says only port 443 (TCP and UDP) serves domain traffic, port 80 is never opened, and certificates renew only over 443 through the TLS challenge. The UFW note no longer lists port 80. The note about the panel's own port 3000 is unchanged. The installer code is not changed here; that change is on a separate branch. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- The Traefik step does nothing when the running container already uses the target image, so a repeated run (for example after the panel reconnects) causes no second outage. - The update lock is taken synchronously before the audit call and released on every exit path, and a panel update cannot start while a host update runs. - The Postgres row compares the full tag, so 18 against 18.6 shows as needing an update. The manual command is shown only for a different major. - The dialog looks for the done and failed markers in the accumulated log, so a marker split across two chunks is not missed. Tests cover the repeated run, the lock race and release, the row comparison, and the split marker. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds a Panel host card to the Remote Servers page. It shows the services that run on the panel's own host, compares each with its pinned target, and lets the operator update the safe ones from the panel.
Replacement details:
docker service update --update-order stop-first --update-failure-action rollback, and a wait for PONG with a timeout.Live check on the panel host
Run with the same generated scripts, from this branch, before merging:
Fixes found by the live check: the generated container published port 80 although the running one did not, dropped the read-only flag on the socket, and attached the default bridge network.
Test plan
biome checkpasses on each changed file;tsc --noEmitpasses inpackages/serverandapps/dokploy.apps/dokploysuite: 2577 pass. The 4 failures are inapplication.real.test.ts, which needs a local swarm manager.🤖 Generated with Claude Code