Skip to content
prod 352bb92
Browse

7 · Shared-hosting readiness

Objective — prove the hosting account is ready for deployment before Phase 4 starts. If this server was already prepared, run the Admin-Server status check. If this is the first app on the hosting account, run the shared-hosting playbook first, then come back here and verify it.

Steps at a glance:

  1. Choose the hosting account and SSH alias — Confirm which hosting account this app will deploy to and which local SSH alias reaches it. Use the same alias you will use in Phase 4 and Phase 5.
  2. Check whether Admin-Server already exists and is alive — Run the status script and log-freshness probe if the server already has ~/Admin-Server/. Scripts on disk are not enough; dead cron jobs block Phase 4.
  3. Run the shared-hosting playbook when this account is new — If the status script is missing or clearly incomplete, stop this app playbook and run the shared-hosting playbook for the hosting account.
  4. Record the server readiness note locally — Write the result where future sessions can find it without re-discovering the hosting account.

The Set up shared hosting playbook is once per hosting account, not once per app. It installs the server-wide ~/Admin-Server/ toolkit that later deploy tasks use for deploy webhooks, ops alerts, monitoring scripts, baselines, and server notes.

This page does not duplicate that server playbook. It only decides whether the hosting account is already ready, routes first-time setup to the right place, registers this app’s domain path in the integrity baseline, and gives Phase 4 a clean gate.

1. Choose the hosting account and SSH alias

Section titled “1. Choose the hosting account and SSH alias”

Confirm which hosting account this app will deploy to and which local SSH alias reaches it. Use the same alias you will use in Phase 4 and Phase 5.

  1. Discover any existing SSH alias before treating SSH as unconfigured.

    Terminal window
    grep -nE '^Host |HostName|User|Port|IdentityFile' ~/.ssh/config 2>/dev/null
    # Match the target hosting IP/domain from Zaj-PROJECT.md or the onboarding summary.
    # Expected: either a reusable Host alias appears, or you know one must be created.
    • Expected: if an existing alias matches host/user/port, reuse it and record that alias in Zaj-PROJECT.md. If it points at an old IP, update the stanza. If no alias exists, return to Phase 2 SSH setup and create one.
  2. Set the alias for this terminal session.

    Terminal window
    export SSH_ALIAS="<selected-hosting-account-ssh-alias>"
    export PHPBIN="${PHPBIN:-php}" # replace with /opt/alt/phpXX/usr/bin/php once Phase 4 confirms it
    ssh -o BatchMode=yes -o ConnectTimeout=8 "$SSH_ALIAS" "pwd && $PHPBIN -v | head -1"
    # Expected: SSH connects without an interactive password prompt and prints a remote path plus PHP version.
    • Expected: the command exits 0; a timeout, password prompt, or unknown host means SSH is not ready for Phase 4.

2. Check whether Admin-Server already exists and is alive

Section titled “2. Check whether Admin-Server already exists and is alive”

Run the status script and freshness probe if the server already has ~/Admin-Server/. This is the fast path for a hosting account that was prepared by a previous project — but only if the cron-backed logs are fresh.

  1. Run the status and freshness check.

    Terminal window
    ssh "$SSH_ALIAS" 'bash -s' <<'REMOTE'
    set -euo pipefail
    cd ~/Admin-Server
    test -x scripts/status.sh
    ./scripts/status.sh
    now=$(date +%s)
    check_log() {
    label="$1"; path="$2"; max_age="$3"
    if [ ! -f "$path" ]; then echo "❌ STALE $label — missing $path"; exit 1; fi
    mtime=$(stat -c %Y "$path")
    age=$((now - mtime))
    if [ "$age" -gt "$max_age" ]; then
    echo "❌ STALE $label — last run $(date -d "@$mtime" -Is), age ${age}s, max ${max_age}s"; exit 1
    fi
    echo "✅ fresh $label — last run $(date -d "@$mtime" -Is)"
    }
    check_any_log() {
    label="$1"; max_age="$2"; shift 2
    for path in "$@"; do
    [ -f "$path" ] && check_log "$label" "$path" "$max_age" && return 0
    done
    echo "❌ STALE $label — missing expected log: $*"; exit 1
    }
    check_any_log "config snapshot" 172800 logs/snapshot-config.log
    check_any_log "integrity" 172800 logs/integrity.log logs/integrity-check.log
    check_any_log "disk/inode" 43200 logs/resource.log logs/resources.log logs/resource-check.log
    check_any_log "PHP error scan" 43200 logs/error-log.log logs/error-log-check.log
    check_any_log "domain inventory" 2592000 logs/domain-inventory.log
    check_any_log "log rotation" 1209600 logs/rotate-logs.log
    REMOTE
    # Expected: status.sh exits 0 and every log row prints "fresh"; any STALE row blocks Phase 4.
    • Expected: the script runs and every log freshness row passes. If the file is missing, not executable, reports missing setup, or prints STALE, continue to step 3 and fix the shared-hosting playbook before Phase 4.
  2. Add this app’s domain path to the Admin-Server integrity baseline.

    Terminal window
    APP_DOMAIN="<selected-domain-from-Zaj-PROJECT>"
    ssh "$SSH_ALIAS" "APP_DOMAIN='$APP_DOMAIN' bash -s" <<'REMOTE'
    set -euo pipefail
    cd ~/Admin-Server
    path="$HOME/domains/$APP_DOMAIN"
    conf="config/monitored-paths.conf"
    touch "$conf"
    for monitored in "$HOME/.ssh/authorized_keys" "$path"; do
    grep -Fxq "$monitored" "$conf" 2>/dev/null || printf '%s\n' "$monitored" >> "$conf"
    grep -Fx "$monitored" "$conf"
    done
    ./scripts/generate-baseline.sh
    git add "$conf" baselines/checksums.md5
    git diff --cached --quiet || git commit -m "Monitor $APP_DOMAIN domain path"
    REMOTE
    # Expected: monitored-paths.conf contains authorized_keys + the app domain path; baseline regenerated.
    • Expected: ~/.ssh/authorized_keys and the domain path are present in monitored-paths.conf, so integrity monitoring catches planted SSH keys and app-path drift once the app is deployed.

