Stage1: безопасный импорт VK, PostgreSQL и production deployment #4
8 changed files with 242 additions and 33 deletions
51
agents/codex/done/2026-10-19-auditor1-r5-review-ca28be6.md
Normal file
51
agents/codex/done/2026-10-19-auditor1-r5-review-ca28be6.md
Normal file
|
|
@ -0,0 +1,51 @@
|
||||||
|
# Auditor1 R5 runbook review
|
||||||
|
|
||||||
|
## Scope and revision
|
||||||
|
|
||||||
|
- Base SHA: `8284eb5d006943d42133eb665c99dcbc3133d6a6`
|
||||||
|
- Reviewed SHA: `ca28be6ae629d3d67936475ea5896b6f70f6e1e4`
|
||||||
|
- Review scope: immutable R5 delta, especially `deploy/randomayzer.haproxy.cfg`, `deploy/randomayzer.Caddyfile`, `docs/STAGE1_DEPLOYMENT_RUNBOOK.md`, and `agents/codex/notes/validate-r5-templates.sh`.
|
||||||
|
- Resulting code SHA: not applicable; reviewer made no production or test changes.
|
||||||
|
- Changed files: this report and its assignment only; pre-existing `AGENTS.md` modification left untouched.
|
||||||
|
|
||||||
|
## Findings
|
||||||
|
|
||||||
|
### MEDIUM — HAProxy no-restart reload procedure is not executable from this runbook
|
||||||
|
|
||||||
|
`docs/STAGE1_DEPLOYMENT_RUNBOOK.md:396-403` deliberately leaves out the HAProxy reload command, and requires the operator to independently discover and prove a safe native reload method. The rollback at `:449-453` likewise requires “both confirmed reload commands.” The task's acceptance explicitly requires reloading without restarting the shared proxy. Until the operator has separately established the process model and worked out the command, this runbook cannot perform or roll back that accepted operation; it correctly blocks rather than guessing, but does not yet supply an executable conditional path.
|
||||||
|
|
||||||
|
Reproducer/evidence: inspect the runbook at those lines; there is no HAProxy command or procedure to establish the target process and verify graceful worker handoff. `git diff --check 8284eb5d006943d42133eb665c99dcbc3133d6a6 ca28be6ae629d3d67936475ea5896b6f70f6e1e4` exited 0, but does not address this operational gap. No live VPS process model was inspected.
|
||||||
|
|
||||||
|
### LOW — Directory-tree backup copies have no explicit completion/integrity check
|
||||||
|
|
||||||
|
For directory mounts, `docs/STAGE1_DEPLOYMENT_RUNBOOK.md:289-304` copies both active trees and both host source trees, but unlike the single-file path at `:284-286`, it has no explicit check that all four copies completed or that the saved trees match their source. The later hash guidance at `:306-307` is general and does not provide a tree-backup verification command. A partial `docker cp`/`cp -a` can therefore leave an incomplete private backup before edits proceed, reducing rollback confidence.
|
||||||
|
|
||||||
|
Reproducer/evidence: follow the directory-mount backup block; after its four copy commands it only runs `chmod`. No `diff`, manifest/hash, or copy-result gate verifies the backup trees. `bash -n agents/codex/notes/validate-r5-templates.sh` exited 0; the validator is a syntax/config fixture and does not exercise VPS backup commands.
|
||||||
|
|
||||||
|
## Reviewed controls that appear correctly represented
|
||||||
|
|
||||||
|
- The runbook gates work on confirmed domain/VPS/WireGuard facts and says to stop for unknown topology (`docs/STAGE1_DEPLOYMENT_RUNBOOK.md` R5 preflight and sections 6.1-6.2).
|
||||||
|
- It requires root context for `/root` backups, avoids printing `.Config.Env`, backs up both active configs and host sources for file mounts, restricts backup permissions, compares active/source content, and preserves single-file bind-mount inode during edits (`:260-332`). The separate directory-tree integrity gap is above.
|
||||||
|
- HAProxy SNI routing is conditional on confirmed TCP TLS passthrough; the new explicit hostname rule is to follow existing explicit routes and precede catch-all. Port 80 is conditional on existing HTTP routing and must preserve the ACME challenge path unmodified and target Caddy's cleartext HTTP backend (`:352-361`).
|
||||||
|
- Caddy and HAProxy are validated inside their running containers before and after edits (`:310-323`, `:363-381`). Caddy reload is concrete and gated on its active admin endpoint; container ID/uptime checks and prior-site baseline checks are specified (`:383-415`).
|
||||||
|
- Rollback limits restoration to changed files, preserves mounted-file inode, validates both configs, and explicitly prohibits restarting/recreating the shared proxy (`:440-456`).
|
||||||
|
- The local fixture script is syntactically valid and scoped to Docker network none. It was not executed in this review, per coordinator instruction to avoid duplicating the validator run.
|
||||||
|
|
||||||
|
## Commands and results
|
||||||
|
|
||||||
|
- `git rev-parse HEAD` — `ca28be6ae629d3d67936475ea5896b6f70f6e1e4`.
|
||||||
|
- `git diff --check 8284eb5d006943d42133eb665c99dcbc3133d6a6 ca28be6ae629d3d67936475ea5896b6f70f6e1e4` — exit 0.
|
||||||
|
- `bash -n agents/codex/notes/validate-r5-templates.sh` — exit 0.
|
||||||
|
- No application tests/build, Docker template validator, Docker commands, or VPS commands were run by this reviewer. Root owns the full gates and validator.
|
||||||
|
|
||||||
|
## UNVERIFIED and blockers
|
||||||
|
|
||||||
|
- Actual VPS container arguments, mounts, active config paths, HAProxy routing order, HAProxy process model/reload mechanism, Caddy admin endpoint, and source/active inode relationship were not observable from this local review.
|
||||||
|
- Public DNS, live TLS/ACME issuance, external auth/login, WireGuard peer identity, firewall isolation, and preservation of existing public sites remain UNVERIFIED.
|
||||||
|
- Parent reported a local fixture experiment with a `haproxy -W -db` master-worker process and USR2 signal; that is not evidence of the actual VPS process model and was not used to close the finding.
|
||||||
|
- No project phase or deployment is declared closed.
|
||||||
|
|
||||||
|
## Remaining non-blocking debt
|
||||||
|
|
||||||
|
- Add a conditional HAProxy reload branch only when the active PID 1/process model and exact config set are inspected, then specify observable graceful-handoff and unchanged-container checks plus failure/rollback handling.
|
||||||
|
- Add explicit verification for all active/source directory-tree backup copies before permitting edits.
|
||||||
52
agents/codex/done/2026-10-19-auditor2-r5-review.md
Normal file
52
agents/codex/done/2026-10-19-auditor2-r5-review.md
Normal file
|
|
@ -0,0 +1,52 @@
|
||||||
|
# Result: independent R5 review
|
||||||
|
|
||||||
|
Base SHA: `8284eb5d006943d42133eb665c99dcbc3133d6a6`
|
||||||
|
Reviewed SHA: `ca28be6ae629d3d67936475ea5896b6f70f6e1e4`
|
||||||
|
Result SHA: `ca28be6ae629d3d67936475ea5896b6f70f6e1e4` (review only; no source changes)
|
||||||
|
Files changed by this reviewer: this report and the task record only; no production or test files.
|
||||||
|
|
||||||
|
## Scope and evidence
|
||||||
|
|
||||||
|
Reviewed the immutable `8284eb5..ca28be6` diff, the updated stage-one owner manifest, and the Caddy/HAProxy templates, removed nginx template, R5 runbook, and local syntax validator. I did not inspect live VPS configuration, alter containers, or run the validator/full gates. The current checkout HEAD matched the reviewed SHA during review. `AGENTS.md` had a pre-existing local modification and was left untouched.
|
||||||
|
|
||||||
|
The runbook does a careful job of distinguishing observed configuration from examples. It requires operator discovery of exact proxy image/version, process arguments, mounts and include files, port 443 mode/SNI ordering, port 80 HTTP-01 path, and source/active configuration identity before editing. It backs up both active proxy files and host source; it also gives separate full-tree backups for directory mounts. Single-file inode preservation, post-edit active/source comparison, validation before reload, a two-protocol baseline for every operator-enumerated site, and scoped rollback are documented. The HAProxy snippets are additive, preserve existing route/default order, and use separate TLS passthrough and cleartext Caddy backends. The Caddy 2.8 site disables TLS-ALPN to require HTTP-01 and does not add access logging. The obsolete nginx alternative is removed.
|
||||||
|
|
||||||
|
## Findings
|
||||||
|
|
||||||
|
### MEDIUM — R5 runbook cannot execute the HAProxy apply step without a separate procedure
|
||||||
|
|
||||||
|
`docs/STAGE1_DEPLOYMENT_RUNBOOK.md:396-403` deliberately leaves the HAProxy reload command unspecified and directs the operator to find a deployment-specific mechanism, otherwise to stop. This is a sound safety guard against guessing at a shared proxy’s process model, but it means this deliverable does not itself provide the requested executable no-restart apply path even for the owner-confirmed Docker/HAProxy 3.0 deployment. The operator must research and supply a process-specific procedure before R5 can proceed; the current text correctly calls that an operational blocker. Parent reported an isolated official HAProxy 3.0 fixture where USR2 preserved the container identity/start time/restart count while replacing worker PIDs, but this does not prove the actual VPS runs master-worker mode or that its PID1/config mechanism accepts that signal. Do not transfer that fixture result to production.
|
||||||
|
|
||||||
|
### LOW — HAProxy route is reloaded before Caddy’s new site configuration
|
||||||
|
|
||||||
|
`docs/STAGE1_DEPLOYMENT_RUNBOOK.md:405-408` instructs applying the HAProxy route first and reloading Caddy second. During that interval, new TLS traffic for the hostname can be sent to a Caddy process that has not loaded the site block yet, producing a transient certificate or routing failure. A safer sequence is to reload Caddy first and then expose the new HAProxy SNI route, with validation/hash gates retained between steps. This is a narrow new-host availability window; it does not imply harm to existing sites.
|
||||||
|
|
||||||
|
No CRITICAL or HIGH findings in the reviewed R5 delta.
|
||||||
|
|
||||||
|
## Commands actually run
|
||||||
|
|
||||||
|
- `git rev-parse HEAD` — `ca28be6ae629d3d67936475ea5896b6f70f6e1e4`.
|
||||||
|
- `git status --short` — showed the pre-existing `AGENTS.md` modification and task-record files; no source edits from this review.
|
||||||
|
- `git show --stat --oneline --no-renames 8284eb5d006943d42133eb665c99dcbc3133d6a6..ca28be6ae629d3d67936475ea5896b6f70f6e1e4` — reviewed R5 delta summary.
|
||||||
|
- `git show ca28be6...:docs/STAGE1_DEPLOYMENT_RUNBOOK.md | nl -ba | sed -n '140,470p'` — inspected runbook and cited line references.
|
||||||
|
- `git show ca28be6...:deploy/randomayzer.haproxy.cfg | nl -ba` and `git show ca28be6...:deploy/randomayzer.Caddyfile | nl -ba` — inspected proxy snippets.
|
||||||
|
- `git show ca28be6...:agents/codex/notes/validate-r5-templates.sh | nl -ba` — inspected the local syntax-validator implementation; did not execute it.
|
||||||
|
- `git diff --check 8284eb5d006943d42133eb665c99dcbc3133d6a6 ca28be6ae629d3d67936475ea5896b6f70f6e1e4` — exit 0.
|
||||||
|
- `bash -n <(git show ca28be6ae629d3d67936475ea5896b6f70f6e1e4:agents/codex/notes/validate-r5-templates.sh)` — exit 0.
|
||||||
|
|
||||||
|
Coordinator reports that target-version Caddy/HAProxy validation and Docker R5 validator passed, and app gates plus PostgreSQL integration passed at identical runtime code. These are coordinator-reported results, not commands run by this reviewer. This review did not run npm tests, lint, build, the Docker validator, or any VPS operation.
|
||||||
|
|
||||||
|
## UNVERIFIED
|
||||||
|
|
||||||
|
- Actual VPS container IDs, image patch versions, entrypoints, config/include paths, mount sources, inodes and active/source equality.
|
||||||
|
- Actual HAProxy mode, TLS inspector, SNI precedence, catch-all ordering, cleartext port 80 route, HTTP-01 reachability, and graceful reload mechanism.
|
||||||
|
- Actual Caddy admin endpoint/reload availability, certificate issuance/renewal, DNS, WireGuard peer identity, firewall policy, login/callback behavior, and all-site baseline health.
|
||||||
|
- Directory-mount include trees are backed up, but the runbook does not give a concrete recursive active/source tree comparison command after edits; it requires the operator to compare the full set. This is non-blocking documentation debt if that comparison is completed before reload.
|
||||||
|
|
||||||
|
## Remaining blockers and non-blocking debt
|
||||||
|
|
||||||
|
- The MEDIUM runbook gap blocks live R5 application until a conditional, inspection-gated HAProxy reload procedure is documented or an operator supplies and records the verified deployment-specific method.
|
||||||
|
- The LOW reload-order issue should be corrected before live use.
|
||||||
|
- Actual topology and live acceptance remain the operator’s responsibility and unverified. No phase-closed or production-ready determination is made here.
|
||||||
|
|
||||||
|
Final verdict: the R5 configuration examples and safeguards are well-scoped, but the current runbook is not yet an executable end-to-end procedure for the HAProxy apply step. No live environment facts were inferred.
|
||||||
19
agents/codex/done/2026-10-19-r5-reload-fix.md
Normal file
19
agents/codex/done/2026-10-19-r5-reload-fix.md
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
# R5 reload and activation repair
|
||||||
|
Base SHA: ca28be6ae629d3d67936475ea5896b6f70f6e1e4.
|
||||||
|
Result SHA: accompanying commit (resolved via git log -- agents/codex/done/2026-10-19-r5-reload-fix.md).
|
||||||
|
|
||||||
|
Changed files: deploy/randomayzer.haproxy.cfg; docs/STAGE1_DEPLOYMENT_RUNBOOK.md; this report and associated inbox/review artifacts.
|
||||||
|
|
||||||
|
- Conditional executable HAProxy USR2 reload requires PID1 haproxy with -W/-Ws, complete validated config and worker handoff; unchanged container ID/start/restart count checked. Unknown topology stops.
|
||||||
|
- HTTP-01-only preparation precedes Caddy Basic Auth activation; TLS SNI route follows it.
|
||||||
|
- Whole-tree backups require nonempty copies and diff equality; rollback preserves unrelated edits.
|
||||||
|
|
||||||
|
Actual verification:
|
||||||
|
- bash agents/codex/notes/validate-r5-templates.sh: exit 0, Caddy 2.8.4 and HAProxy 3.0.30 configuration valid in isolated fake fixtures.
|
||||||
|
- bash -n on all 25 runbook bash blocks: exit 0.
|
||||||
|
- Exact runbook reload function, official HAProxy 3.0 fixture: exit 0, new worker observed and container identity/start/restart count unchanged.
|
||||||
|
- Same function against non-master PID1 sleep: rejected without changing container identity/start/restart count or running state.
|
||||||
|
- Temporary fixtures removed after checks; no VPS mutation.
|
||||||
|
|
||||||
|
UNVERIFIED: actual VPS process model, config mounts/admin API, active backend names, DNS/TLS, WireGuard peer, existing-site baselines and live acceptance. These remain operator gates, not completed deployment.
|
||||||
|
Blockers: independent rereview pending at report creation. Non-blocking debt: Caddy formatting and explicit forwarded-header warnings in local validation.
|
||||||
|
|
@ -0,0 +1,7 @@
|
||||||
|
# Task
|
||||||
|
Base SHA: 8284eb5
|
||||||
|
Reviewed SHA: ca28be6ae629d3d67936475ea5896b6f70f6e1e4
|
||||||
|
Scope: Independent review of the owner-updated R5 deployment delta and runbook for the existing Caddy 2.8 plus HAProxy 3.0 Docker topology.
|
||||||
|
Do not change: Production/source/test code, templates, containers, or host configuration. No commit/push/delegation; do not rerun the coordinator's named Docker validator. Preserve pre-existing AGENTS.md modification.
|
||||||
|
Definition of Done: Concrete findings with severity/path/line/reproducer; exact SHA; commands/results; UNVERIFIED topology/evidence and blockers.
|
||||||
|
Required verification: Read-only source/runbook review and safe syntax checks only. No VPS or container access.
|
||||||
3
agents/codex/inbox/2026-10-19-auditor2-r5-review.md
Normal file
3
agents/codex/inbox/2026-10-19-auditor2-r5-review.md
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
# Auditor2 independent R5 review
|
||||||
|
|
||||||
|
Review immutable SHA `ca28be6ae629d3d67936475ea5896b6f70f6e1e4` against `8284eb5` as assigned by coordinator. Read updated owner manifest and scrutinize HAProxy/Caddy templates, removed nginx alternative, actual VPS runbook, and local reproducible validator for route preservation, backups/config-tree/inode provenance, TLS 443 vs HTTP 80 ACME routing, SNI priority, syntax/config validation, graceful reload gating, rollback, and all-site HTTP/HTTPS baselines. No production/source edits, commit/push, VPS access/restarts or container mutations. Do not assume actual topology; unknowns remain UNVERIFIED. Do not rerun full app gates or the Docker validator already run by coordinator. Write unique task/report and individual memory worklog, with exact SHA, severity/evidence, UNVERIFIED blockers, then freeze.
|
||||||
5
agents/codex/inbox/2026-10-19-r5-reload-fix.md
Normal file
5
agents/codex/inbox/2026-10-19-r5-reload-fix.md
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
# R5 independent-review repair
|
||||||
|
Base/reviewed SHA: ca28be6ae629d3d67936475ea5896b6f70f6e1e4.
|
||||||
|
Scope: executable conditional HAProxy master-worker reload with process/container evidence and rollback; fail-closed whole-tree backups; explicit HTTP-01/Caddy-auth/TLS-route staging. No actual VPS edits. Preserve existing unrelated routes and require actual runtime/mount preconditions.
|
||||||
|
Evidence already observed in isolated official HAProxy3.0 fixture: PID1 haproxy -W -db -f..., USR2 changed worker generation while container ID/start/restart count remained unchanged. Actual VPS process model remains UNVERIFIED.
|
||||||
|
DoD: syntax and fixture checks, independent rereview, explicit unknown-state stop branches.
|
||||||
|
|
@ -22,5 +22,6 @@ use_backend CADDY_TLS_BACKEND_FROM_ACTIVE_CONFIG if randomayzer_sni
|
||||||
# Caddy must receive the full, unchanged /.well-known/acme-challenge/<token>
|
# Caddy must receive the full, unchanged /.well-known/acme-challenge/<token>
|
||||||
# path on port 80; do not redirect, rewrite, or route it elsewhere in HAProxy.
|
# path on port 80; do not redirect, rewrite, or route it elsewhere in HAProxy.
|
||||||
#
|
#
|
||||||
# acl randomayzer_http_host hdr(host) -i random.ochenstarik.ru
|
# acl randomayzer_http01 path_beg /.well-known/acme-challenge/
|
||||||
# use_backend CADDY_HTTP_BACKEND_FROM_ACTIVE_CONFIG if randomayzer_http_host
|
# acl randomayzer_http_host hdr(host),field(1,:) -i random.ochenstarik.ru
|
||||||
|
# use_backend CADDY_HTTP_BACKEND_FROM_ACTIVE_CONFIG if randomayzer_http_host randomayzer_http01
|
||||||
|
|
|
||||||
|
|
@ -147,6 +147,13 @@ R5 остаётся **BLOCKED** до подтверждения владельц
|
||||||
|
|
||||||
VPS-команды ниже запускай из root shell с доступом к Docker; если SSH-сеанс не root, выполни `sudo -i`
|
VPS-команды ниже запускай из root shell с доступом к Docker; если SSH-сеанс не root, выполни `sudo -i`
|
||||||
и перейди в checkout. Это нужно для приватного backup под `/root` и управления действующими контейнерами.
|
и перейди в checkout. Это нужно для приватного backup под `/root` и управления действующими контейнерами.
|
||||||
|
В root Bash включить остановку при ошибке; до начала согласовать окно без параллельного редактирования proxy
|
||||||
|
конфигов. При изменении файлов другим оператором прекратить работу и согласовать diff, не затирать его backup.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
set -euo pipefail
|
||||||
|
```
|
||||||
|
|
||||||
Не выводи `.Config.Env`. На домашнем сервере оставайся под своим обычным пользователем, используя `sudo`
|
Не выводи `.Config.Env`. На домашнем сервере оставайся под своим обычным пользователем, используя `sudo`
|
||||||
только для firewall-команд.
|
только для firewall-команд.
|
||||||
|
|
||||||
|
|
@ -161,7 +168,7 @@ docker inspect --format 'image={{.Config.Image}} path={{.Path}} args={{json .Arg
|
||||||
docker inspect --format '{{range .Mounts}}{{printf "%s\t%s\t%s\tRW=%t\n" .Type .Source .Destination .RW}}{{end}}' krona-proxy-mux
|
docker inspect --format '{{range .Mounts}}{{printf "%s\t%s\t%s\tRW=%t\n" .Type .Source .Destination .RW}}{{end}}' krona-proxy-mux
|
||||||
docker inspect --format 'image={{.Config.Image}} path={{.Path}} args={{json .Args}} entrypoint={{json .Config.Entrypoint}} cmd={{json .Config.Cmd}}' krona-reverse-proxy
|
docker inspect --format 'image={{.Config.Image}} path={{.Path}} args={{json .Args}} entrypoint={{json .Config.Entrypoint}} cmd={{json .Config.Cmd}}' krona-reverse-proxy
|
||||||
docker inspect --format '{{range .Mounts}}{{printf "%s\t%s\t%s\tRW=%t\n" .Type .Source .Destination .RW}}{{end}}' krona-reverse-proxy
|
docker inspect --format '{{range .Mounts}}{{printf "%s\t%s\t%s\tRW=%t\n" .Type .Source .Destination .RW}}{{end}}' krona-reverse-proxy
|
||||||
docker exec krona-proxy-mux haproxy -vv | head -n 3
|
docker exec krona-proxy-mux haproxy -vv | sed -n '1,3p'
|
||||||
docker exec krona-reverse-proxy caddy version
|
docker exec krona-reverse-proxy caddy version
|
||||||
ss -ltn '( sport = :80 or sport = :443 )'
|
ss -ltn '( sport = :80 or sport = :443 )'
|
||||||
getent ahostsv4 random.ochenstarik.ru
|
getent ahostsv4 random.ochenstarik.ru
|
||||||
|
|
@ -177,7 +184,7 @@ HAProxy 3.0.x и Caddy 2.8.x. Точные patch-версии на VPS зафи
|
||||||
файлы, которыми контейнер управляется. Не печатать/публиковать raw-конфиги или полные inspect-объекты.
|
файлы, которыми контейнер управляется. Не печатать/публиковать raw-конфиги или полные inspect-объекты.
|
||||||
Для HAProxy подтвердить, что порт 443 — `mode tcp` TLS passthrough и где уже выполняются SNI inspection,
|
Для HAProxy подтвердить, что порт 443 — `mode tcp` TLS passthrough и где уже выполняются SNI inspection,
|
||||||
`use_backend` и catch-all. Для HTTP-01 установить фактическую цепочку порта 80 до Caddy. Если HAProxy
|
`use_backend` и catch-all. Для HTTP-01 установить фактическую цепочку порта 80 до Caddy. Если HAProxy
|
||||||
терминирует TLS, существующий SNI-маршрут не ведёт к Caddy, для Caddy не существует достижимого HTTP-01,
|
терминирует TLS, существующий SNI-маршрут не ведёт к Caddy, не определён безопасный путь HTTP-01 до Caddy,
|
||||||
или для редактирования/reload не найден штатный механизм — **остановиться**. Не угадывать backend, адрес
|
или для редактирования/reload не найден штатный механизм — **остановиться**. Не угадывать backend, адрес
|
||||||
Docker-сети, config path или команду reload.
|
Docker-сети, config path или команду reload.
|
||||||
|
|
||||||
|
|
@ -234,6 +241,11 @@ curl --connect-timeout 5 --max-time 15 --fail --silent --show-error http://10.77
|
||||||
|
|
||||||
Ожидается JSON `authenticated: false`, `user: null`; это проверяет путь до приложения, не внешний TLS/login.
|
Ожидается JSON `authenticated: false`, `user: null`; это проверяет путь до приложения, не внешний TLS/login.
|
||||||
|
|
||||||
|
До редактирования прочитать 6.4 и выполнить его read-only preflight; определить функцию reload в той же
|
||||||
|
root shell. Не начинать изменение, если предусловия стандартного master-worker варианта не выполнены и
|
||||||
|
не существует другого уже документированного и проверенного оператором механизма. Команда reload при
|
||||||
|
этом ещё не выполняется.
|
||||||
|
|
||||||
### 6.2. Базовый снимок и резервная копия обоих конфигов
|
### 6.2. Базовый снимок и резервная копия обоих конфигов
|
||||||
|
|
||||||
До редактирования сохранить ответы всех уже обслуживаемых сайтов по обоим публичным входам. Адреса listener
|
До редактирования сохранить ответы всех уже обслуживаемых сайтов по обоим публичным входам. Адреса listener
|
||||||
|
|
@ -279,6 +291,8 @@ docker cp "krona-proxy-mux:$HAPROXY_ACTIVE_CONFIG" "$BACKUP_DIR/haproxy-active"
|
||||||
cp -a -- "$CADDY_HOST_SOURCE" "$BACKUP_DIR/caddy-source"
|
cp -a -- "$CADDY_HOST_SOURCE" "$BACKUP_DIR/caddy-source"
|
||||||
cp -a -- "$HAPROXY_HOST_SOURCE" "$BACKUP_DIR/haproxy-source"
|
cp -a -- "$HAPROXY_HOST_SOURCE" "$BACKUP_DIR/haproxy-source"
|
||||||
chmod -R go-rwx "$BACKUP_DIR"
|
chmod -R go-rwx "$BACKUP_DIR"
|
||||||
|
cmp -s -- "$CADDY_HOST_SOURCE" "$BACKUP_DIR/caddy-source" || { echo 'STOP: Caddy source backup incomplete'; exit 1; }
|
||||||
|
cmp -s -- "$HAPROXY_HOST_SOURCE" "$BACKUP_DIR/haproxy-source" || { echo 'STOP: HAProxy source backup incomplete'; exit 1; }
|
||||||
CADDY_INODE_BEFORE=$(stat -Lc '%d:%i' "$CADDY_HOST_SOURCE")
|
CADDY_INODE_BEFORE=$(stat -Lc '%d:%i' "$CADDY_HOST_SOURCE")
|
||||||
HAPROXY_INODE_BEFORE=$(stat -Lc '%d:%i' "$HAPROXY_HOST_SOURCE")
|
HAPROXY_INODE_BEFORE=$(stat -Lc '%d:%i' "$HAPROXY_HOST_SOURCE")
|
||||||
cmp -s -- "$CADDY_HOST_SOURCE" "$BACKUP_DIR/caddy-active" || { echo 'STOP: Caddy active/source differ'; exit 1; }
|
cmp -s -- "$CADDY_HOST_SOURCE" "$BACKUP_DIR/caddy-active" || { echo 'STOP: Caddy active/source differ'; exit 1; }
|
||||||
|
|
@ -301,6 +315,14 @@ docker cp "krona-proxy-mux:$HAPROXY_CONFIG_DIR/." "$BACKUP_DIR/haproxy-tree-acti
|
||||||
cp -a -- "$CADDY_HOST_CONFIG_DIR/." "$BACKUP_DIR/caddy-tree-source/"
|
cp -a -- "$CADDY_HOST_CONFIG_DIR/." "$BACKUP_DIR/caddy-tree-source/"
|
||||||
cp -a -- "$HAPROXY_HOST_CONFIG_DIR/." "$BACKUP_DIR/haproxy-tree-source/"
|
cp -a -- "$HAPROXY_HOST_CONFIG_DIR/." "$BACKUP_DIR/haproxy-tree-source/"
|
||||||
chmod -R go-rwx "$BACKUP_DIR"
|
chmod -R go-rwx "$BACKUP_DIR"
|
||||||
|
# Любой неполный copy/mismatch — STOP до редактирования. Не выводить содержимое/дифф конфигов.
|
||||||
|
for tree in caddy-tree-active caddy-tree-source haproxy-tree-active haproxy-tree-source; do
|
||||||
|
test -n "$(find "$BACKUP_DIR/$tree" -type f -print -quit)" || { echo 'STOP: empty config-tree backup'; exit 1; }
|
||||||
|
done
|
||||||
|
diff -qr -- "$CADDY_HOST_CONFIG_DIR" "$BACKUP_DIR/caddy-tree-source" >/dev/null || { echo 'STOP: Caddy source backup differs'; exit 1; }
|
||||||
|
diff -qr -- "$HAPROXY_HOST_CONFIG_DIR" "$BACKUP_DIR/haproxy-tree-source" >/dev/null || { echo 'STOP: HAProxy source backup differs'; exit 1; }
|
||||||
|
diff -qr -- "$BACKUP_DIR/caddy-tree-active" "$BACKUP_DIR/caddy-tree-source" >/dev/null || { echo 'STOP: Caddy active/source tree differs'; exit 1; }
|
||||||
|
diff -qr -- "$BACKUP_DIR/haproxy-tree-active" "$BACKUP_DIR/haproxy-tree-source" >/dev/null || { echo 'STOP: HAProxy active/source tree differs'; exit 1; }
|
||||||
```
|
```
|
||||||
|
|
||||||
Сверить хеши активных файлов с source до изменения. Если active path или source не доказан, остановиться. Резервная копия может
|
Сверить хеши активных файлов с source до изменения. Если active path или source не доказан, остановиться. Резервная копия может
|
||||||
|
|
@ -350,15 +372,24 @@ sudo vim -c 'set backupcopy=yes' "$HAPROXY_HOST_SOURCE"
|
||||||
1 MB; access log для этого сайта не добавлять, так как OAuth callback может нести чувствительные query values.
|
1 MB; access log для этого сайта не добавлять, так как OAuth callback может нести чувствительные query values.
|
||||||
|
|
||||||
HAProxy snippet `deploy/randomayzer.haproxy.cfg` содержит **только примеры вставок**, а не полный конфиг.
|
HAProxy snippet `deploy/randomayzer.haproxy.cfg` содержит **только примеры вставок**, а не полный конфиг.
|
||||||
Если и только если активный frontend на 443 — TCP TLS passthrough, адаптировать SNI ACL и `use_backend` к
|
Порядок активации — HTTP-01 при необходимости, затем защищённый Caddy site, затем новый TLS SNI route.
|
||||||
уже существующему Caddy TLS backend. Вставить новое точное правило после других существующих явных доменных
|
Это три отдельных этапа; не публиковать новый TLS route до успешного Caddy reload с Basic Auth.
|
||||||
маршрутов и перед catch-all; существующие rules/default backend не менять. Не добавлять второй 443 listener.
|
|
||||||
Если активный конфиг подтверждает отдельный `mode http` frontend на 80, который пока не маршрутизирует этот
|
Если текущий порт 80 уже передаёт challenge для этого Host к Caddy, оставить его без изменения. Иначе,
|
||||||
Host к Caddy, добавить host ACL к существующему Caddy cleartext HTTP backend. Этот HTTP backend должен вести
|
только для подтверждённого `mode http` frontend, сначала добавить **лишь** HTTP-01 ACL/route из snippet к
|
||||||
именно на Caddy HTTP port; не переиспользовать backend TLS passthrough/443. HAProxy должен передать Caddy
|
существующему cleartext Caddy HTTP backend: точный Host **и** path prefix `/.well-known/acme-challenge/`.
|
||||||
`/.well-known/acme-challenge/<token>` неизменённым, не basic-auth/redirect/rewrite на HAProxy и не менять
|
Не использовать TLS/443 backend, не менять другие HTTP routes, не добавлять новый listener и не добавлять
|
||||||
порт 80. Если текущий route уже передаёт этот Host к Caddy — оставить его без изменений. Не добавлять
|
пока TLS SNI ACL. Провалидировать полный HAProxy config, выполнить подтверждённый reload из 6.4 и повторить
|
||||||
Authelia forward-auth backend/rules без подтверждённого существующего policy.
|
other-site baseline. Этот этап делает доступным только challenge path; новый TLS route ещё отсутствует.
|
||||||
|
Если существующий HTTP mode/route/backend не установлен, остановиться — не угадывать топологию.
|
||||||
|
|
||||||
|
Теперь добавить Caddy block с Basic Auth, проверить source/active inode/hash и `caddy validate`, затем
|
||||||
|
выполнить только Caddy reload из 6.4. Успешный reload доказывает загрузку auth-конфига; выдача сертификата
|
||||||
|
проверяется отдельно. После успешного Caddy reload, если и только если frontend 443 — TCP TLS passthrough,
|
||||||
|
добавить точный SNI ACL/`use_backend` к существующему Caddy TLS backend после явных маршрутов других доменов
|
||||||
|
и перед catch-all. Другие rules/default backend не менять. Повторить source/active checks и полный
|
||||||
|
`haproxy -c -V`, затем graceful reload HAProxy из 6.4 и baseline всех сайтов. Не добавлять Authelia без
|
||||||
|
подтверждённого policy. Для каждого из этапов применяются checks ниже; не пропускать их при повторном reload.
|
||||||
|
|
||||||
После вносимых дополнений ещё раз проверить хеши и оба конфига:
|
После вносимых дополнений ещё раз проверить хеши и оба конфига:
|
||||||
|
|
||||||
|
|
@ -380,32 +411,70 @@ docker exec krona-proxy-mux haproxy -c -V -f "$HAPROXY_ACTIVE_CONFIG"
|
||||||
Ожидается одинаковый source/active hash для каждого файла плюс успешные Caddy/HAProxy checks. Если include
|
Ожидается одинаковый source/active hash для каждого файла плюс успешные Caddy/HAProxy checks. Если include
|
||||||
files edited, сверить и провалидировать весь config set. Не reload при любом mismatch/error.
|
files edited, сверить и провалидировать весь config set. Не reload при любом mismatch/error.
|
||||||
|
|
||||||
### 6.4. Применение без container restart
|
### 6.4. Условные команды reload без container restart
|
||||||
|
|
||||||
Caddy поддерживает штатную загрузку валидированного конфига через admin API, без restart процесса:
|
**До изменения** подтвердить, что PID1 именно `haproxy`, в его действующих argv есть отдельный `-W`/`-Ws`,
|
||||||
|
а все `-f` paths соответствуют полному config set, проверяемому в 6.3. Этот стандартный вариант проверен
|
||||||
|
локально на official `haproxy:3.0-alpine`, но не доказывает process model VPS. При wrapper/tini, другом PID1,
|
||||||
|
отсутствии flags или неизвестном config set — STOP, не посылать сигнал и не менять процессную модель.
|
||||||
|
Read-only preflight (выполняется до 6.2):
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
docker exec krona-reverse-proxy caddy reload \
|
docker exec krona-proxy-mux sh -c 'test "$(cat /proc/1/comm)" = haproxy && tr "\000" "\n" < /proc/1/cmdline | grep -Eq "^-W(s)?$"' || { echo 'STOP: unconfirmed HAProxy master-worker PID1'; exit 1; }
|
||||||
--config "$CADDY_ACTIVE_CONFIG" --adapter caddyfile
|
# Сверить каждый -f с обнаруженными active paths, не угадывать значения.
|
||||||
|
docker exec krona-proxy-mux sh -c 'tr "\000" "\n" < /proc/1/cmdline'
|
||||||
```
|
```
|
||||||
|
|
||||||
Ожидается подтверждение reload; если admin API выключен, слушает не стандартный адрес или команда отвергла
|
Для подтверждённого выше PID1=master определить функции в той же root shell. Они не запускают reload до
|
||||||
конфиг — не использовать сигнал/restart как обход. Сначала определить действующий Caddy admin endpoint и
|
явного вызова. Проверка generation не заменяет последующие probes всех сайтов и нового route.
|
||||||
согласованный reload способ; старый config остаётся baseline до успешного reload.
|
|
||||||
|
|
||||||
Для HAProxy **reload command намеренно не задан**: реальный `master-worker` mode, PID/master CLI socket,
|
```bash
|
||||||
entrypoint и compose deployment не подтверждены из локального checkout. После inspection использовать только
|
haproxy_worker_pids() {
|
||||||
штатный безостановочный reload mechanism этого контейнера/его deployment, если он подтверждён его активными
|
docker exec "$1" sh -c 'for pid in $(cat /proc/1/task/1/children); do if [ "$(cat /proc/$pid/comm 2>/dev/null)" = haproxy ]; then printf "%s " "$pid"; fi; done'
|
||||||
параметрами и документацией. Для обычной master-worker установки это может быть командой master CLI или
|
}
|
||||||
управляемым запуском нового процесса с graceful handoff, но конкретный вариант зависит от обнаруженного
|
reload_haproxy_without_restart() {
|
||||||
process model/config. Не выполнять `docker restart`, `docker compose up --force-recreate`, `kill -HUP` или
|
local container="$1" before after old_workers new_workers pid attempt handoff
|
||||||
`kill -USR2` по догадке. Если безопасный reload не доказан, остановиться после validation; это operational
|
docker exec "$container" sh -c 'test "$(cat /proc/1/comm)" = haproxy && tr "\000" "\n" < /proc/1/cmdline | grep -Eq "^-W(s)?$"' || return 1
|
||||||
blocker, а не повод перезапустить общий proxy.
|
before=$(docker inspect --format '{{.Id}} {{.State.StartedAt}} {{.RestartCount}}' "$container") || return 1
|
||||||
|
old_workers=$(haproxy_worker_pids "$container") || return 1
|
||||||
|
test -n "$old_workers" || return 1
|
||||||
|
# USR2 targets confirmed PID1 master. This is NOT docker restart/kill default signal.
|
||||||
|
docker kill --signal=USR2 "$container" >/dev/null || return 1
|
||||||
|
handoff=no
|
||||||
|
for attempt in 1 2 3 4 5 6 7 8 9 10; do
|
||||||
|
new_workers=$(haproxy_worker_pids "$container") || return 1
|
||||||
|
for pid in $new_workers; do
|
||||||
|
case " $old_workers " in *" $pid "*) ;; *) handoff=yes ;; esac
|
||||||
|
done
|
||||||
|
test "$handoff" = yes && break
|
||||||
|
sleep 1
|
||||||
|
done
|
||||||
|
after=$(docker inspect --format '{{.Id}} {{.State.StartedAt}} {{.RestartCount}}' "$container") || return 1
|
||||||
|
test "$before" = "$after" && test "$handoff" = yes || return 1
|
||||||
|
test "$(docker inspect --format '{{.State.Running}}' "$container")" = true || return 1
|
||||||
|
printf 'HAProxy worker handoff observed; container identity/start/restart count unchanged\n'
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
Перед HAProxy reload убедиться, что Caddy config уже validated и source/active hash совпадают. Использовать
|
После **каждого** полного validation/source-match gate из 6.3 активировать только соответствующий этап:
|
||||||
подтверждённый reload. Затем выполнить Caddy reload. Ни один контейнер не должен пересоздаваться/перезапускаться;
|
|
||||||
сравнить `docker ps` IDs/uptime с доизменительным снимком. Сохранить только команды и коды/нечувствительный
|
```bash
|
||||||
вывод, не сохранять конфиги или OAuth access logs.
|
# Сначала только если нужен новый HTTP-01 route; затем повторить этот вызов для финального TLS SNI route.
|
||||||
|
reload_haproxy_without_restart krona-proxy-mux || { echo 'STOP: HAProxy handoff failed; use rollback 6.6'; exit 1; }
|
||||||
|
```
|
||||||
|
|
||||||
|
Между HTTP-01 и TLS этапами загрузить Caddy Basic Auth/site (без container restart):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
CADDY_CONTAINER_BEFORE=$(docker inspect --format '{{.Id}} {{.State.StartedAt}} {{.RestartCount}}' krona-reverse-proxy)
|
||||||
|
docker exec krona-reverse-proxy caddy reload --config "$CADDY_ACTIVE_CONFIG" --adapter caddyfile || { echo 'STOP: Caddy reload failed; use rollback 6.6'; exit 1; }
|
||||||
|
test "$CADDY_CONTAINER_BEFORE" = "$(docker inspect --format '{{.Id}} {{.State.StartedAt}} {{.RestartCount}}' krona-reverse-proxy)" || { echo 'STOP: Caddy container identity changed'; exit 1; }
|
||||||
|
```
|
||||||
|
|
||||||
|
Если Caddy admin API выключен/имеет другой адрес — STOP; использовать только заранее подтверждённый admin
|
||||||
|
endpoint и штатный reload, не сигнал/restart как обход. Если worker handoff не подтверждён или service probes
|
||||||
|
изменились, не повторять USR2 бесконечно: восстановить private backup, validate и применить ту же проверенную
|
||||||
|
reload-процедуру по 6.6. При неизвестном process model оставить конфиги неизменными и передать blocker владельцу.
|
||||||
|
|
||||||
### 6.5. После reload и приёмка
|
### 6.5. После reload и приёмка
|
||||||
|
|
||||||
|
|
@ -446,7 +515,7 @@ private backup, записывая в существующий inode (`cat backu
|
||||||
mount. Не восстанавливать/перезаписывать весь proxy config tree поверх чужих параллельных изменений. Проверить
|
mount. Не восстанавливать/перезаписывать весь proxy config tree поверх чужих параллельных изменений. Проверить
|
||||||
source и active hashes, затем Caddy `validate` и HAProxy `-c` теми же путями, что выше.
|
source и active hashes, затем Caddy `validate` и HAProxy `-c` теми же путями, что выше.
|
||||||
|
|
||||||
Применить обе подтверждённые reload-команды без рестарта и проверить Caddy/HAProxy container ID/uptime,
|
Загрузить восстановленный Caddy config его reload-командой, затем вызвать `reload_haproxy_without_restart krona-proxy-mux` с теми же предусловиями; обе операции выполняются без рестарта и проверить Caddy/HAProxy container ID/uptime,
|
||||||
затем повторить исходные other-site baselines. Ожидается прежний baseline для Forgejo и каждого перечисленного
|
затем повторить исходные other-site baselines. Ожидается прежний baseline для Forgejo и каждого перечисленного
|
||||||
домена; Randomayzer снова не должен попадать на новый route. Если безопасный HAProxy reload не найден или
|
домена; Randomayzer снова не должен попадать на новый route. Если безопасный HAProxy reload не найден или
|
||||||
baseline чужого сайта не восстановился, не перезапускать общий proxy: оставить его работающим в доступном
|
baseline чужого сайта не восстановился, не перезапускать общий proxy: оставить его работающим в доступном
|
||||||
|
|
@ -465,3 +534,5 @@ volumes, sites, Authelia, Forgejo, fleet-hub и WireGuard сохраняются
|
||||||
- [Caddy automatic HTTPS](https://caddyserver.com/docs/automatic-https) — HTTP-01/redirect/certificate behavior. Доступность пути подтверждается реальной конфигурацией/сертификатом, не статическим предположением.
|
- [Caddy automatic HTTPS](https://caddyserver.com/docs/automatic-https) — HTTP-01/redirect/certificate behavior. Доступность пути подтверждается реальной конфигурацией/сертификатом, не статическим предположением.
|
||||||
- [Caddy command line](https://caddyserver.com/docs/command-line) — `validate` и `reload`; admin endpoint и успешный reload должны быть подтверждены на существующем контейнере.
|
- [Caddy command line](https://caddyserver.com/docs/command-line) — `validate` и `reload`; admin endpoint и успешный reload должны быть подтверждены на существующем контейнере.
|
||||||
- [Docker inspect](https://docs.docker.com/reference/cli/docker/container/inspect/) and [Docker cp](https://docs.docker.com/reference/cli/docker/container/cp/) — узкий вывод конфигурации контейнера, mounts и резервное копирование. Никогда не выводить `.Config.Env`.
|
- [Docker inspect](https://docs.docker.com/reference/cli/docker/container/inspect/) and [Docker cp](https://docs.docker.com/reference/cli/docker/container/cp/) — узкий вывод конфигурации контейнера, mounts и резервное копирование. Никогда не выводить `.Config.Env`.
|
||||||
|
|
||||||
|
- [HAProxy 3.0 Management Guide](https://docs.haproxy.org/3.0/management.html) — `-W`/`-Ws`, SIGUSR2 для master и exit status `-c`/`-V`. [Official Docker entrypoint](https://github.com/docker-library/haproxy/blob/master/3.0/alpine/docker-entrypoint.sh) — пример образа; действующий PID1/argv VPS всё равно проверяется отдельно.
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue