4 · Run the installer
Objective — run the vendor’s web wizard without a 504 mid-migration: raise the PHP-FPM and nginx timeouts, pre-flight four preconditions, complete the installer in the browser, then capture the admin credentials safely.
Background
Section titled “Background”The web installer creates the admin account, runs every migration, and seeds demo data. The single biggest failure mode is a 504 mid-migration that leaves a partial schema and no install marker — so raise the timeouts and pre-flight before you touch the browser.
1. Raise the PHP-FPM timeout
Section titled “1. Raise the PHP-FPM timeout”The installer runs in the web SAPI, where PHP defaults to a 60-second limit. Set .user.ini (read by PHP-FPM on every request).
-
Write the raised limits to
public/.user.ini(PHP-FPM reads it from the document root, not the repo root).Terminal window cat > public/.user.ini <<'EOF'max_execution_time = 300memory_limit = 512Mpost_max_size = 100Mupload_max_filesize = 100MEOF# Expected: public/.user.ini exists with the four keys- ✅
public/.user.inicarries the four raised values.
- ✅
-
Verify the CLI side is unlimited so terminal migrations never time out.
Terminal window php -r "echo 'CLI max_execution_time=' . ini_get('max_execution_time') . PHP_EOL;"# Expected: CLI max_execution_time=0- ✅ CLI
max_execution_timeis0(unlimited).
- ✅ CLI
The post_max_size / upload_max_filesize bumps are a bonus — CodeCanyon admin panels often accept logos, PDFs, and media larger than PHP’s 8 MB default.
2. Raise the nginx timeout too
Section titled “2. Raise the nginx timeout too”nginx has its own 60s fastcgi_read_timeout. You need both — nginx times out waiting for FPM, FPM times out executing the script. Raising only one leaves the other as the bottleneck.
-
Patch the Herd nginx config and restart.
Terminal window NGINX_CONF=~/Library/Application\ Support/Herd/config/valet/Nginx/[PROJECT_NAME].testgrep -q 'fastcgi_read_timeout' "$NGINX_CONF" 2>/dev/null || \sed -i '' 's/fastcgi_pass \$herd_sock;/fastcgi_pass $herd_sock;\n fastcgi_read_timeout 300;/' \"$NGINX_CONF"herd restart# Expected: fastcgi_read_timeout 300 now present; Herd reloads- ✅ nginx
fastcgi_read_timeoutis300and Herd has restarted.
- ✅ nginx
3. Detect installation status
Section titled “3. Detect installation status”Probe the users table, not settings — many apps fragment settings across a dozen tables (global_settings, email_settings, …), which gives false negatives. users is universal.
-
Check the marker and the
userstable.Terminal window ls storage/installed 2>/dev/null && echo "marker: ✅" || echo "marker: ❌ missing"php artisan tinker --execute="echo Schema::hasTable('users') ? 'users: ✅' : 'users: ❌ empty DB';"# Expected: both lines print the marker + users-table state- ✅ The current install state is clear from the marker +
userstable.
- ✅ The current install state is clear from the marker +
-
Map the state to its action.
storage/installeduserstableAction Missing ❌ empty Run the installer (§5) Missing ✅ present Installer finished but timed out before the marker — touch storage/installed, skip to page 5Exists ✅ present Already installed — skip to page 5 Exists ❌ empty Corrupted — rm storage/installedand re-run the installer- ✅ The correct next action is chosen.
-
Confirm the installer route prefix — most apps use
/install; some use/installeror/setup.Terminal window grep -rn "prefix.*install" routes/ app/ vendor/ --include="*.php" 2>/dev/null | head -1 || echo "Check vendor docs"# Expected: a route prefix line, or the "Check vendor docs" fallback- ✅ The installer route prefix is known.
4. Pre-flight check
Section titled “4. Pre-flight check”Run this before opening the wizard — it confirms all four preconditions at once. If any check fails, fix it before proceeding — this is what prevents the 504-mid-migration disaster.
-
Run the four-in-one pre-flight.
Terminal window DB_NAME=$(grep DB_DATABASE .env | cut -d= -f2)TABLES=$(mysql -h 127.0.0.1 -u root -N -e "SELECT COUNT(*) FROM information_schema.tables WHERE table_schema='${DB_NAME}';" 2>/dev/null)[ -n "$TABLES" ] && echo "✅ DB ${DB_NAME} reachable (${TABLES} tables)" || echo "❌ DB NOT reachable"[ ! -f storage/installed ] && echo "✅ marker absent" || echo "❌ marker EXISTS — rm storage/installed"INSTALL_STATUS=$(curl -sI -o /dev/null -w "%{http_code}" https://[PROJECT_NAME].test/install 2>/dev/null)[ "$INSTALL_STATUS" = "200" ] && echo "✅ /install HTTP 200" || echo "❌ /install HTTP ${INSTALL_STATUS} — fix page 3"MAX_EXEC=$(grep -oE 'max_execution_time\s*=\s*[0-9]+' public/.user.ini 2>/dev/null | grep -oE '[0-9]+$')[ -n "$MAX_EXEC" ] && [ "$MAX_EXEC" -ge 300 ] && echo "✅ max_execution_time=${MAX_EXEC}" || echo "❌ re-run §1"# Expected: 4× ✅- ✅ All four checks print ✅ before the wizard opens.
5. Complete the wizard
Section titled “5. Complete the wizard”The web installer is a clicked-through flow that creates the admin account and runs every migration — a person drives it in the browser.
-
Work through each installer step.
Step What to enter Requirements All green (red = install the missing PHP extension) Permissions All green (red = fix folder permissions) Database Host 127.0.0.1, Port3306, DB[PROJECT_NAME]_local, Userroot, Pass (empty or yours)Admin account See the credential-choice note below App settings App name, URL https://[PROJECT_NAME].testFinish Wait — expect 30–120s for 100+ migrations under the 300s timeout - ✅ The wizard reaches its finish screen without an error.
Whichever credentials you choose, the one thing never to do mid-wizard is panic-retry:
6. Verify the install completed
Section titled “6. Verify the install completed”With the wizard finished, prove the marker, users, and log are all healthy from the terminal.
-
Confirm the marker, the user count, and a clean log.
Terminal window ls -la storage/installed 2>/dev/null && echo "Installed" || touch storage/installedphp artisan tinker --execute="echo 'Users: ' . App\Models\User::count();"tail -20 storage/logs/laravel.log 2>/dev/null | grep -i "error\|exception" || echo "No errors"# Expected: marker present, Users > 0, "No errors"- ✅ Marker present,
User::count()> 0, and no errors in the log tail.
- ✅ Marker present,
7. Capture credentials — immediately
Section titled “7. Capture credentials — immediately”Default credentials like 123456 are the #1 security risk for CodeCanyon apps. If the finish screen didn’t show them, find them.
-
Locate the admin credentials.
Terminal window grep -riE "admin|password|default.*user" Admin-Local/2-Docs/1-VendorDocs/ 2>/dev/null | head -10mysql -h 127.0.0.1 -u root -e "USE $(grep DB_DATABASE .env | cut -d= -f2); SELECT id, name, email, type FROM users LIMIT 10;"# Expected: the admin email surfaces from vendor docs or the users table- ✅ The admin email (and the default password, if applicable) is in hand.
-
Store them in a vault — never echo or
cata stored credential.Terminal window op item create --category login --title "superadmin" --vault "[PROJECT_NAME]-Local" \--url "https://[PROJECT_NAME].test/admin" --tags "admin,default-change-me" \"username=[ADMIN_EMAIL]" "password=[ADMIN_PASSWORD]"# Expected: the item is created in 1Password (no value printed to the terminal)- ✅ Credentials live in 1Password (or the gitignored
credentials.md), taggeddefault-change-me.
- ✅ Credentials live in 1Password (or the gitignored
Checklist
Section titled “Checklist”Do not mark this step done until every box below is checked.
- 🤖 Timeouts raised —
public/.user.iniand nginxfastcgi_read_timeoutboth = 300s. - 🤖 Pre-flight green — the check shows 4× ✅.
- 👤 Wizard complete —
storage/installedmarker present after the browser flow. - 🤖 Install verified —
User::count()> 0 and no errors inlaravel.log. - 🤖 Credentials stored — in 1Password /
credentials.mdand flagged for Phase 6 rotation.