3. Run the shared-hosting playbook when this account is new

Section titled “3. Run the shared-hosting playbook when this account is new”

If the status script is missing or clearly incomplete, stop this app playbook and run the shared-hosting playbook for the hosting account. Return here only after that server playbook reaches its checklist.

  1. Open and complete the shared-hosting playbook.

    • Set up shared hosting

    • Expected: the hosting account has ~/Admin-Server/, executable scripts, configured monitoring/alert state, and a documented SSH alias.

  2. Re-run the status + freshness check after setup.

    Terminal window
    ssh "$SSH_ALIAS" '~/Admin-Server/scripts/status.sh'
    # Expected: status.sh shows the correct identity. Then rerun step 2's freshness probe and require no STALE rows.
    • Expected: no missing Admin-Server toolkit and no stale cron-backed logs. Fix failed checks in the shared-hosting playbook before continuing.

Write the result where future sessions can find it without re-discovering the hosting account.

  1. Record the non-secret server mapping in Zaj-PROJECT.md.

    Terminal window
    cat <<'EOF' >> Zaj-PROJECT.md
    ## Shared-hosting readiness — <environment> — <YYYY-MM-DD>
    - SSH alias: <SSH_ALIAS>
    - Host/user/port: <host> · <user> · <port>
    - Hosting account: <host/account nickname>
    - Admin-Server status: verified with fresh logs; monitored-paths.conf includes ~/.ssh/authorized_keys and this domain
    - Shared-hosting playbook: completed or previously verified
    EOF
    # Expected: Zaj-PROJECT.md records the reusable non-secret alias/readiness facts.
    • Expected: Zaj-PROJECT.md now carries the alias/readiness state that Phase 4 consumes.
  2. Record personal/machine-only notes in CLAUDE.local.md when useful.

    Terminal window
    cat <<'EOF' >> CLAUDE.local.md
    ## Shared-hosting readiness
    - SSH alias: <SSH_ALIAS>
    - Hosting account: <host/account nickname>
    - Admin-Server status: verified with fresh logs on <YYYY-MM-DD>
    - monitored-paths.conf includes: ~/.ssh/authorized_keys and ~/domains/<domain>
    - Shared-hosting playbook: completed or previously verified
    EOF
    # Expected: CLAUDE.local.md records the alias and readiness state without secrets.
    • Expected: CLAUDE.local.md remains gitignored; no webhook URL, password, token, or private key is written into tracked files.

Do not mark this step done until every box below is checked.

  • 🔀 Hosting account chosen — the app’s intended hosting account and SSH alias are known.
  • 🤖 SSH worksssh "$SSH_ALIAS" ... connects without an interactive password prompt.
  • 🤖 Admin-Server present~/Admin-Server/scripts/status.sh exists and is executable.
  • 🔀 Shared-hosting setup complete — first-time accounts completed the shared-hosting playbook before this app moved on.
  • 🤖 Status + liveness cleanstatus.sh exits 0 and the log freshness probe has no STALE rows.
  • 🤖 Integrity baseline covers app~/Admin-Server/config/monitored-paths.conf includes ~/.ssh/authorized_keys and this app’s ~/domains/<domain> path, the baseline was regenerated, and the change is committed in the Admin-Server repo.
  • 🤖 Project state updatedZaj-PROJECT.md records the non-secret alias/readiness state Phase 4 consumes.
  • 🔀 Local note updatedCLAUDE.local.md records any machine-only alias/readiness note and remains gitignored.