Files
timebank-cc-public/references/RUNBOOK_LARAVEL_10_TO_11.md
T

276 lines
13 KiB
Markdown

# Runbook: Uuro staging server, Laravel 10 to Laravel 11
The checklist for upgrading the Uuro staging server. Work through it top to bottom and tick the boxes. The
background, every question the script asks and the troubleshooting table are in
[UPGRADE_LARAVEL_10_TO_11.md](UPGRADE_LARAVEL_10_TO_11.md).
Timebank.cc runs Laravel 11 since 2026-10-15; Uuro is the last installation on Laravel 10.
| | |
|---|---|
| From | branch `uuro`, Laravel 10.48 |
| To | `origin/laravel-11`, Laravel 11.57, on branch `main` |
| Tool | `scripts/upgrade.sh --leave-branch`, from the target branch, run from `/tmp` |
| Duration | about 30 minutes; the site shows the maintenance page for 15 to 20 of them (search is rebuilt) |
| Rollback | `bash storage/app/upgrades/<stamp>/upgrade.sh --rollback`: back to branch `uuro` and its files |
**Why the branch goes.** Uuro ran a branch of its own with its config, logos, favicons and Open Graph tags. Those now
live in the platform folder `platform/` (outside git, see `MULTI_PLATFORM_INSTANCES.md`, section 3), and the Open
Graph tags and extra favicons are in the code for every platform. So the installation moves to `main`, and later
upgrades are the same as for Timebank.cc. The upgrade cannot fast-forward the branch; `--leave-branch` moves the
installation instead:
- it lists the commits of `uuro` that will no longer be in the installation and keeps them in a tag
`pre-leave-uuro-<stamp>`; `origin/uuro` stays on Gitea as an archive;
- it lists the tracked files the move deletes, among them `config/uuro.php`, and refuses to move while
`platform/config.php` is missing;
- it asks you to type `uuro`, then moves the installation to branch `main` at the target;
- the rollback returns to branch `uuro` with all its files.
Rehearsed on a copy of `origin/uuro` on 2026-10-19: the move, the site from the platform folder, the rollback.
Start every terminal session by setting the application root once (the server's own path):
```bash
export APP=/var/www/CHANGE-ME # the application root on this server
```
Every block below is read-only unless it says otherwise.
---
## T-1 day: preparation
### 1. Pick the moment
- [ ] A quiet hour; the Uuro developer and someone who can test (log in, pay, chat) are available.
### 2. Check the server
As root:
```bash
(
cd "${APP:?set APP first}" || exit 1
echo "== versions"; php artisan --version; php -v | head -1; git branch --show-current
echo "== tmux"; tmux -V 2>/dev/null || echo "tmux MISSING: apt-get install -y tmux"
echo "== disk"; df -h . | tail -1; du -sh vendor
echo "== local changes (a changed public/storage and public/build are normal)"
git -c core.fileMode=false status --short --untracked-files=no
echo "== commits not on Gitea (should be empty)"
git fetch -q origin uuro && git log --oneline origin/uuro..HEAD
echo "== .env keys"
grep -E '^(APP_URL|DEPLOY_ENVIRONMENT|DEPLOY_APP_DIR|DEPLOY_SERVER_TYPE|DEPLOY_WS_URL|TIMEBANK_CONFIG|TIMEBANK_THEME|DB_DEPLOY_USERNAME|SCOUT_QUEUE_TIMEOUT|PLATFORM_PATH)=' .env
echo "DB_DEPLOY_PASSWORD set: $(grep -c '^DB_DEPLOY_PASSWORD=.' .env)"
echo "== apt (look for GPG or EXPKEYSIG errors)"
apt-get update 2>&1 | grep -iE 'err|gpg|expkeysig' || echo "apt ok"
echo "== worker units: folder and PHP must exist"
for u in /etc/systemd/system/*.service; do
grep -q "artisan" "$u" 2>/dev/null || continue
wd=$(grep -oP '^WorkingDirectory=\K.*' "$u"); bin=$(grep -oP '^ExecStart=\K\S+' "$u")
printf '%-45s %-28s %s %s\n' "$(basename "$u")" "$wd" "$([ -d "$wd" ] && echo ok || echo MISSING)" "$bin"
done
)
```
- [ ] Laravel 10.x, branch `uuro`, PHP 8.2 or newer; tmux installed.
- [ ] Free disk space at least twice `vendor/` plus 2 GB.
- [ ] Local changes: only `public/storage` and `public/build` (and files under them). Anything else: find out why first.
- [ ] No commits that are not on Gitea. If there are, push them to `origin/uuro` first: they stay in the archive.
- [ ] `.env`: `TIMEBANK_CONFIG=uuro`, `TIMEBANK_THEME=uuro`, `DEPLOY_ENVIRONMENT=server` with the other `DEPLOY_*`
keys; `DB_DEPLOY_PASSWORD set: 1` or the MySQL root password at hand; `SCOUT_QUEUE_TIMEOUT=1800` (add it if
missing). No `PLATFORM_PATH`: the folder is `platform/` in the application root.
- [ ] `apt ok`. An `EXPKEYSIG` for packages.sury.org: fix it first (guide, Troubleshooting, last row).
- [ ] Every worker unit points at `$APP` and an existing PHP (on Timebank.cc four workers pointed at a removed folder
for months). Fix a unit before the upgrade (backup first), then `systemctl daemon-reload`.
If `git fetch` asks for the Gitea login every time, cache it for an hour:
`git config --global credential.helper 'cache --timeout=3600'`.
### 3. Build the platform folder (creates `platform/`, changes nothing else)
The move replaces or deletes the files of branch `uuro`, so first copy what makes Uuro Uuro into the platform folder.
The old code ignores the folder; it is used from the moment the new code runs.
```bash
(
cd "${APP:?set APP first}" || exit 1
[ ! -e platform ] || { echo "platform/ exists already: not touched"; exit 1; }
mkdir -p platform/public platform/views/logos platform/lang
cp config/uuro.php platform/config.php
cp resources/views/logos/uuro.blade.php platform/views/logos/uuro.blade.php
cp storage/app/public/app-images/app_mail_logo.png platform/public/mail-logo.png
cp storage/app/public/app-images/app_mail_logo_inverted.png platform/public/mail-logo-inverted.png
cp public/images/og-image.png platform/public/og-image.png
for f in favicon.ico favicon.svg favicon-96x96.png apple-touch-icon.png web-app-manifest-192x192.png web-app-manifest-512x512.png; do
[ -f "public/$f" ] && cp "public/$f" "platform/public/$f"
done
chown -R --reference=config platform
find platform -type f | sort
)
```
- [ ] It lists `config.php`, `views/logos/uuro.blade.php` and `public/` with the mail logos, `og-image.png` and the
favicons.
### 4. Dry run (changes nothing)
```bash
tmux new -s upgrade
```
```bash
(
cd "${APP:?set APP first}" || exit 1
git fetch origin || { echo "git fetch failed"; exit 1; }
git show origin/laravel-11:scripts/upgrade.sh > /tmp/timebank-upgrade.sh
lines=$(wc -l < /tmp/timebank-upgrade.sh)
[ "$lines" -gt 100 ] || { echo "upgrade.sh did not come through ($lines lines)"; exit 1; }
bash /tmp/timebank-upgrade.sh --dry-run --leave-branch --target origin/laravel-11
)
```
- [ ] `On branch 'uuro', which this upgrade leaves`; the list of commits that leave (37 on 2026-10-19, more if the
branch got new ones); no warning about unpushed commits.
- [ ] `Tracked files the move deletes` includes `config/uuro.php`, and the script does not refuse.
- [ ] PHP accepted for the command line and the website; enough disk space;
`Platform folder: ... (config.php lang public views)`.
- [ ] `2. Plan`: `Leaves branch 'uuro' for main`, `Laravel major upgrade (10 -> 11)`, 6 new migrations that add
tables only (polls).
- [ ] Ends with `Dry run: nothing was changed`.
If the dry run stops, fix the cause today, not on the day itself.
---
## Day of the upgrade
### 5. Start
In tmux, the same block as in step 4 but without `--dry-run`, as a single line (the script asks questions):
```bash
cd "$APP" && git fetch origin && git show origin/laravel-11:scripts/upgrade.sh > /tmp/timebank-upgrade.sh && bash /tmp/timebank-upgrade.sh --leave-branch --target origin/laravel-11
```
Open a second tmux window now (`Ctrl-b c`, then `cd "$APP"`). Switch with `Ctrl-b n`. If the SSH connection drops,
log in again and run `tmux attach -t upgrade`.
### 6. Work through the script
- [ ] **2. Plan**: `Upgrade this installation to <commit>?` → `y`; `Type the branch name 'uuro'` → `uuro`.
- [ ] **3. Backup**: `Make a database backup now?` → `y`. Wait for `Backup verified`.
- [ ] **4. Maintenance**: run the printed `php artisan down --retry=60 --secret=<secret>` in window 2 and **write down
the secret**. Press Enter in window 1.
- [ ] **5. Deploy**: `Left branch 'uuro' (tag pre-leave-uuro-<stamp>); now on main.`, then `deploy.sh` runs:
- `Would you like to merge new keys now? (y/N)` → `y`; then `yes` for each file. The new keys for Uuro go into
`platform/config.php` (65 on 2026-10-19); the footer and other lists stay as they are.
- MySQL user and password: only without `DB_DEPLOY_*` in `.env`.
- If deploy.sh fails: the site stays in maintenance. See the guide, Troubleshooting.
- After it: `public/storage linked to this server's storage.`
- [ ] **6. Version check**: `Laravel Framework 11.x`.
- [ ] **7. Restart**: run the printed restart commands in window 2 (check they report `active (running)`), then press
Enter in window 1.
### 7. Test, while visitors still see the maintenance page
Open `<APP_URL>/<secret>` once in your browser. That browser now bypasses the maintenance page.
- [ ] The site is in the Uuro theme, with Uuro's logo and favicon.
- [ ] Log in; switch to an organisation profile and to a bank profile, and back.
- [ ] Make a small payment, and check it in the transaction list.
- [ ] Send a chat message with an image.
- [ ] Search for a person and for a post (search was rebuilt during the deploy).
- [ ] Open the admin pages: profiles, statistics, mailings.
- [ ] Request a password reset for an admin or bank profile: it works now (on branch `uuro` it failed).
- [ ] The page source has `<meta property="og:image" content=".../platform/og-image.png">`.
- [ ] In window 2:
```bash
php artisan upgrade:verify
php artisan platform:check
tail -n 50 storage/logs/laravel-$(date +%F).log
```
`upgrade:verify` reports `platform config: platform/config.php` and no failures; `platform:check` reports
`Platform config: platform/config.php` and `linked at /platform` (the logo copied by hand gives an `i` line: fine).
Good to know: queue workers do not run in maintenance mode, so like and star counters (updated by queued jobs) lag
behind during this test. A count that looks one off after liking and unliking is that; it corrects itself once the
site is live (seen on Timebank.cc on 2026-10-19).
### 8. Go or no-go
| Go (`g`) if | No-go (`r`) if |
|---|---|
| every test above worked | log-in, payments or profile switching fail |
| the Uuro theme, logo and favicons show | the site shows Timebank.cc's brand |
| no new errors in the log | new errors appear on every page view |
- **Go**: answer `g`, run `php artisan up` in window 2, press Enter. Check the public site once from a private window.
- **No-go**: answer `r`. The rollback starts right away: back to branch `uuro` with `config/uuro.php` and its other
files; restoring the database is safe now.
Note the stamp the script prints (`storage/app/upgrades/<stamp>/`).
---
## After going live
### 9. The first hour
- [ ] Watch the log: `tail -f storage/logs/laravel-$(date +%F).log`.
- [ ] `php artisan config:merge --all --dry-run` reports nothing new.
- [ ] Review the new keys in `platform/config.php`: they came from the default template, e.g. the email sign-off
`platform_sign_off_signature` ("happy Timebanking!").
- [ ] Workers and Reverb are running; the queue drains: `php artisan queue:monitor high,messages,default,emails,mailing,low`.
### 10. The next three days: watch the logs
Once a day, read-only:
```bash
( cd "${APP:?set APP first}"; for d in $(seq 0 3); do f=storage/logs/laravel-$(date -d "-$d day" +%F).log; [ -f $f ] && echo "== $f: $(grep -c '\.ERROR' $f) errors" && grep '\.ERROR' $f | cut -c1-160 | sed -E 's/\[[^]]*\] //' | sort | uniq -c | sort -rn | head -5; done )
```
### 11. After three quiet days: clean up and finish
- [ ] Remove the snapshot of `vendor/`; keep the database backup a little longer:
```bash
( cd "${APP:?set APP first}"; s=storage/app/upgrades/<stamp>/; ls -lh $s; rm -v ${s}vendor.tar.gz )
```
- [ ] Put `platform/` in a private git repository of its own: its history and its off-site copy (the server's
backups stay on the server). No secrets in it; they stay in `.env`.
- [ ] Keep `origin/uuro` on Gitea as an archive.
- [ ] Developers: with Uuro on Laravel 11, every installation is. Fast-forward `main` to `laravel-11`, so routine
`./deploy.sh -e server` deploys pull the new version again on both servers. From then on `deploy.sh` stops a
routine deploy that would raise the Laravel major version (e.g. to 12) and points to `scripts/upgrade.sh`.
---
## Rollback
| When | Command | Database |
|---|---|---|
| Before going live | answer `r` at the go/no-go question | restore offered; safe |
| After going live | `bash storage/app/upgrades/<stamp>/upgrade.sh --rollback` | code only, unless you type `RESTORE` |
The rollback returns to branch `uuro` at its old commit, with `config/uuro.php` and the other files of the branch;
the platform folder stays (the old code ignores it). A database restore after going live deletes everything written
since the backup; usually the code-only rollback is right, because the old code ignores new tables.
After a rollback, do not run `./deploy.sh` until the problem is fixed. Send
`storage/app/upgrades/<stamp>/upgrade.log`, `rollback.log` and `state.env` to the developers.
## Record
| | |
|---|---|
| Date and start time | |
| Previous commit (branch `uuro`) | |
| New commit (branch `main`) | |
| Upgrade stamp and tag `pre-leave-uuro-...` | |
| Live at | |
| Issues and how they were solved | |