Snapshot of main at 9f39a6e1e (2026-11-02)
This commit is contained in:
commit
6ccf1792d7
2580 files changed
+1040202
No files matched your search
@@ -0,0 +1,299 @@
|
||||
# Upgrade from Laravel 10 to Laravel 11, for any server and platform
|
||||
|
||||
This guide upgrades an installation of this application from **Laravel 10** (any older version of the
|
||||
`main` branch) to **Laravel 11** (the `laravel-11` branch). It is the same for every platform that runs this
|
||||
code (Timebank.cc, Uuro or any other) and for every server: production, development or test.
|
||||
|
||||
Check where you start:
|
||||
|
||||
```bash
|
||||
php artisan --version # Laravel Framework 10.x: this guide applies
|
||||
git branch --show-current # main
|
||||
```
|
||||
|
||||
The upgrade is done by `scripts/upgrade.sh`. The script checks the server, makes a verified database backup,
|
||||
runs the new `deploy.sh` while the site is in maintenance mode, and lets you test before visitors see the new
|
||||
version. If something is wrong, it rolls back.
|
||||
|
||||
Plan about 30 minutes. The site itself is offline (maintenance page) for about 5 to 15 minutes.
|
||||
|
||||
Upgrade one server at a time. Start with a test or development server if you have one.
|
||||
|
||||
**Status (2026-10-19).** Timebank.cc runs Laravel 11 since 2026-10-15. The last installation on Laravel 10 is the Uuro
|
||||
staging server, which runs a branch of its own (`uuro`) instead of `main`. It moves to `main` during the upgrade
|
||||
with `upgrade.sh --leave-branch`, after its config, logos and favicons are copied into its platform folder `platform/`.
|
||||
Its day-by-day checklist is [RUNBOOK_LARAVEL_10_TO_11.md](RUNBOOK_LARAVEL_10_TO_11.md); this guide explains each step.
|
||||
|
||||
---
|
||||
|
||||
## 1. Before you start
|
||||
|
||||
### Requirements
|
||||
|
||||
| What | Needed | How to check |
|
||||
|---|---|---|
|
||||
| PHP for the website and the command line | 8.2 or newer (Laravel 11 needs it) | `php -v`; the script also asks the website itself |
|
||||
| Git branch | `main` | `git branch --show-current` |
|
||||
| tmux or screen | so a dropped SSH connection does not stop the upgrade halfway | `tmux -V` (capital V); install with `apt-get install -y tmux` |
|
||||
| Free disk space | about twice the size of `vendor/` plus 2 GB | `df -h .` and `du -sh vendor` |
|
||||
| MySQL user that may drop and create the database (root or a deployment user) | for migrations, and for a database restore during a rollback | see `.env` below |
|
||||
| Time and a quiet moment | not during a busy period or a mailing | |
|
||||
|
||||
Local changes to tracked files stop the upgrade. Two kinds of change are expected and ignored:
|
||||
- `public/build/`, which `deploy.sh` rebuilds on every server
|
||||
- file modes (the executable bit), which `deploy.sh`'s `chmod -R 775` changes
|
||||
|
||||
Check with:
|
||||
|
||||
```bash
|
||||
git -c core.fileMode=false status --short --untracked-files=no -- . ':(exclude)public/build'
|
||||
```
|
||||
|
||||
This should print nothing. If it lists files, find out why they were changed on the server before you continue.
|
||||
|
||||
### Check `.env`
|
||||
|
||||
These keys are read by `deploy.sh` and `scripts/upgrade.sh`. Show them without printing passwords:
|
||||
|
||||
```bash
|
||||
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)=' .env
|
||||
grep -c '^DB_DEPLOY_PASSWORD=.' .env # 1 = set
|
||||
```
|
||||
|
||||
| Key | Purpose |
|
||||
|---|---|
|
||||
| `APP_URL` | The site's address. The script uses it to ask the website which PHP version serves it. |
|
||||
| `DEPLOY_ENVIRONMENT=server` | `deploy.sh` runs in server mode. Server mode also needs `DEPLOY_APP_DIR`, `DEPLOY_SERVER_TYPE` (`dev` or `prod`) and `DEPLOY_WS_URL`. |
|
||||
| `TIMEBANK_CONFIG` | The platform config, `config/<name>.php`. It can be any name, e.g. `uuro`. |
|
||||
| `TIMEBANK_THEME` | `timebank_cc`, `uuro`, `vegetable` or `yellow`. |
|
||||
| `DB_DEPLOY_USERNAME`, `DB_DEPLOY_PASSWORD` | The MySQL user for migrations and database restores. Without them you are asked for one: have the MySQL root password ready. |
|
||||
| `SCOUT_QUEUE_TIMEOUT=1800` | Recommended: lets the nightly search re-index finish without the queue worker being killed. |
|
||||
|
||||
### Know your restart commands
|
||||
|
||||
After the deploy you restart long-running processes, because they still hold the old code. The script
|
||||
suggests commands for the services it finds. Typically:
|
||||
|
||||
```bash
|
||||
sudo systemctl restart <your Reverb service>
|
||||
sudo systemctl reload apache2 # or nginx
|
||||
sudo systemctl reload php8.3-fpm # if the site runs on PHP-FPM
|
||||
```
|
||||
|
||||
`deploy.sh` restarts the queue workers itself.
|
||||
|
||||
---
|
||||
|
||||
## 2. Dry run (changes nothing)
|
||||
|
||||
Log in to the server, start tmux and go to the application root:
|
||||
|
||||
```bash
|
||||
tmux new -s upgrade # reconnect later with: tmux attach -t upgrade
|
||||
cd /var/www/<your app>
|
||||
git fetch origin
|
||||
git show origin/laravel-11:scripts/upgrade.sh > /tmp/timebank-upgrade.sh
|
||||
bash /tmp/timebank-upgrade.sh --dry-run --target origin/laravel-11
|
||||
```
|
||||
|
||||
Always run the script from `/tmp`, taken from the target branch. The copy in your installation is older or
|
||||
absent.
|
||||
|
||||
A good dry run ends with `Dry run: nothing was changed` and shows:
|
||||
- `1. Checks`: the PHP version is accepted for both the command line and the website, there is enough disk
|
||||
space, and `Made on this server, differ from git: ...` (if shown) is fine: deploy.sh makes those files
|
||||
again. A changed `public/storage` is never reported: it is this server's own storage link.
|
||||
- `2. Plan`: current and target commit, `Laravel major upgrade (10 -> 11)`, and the number of new migrations.
|
||||
If any migration changes existing tables, a rollback after going live needs the database restore.
|
||||
|
||||
If it stops instead, see [Troubleshooting](#7-troubleshooting).
|
||||
|
||||
---
|
||||
|
||||
## 3. The upgrade
|
||||
|
||||
```bash
|
||||
bash /tmp/timebank-upgrade.sh --target origin/laravel-11
|
||||
```
|
||||
|
||||
The script goes through eight steps and waits for you at each question. What to answer:
|
||||
|
||||
| Step | Question or action | Answer |
|
||||
|---|---|---|
|
||||
| 1. Checks | `Not running inside tmux or screen... Continue anyway?` (only outside tmux) | Stop (`N`) and start tmux. |
|
||||
| 2. Plan | `Upgrade this installation to <commit>?` | `y` |
|
||||
| 3. Backup | `Make a database backup now with scripts/backup-database.sh?` | `y`. The backup is verified and kept with the upgrade state, together with a snapshot of `vendor/` and `public/build`. |
|
||||
| 4. Maintenance | The script prints a command with a secret. | In a second tmux window (`Ctrl-b c`), in the application root, run that command: `php artisan down --retry=60 --secret=<secret>`. Then press Enter in the first window. |
|
||||
| 5. Deploy | The new `deploy.sh` runs and asks its own questions. | See below. |
|
||||
| 6. Version check | Shows `Laravel Framework 11.x`. | Nothing to do. |
|
||||
| 7. Restart | Shows restart commands for this server. | Run them in the second window, then press Enter. |
|
||||
| 8. Go / no-go | `Go live (g) or roll back now (r)?` | First test (see below), then `g` or `r`. |
|
||||
|
||||
### Questions from `deploy.sh` (step 5)
|
||||
|
||||
- **`New configuration keys available ... Would you like to merge new keys now? (y/N)`**: press `y`
|
||||
(a single key press). For each config file it then asks `Merge these keys into <file>? (yes/no)`: type `yes`.
|
||||
New settings are added and your own values stay as they are. A backup of each file goes to
|
||||
`storage/config-backups/`.
|
||||
- **`MySQL username [root]` / `MySQL password`**: only when `DB_DEPLOY_*` is not in `.env`.
|
||||
- **`You have uncommitted changes. Continue anyway? (y/n)`**: this should not appear any more. If it does,
|
||||
check what `git status` lists before you answer.
|
||||
|
||||
If `deploy.sh` fails, the script stops and the site stays in maintenance mode. See
|
||||
[Troubleshooting](#7-troubleshooting).
|
||||
|
||||
### Test before going live (step 8)
|
||||
|
||||
The site is still in maintenance mode. Open `<APP_URL>/<secret>` once in your browser: that browser can then
|
||||
use the site while visitors still see the maintenance page. Check:
|
||||
|
||||
- log in, and switch to an organisation or bank profile
|
||||
- a payment
|
||||
- a chat message with an image
|
||||
- a poll, if your platform uses polls
|
||||
- search
|
||||
- the error log: `tail -n 50 storage/logs/laravel-$(date +%F).log` (or `laravel.log`)
|
||||
|
||||
Then:
|
||||
- **All fine**: answer `g`. Run `php artisan up` in the second window, then press Enter.
|
||||
- **Something wrong**: answer `r`. The rollback starts right away and may also restore the database, which
|
||||
is safe at this point because nothing went live.
|
||||
|
||||
---
|
||||
|
||||
## 4. After the upgrade
|
||||
|
||||
0. **Health check** (once this version has it): `php artisan upgrade:verify` checks profiles, permissions,
|
||||
white-label settings, payment protection, search and background services, read-only. Run it before and
|
||||
after an upgrade; exit code 1 means a check failed.
|
||||
1. **Platform settings** (all platforms). See which new settings arrived, and check that nothing is waiting:
|
||||
|
||||
```bash
|
||||
php artisan config:merge --all --dry-run # should report nothing new
|
||||
```
|
||||
|
||||
On a platform other than Timebank.cc, review these in its platform config (`platform/config.php`, or
|
||||
`config/<TIMEBANK_CONFIG>.php` without a platform folder). They came from the default template:
|
||||
|
||||
| Setting | Default for a new platform | Meaning |
|
||||
|---|---|---|
|
||||
| `platform_translations.*` | your existing names | Platform name, currency and terms per language. |
|
||||
| `mail.*` | your existing addresses | Sender and recipient addresses. |
|
||||
| `local_pages` | all `false` | Timebank.cc's city pages (`the-hague`, `lekkernassuh`, `amst-brus-lisb`). A page that is off has no URL, and its footer link disappears. |
|
||||
| `android_app.enabled` | `false` | The Android app page and the app's update check (`/app/version`). |
|
||||
| `account_info.*_self`, `*_privileged` | `true` | Which balances and totals owners and privileged viewers (admins, banks) see. |
|
||||
|
||||
A setting a config file does not have yet keeps its old behaviour until it is merged.
|
||||
|
||||
2. **Email logo, favicons and preview image** (platforms other than Timebank.cc; all branding is described in
|
||||
[MULTI_PLATFORM_INSTANCES.md](MULTI_PLATFORM_INSTANCES.md), sections 3 and 6). Without its own logo file, a
|
||||
platform gets a text logo with its name in emails and PDFs. Put the files in the platform folder (Uuro's
|
||||
runbook copies them there from its branch):
|
||||
|
||||
```
|
||||
platform/public/mail-logo.png dark logo, for white backgrounds (PNG, about 900×700, transparent)
|
||||
platform/public/mail-logo-inverted.png light logo, for the newsletter header
|
||||
platform/public/favicon.ico, favicon-32x32.png, favicon-16x16.png, apple-touch-icon.png
|
||||
platform/public/og-image.png preview for shared links (about 1200×630)
|
||||
```
|
||||
|
||||
`deploy.sh` links them at `/platform` (`php artisan platform:link`); `php artisan platform:check` confirms it.
|
||||
|
||||
3. **Workers and scheduler**. Check that the queue workers run, with all queues:
|
||||
|
||||
```bash
|
||||
sudo systemctl status 'timebank-*' --no-pager | grep -E 'Active|●'
|
||||
```
|
||||
|
||||
4. **The next days**. Watch the error log. When all is well, free the disk space of the snapshot. The
|
||||
script prints the exact command:
|
||||
|
||||
```bash
|
||||
rm storage/app/upgrades/<stamp>/vendor.tar.gz
|
||||
```
|
||||
|
||||
Keep the database backup in that folder a little longer.
|
||||
|
||||
### Routine deploys afterwards
|
||||
|
||||
`./deploy.sh -e server` keeps working as before. It pulls `main`. Until `main` itself has been
|
||||
fast-forwarded to the Laravel 11 version, that pull finds nothing new on an upgraded server, which is
|
||||
harmless.
|
||||
|
||||
`main` is fast-forwarded to Laravel 11 only after every server has been upgraded, so after Uuro: a Laravel 10
|
||||
server's own `deploy.sh` would otherwise pull Laravel 11 without the protection of this script. From Laravel 11
|
||||
on, `deploy.sh` stops a routine server deploy that would raise the Laravel major version.
|
||||
|
||||
In its "pull conflict" question, never choose option 2 (reset and `git clean`): it deletes untracked files,
|
||||
such as uploads in `storage/`.
|
||||
|
||||
---
|
||||
|
||||
## 5. Rollback
|
||||
|
||||
Roll back with the copy of the script in the upgrade's state folder. The script printed the exact command;
|
||||
without a stamp it takes the latest upgrade:
|
||||
|
||||
```bash
|
||||
bash storage/app/upgrades/<stamp>/upgrade.sh --rollback
|
||||
```
|
||||
|
||||
It asks for confirmation, switches on maintenance mode and resets the code to the previous commit. It then
|
||||
restores `vendor/`, `bootstrap/cache` and the server's own `public/build` from the snapshot (no download
|
||||
needed), clears the caches and tells you what to restart.
|
||||
|
||||
**The database:**
|
||||
- **Before going live**, the rollback offers to restore the backup. That is safe.
|
||||
- **After going live**, it rolls back the code only, unless you type `RESTORE`. A restore deletes everything
|
||||
written since the backup: payments, messages, votes and new profiles. Usually the code-only rollback is
|
||||
right, because the old code ignores new tables.
|
||||
|
||||
The restore connects as `DB_DEPLOY_USERNAME`, or asks for a MySQL user that may drop and create the
|
||||
database.
|
||||
|
||||
After a rollback, do not run `./deploy.sh` until the problem is fixed: it would pull the version you just
|
||||
left.
|
||||
|
||||
---
|
||||
|
||||
## 6. What the upgrade changes
|
||||
|
||||
- **Laravel 10 to 11.** Laravel 11.57 and the matching package versions (Livewire 3.8 among them); the
|
||||
application code was adapted. No database changes are needed for it. PHP 8.2 or newer is required.
|
||||
- **Platform config.** A platform may use its own config name: `TIMEBANK_CONFIG=myorg` with `config/myorg.php`.
|
||||
`deploy.sh` creates the file from `config/timebank-default.php.example` when it is missing, and
|
||||
`config:merge` keeps it up to date. A config file that is not in git is excluded from git on that server
|
||||
(`.git/info/exclude`), so deploys no longer report it as an uncommitted change.
|
||||
- **Settings for platform-specific pages.** `local_pages` and `android_app`, see [After the upgrade](#4-after-the-upgrade).
|
||||
- **Branding.** Texts that showed "Timebank" or "Timebank.cc" now use the platform name. Emails use the
|
||||
theme's logo or the generated text logo.
|
||||
- **Deploys.** `deploy.sh` no longer stops at a server-built `public/build` or at mode-only changes, and stops a
|
||||
routine server deploy that would raise the Laravel major version.
|
||||
- **Platform folder.** Everything platform-specific may live in `platform/` (outside git): config, theme, text and
|
||||
template overrides, logos, favicons and the preview image. See
|
||||
[MULTI_PLATFORM_INSTANCES.md](MULTI_PLATFORM_INSTANCES.md), section 3. A platform branch of its own is no longer
|
||||
needed; `upgrade.sh --leave-branch` moves an installation off one.
|
||||
- **Open Graph tags** (preview of shared links) and optional favicon formats for every platform.
|
||||
- **Admin roles.** The legacy roles `Admin\{id}\admin` are replaced by the roles from `admin_roles`
|
||||
(`database:update` runs `admin-roles:migrate`).
|
||||
|
||||
---
|
||||
|
||||
## 7. Troubleshooting
|
||||
|
||||
| Message | Meaning and what to do |
|
||||
|---|---|
|
||||
| `There are local changes to tracked files` | Files were edited on the server. Look at them with `git diff`. Commit the change upstream, or save a copy and `git checkout -- <file>`. |
|
||||
| `This installation has commits that are not on <target>` | The server has local commits. A fast-forward is not possible: ask the developers. |
|
||||
| `This server's PHP does not meet the requirements` / `This site is served by PHP x` | Install PHP 8.2 or newer (with the extensions listed) and switch the site to it first. |
|
||||
| `Could not ask the site which PHP serves it` | `APP_URL` is unreachable from the server itself. The script lists the PHP versions it finds and asks you to confirm. |
|
||||
| `Only N MB free` | Free disk space (old backups in `backups/`, old snapshots in `storage/app/upgrades/`). |
|
||||
| `deploy.sh stopped with an error` | The site stays in maintenance mode. Read the error above it. Either fix the cause, run `bash deploy.sh -e server` again and continue with steps 6 to 8 by hand (restart, test through the bypass URL, `php artisan up`), or roll back with the command the script printed (database restore allowed: nothing went live). |
|
||||
| `⊘ <file>: N new keys available (not applied)` or `not merged - ...` | `config:merge` did not change that file; it keeps working with the old settings. Run `php artisan config:merge <name> --dry-run` to see the keys, and add a reported key by hand from the `.example` file if needed. |
|
||||
| `✗ <file>: Merged config is invalid` | The merge checked its own result and restored the file. Nothing changed. Report the message to the developers. |
|
||||
| Restore fails with `Access denied ... DROP` | Add `DB_DEPLOY_USERNAME` and `DB_DEPLOY_PASSWORD` to `.env`, or restore by hand: `gzip -dc <backup>.sql.gz \| mysql -u root -p` |
|
||||
| The site still shows the maintenance page | Run `php artisan up` in the application root. |
|
||||
| `apt-get update`: `GPG error: https://packages.sury.org/php ... EXPKEYSIG` | The signing key of the Sury PHP repository expired: no PHP updates arrive and `apt-get install` stops. Install Sury's key package and point the source at it (backup first):<br>`cp -a /etc/apt/sources.list.d/php.list /root/php.list.bak-$(date +%F)`<br>`curl -fsSLo /tmp/sury-keyring.deb https://packages.sury.org/debsuryorg-archive-keyring.deb && dpkg -i /tmp/sury-keyring.deb`<br>`echo "deb [signed-by=/usr/share/keyrings/debsuryorg-archive-keyring.gpg] https://packages.sury.org/php/ $(lsb_release -sc) main" > /etc/apt/sources.list.d/php.list`<br>`apt-get update` |
|
||||
|
||||
All output of an upgrade and a rollback is logged in `storage/app/upgrades/<stamp>/` (`upgrade.log`,
|
||||
`rollback.log`), together with `state.env`. Send these files along when you ask for help.
|
||||
Reference in new issue
Block a user