Skip to content
prod e051e98
Browse

4 · Installer + harden

Objective — install the app the CodeCanyon way (a web wizard, not artisan migrations): temporarily unblock /install, run the wizard against the staging DB, verify the app loads, then immediately re-block /install + /update and re-harden permissions — because you opened a writable, installable surface to the public web.

CodeCanyon apps install through a web wizard, not artisan migrations. Phase 3 blocked /install and /update for safety, so this page temporarily unblocks them, runs the wizard, then re-blocks and re-hardens. The harden step is not optional — you opened a writable, installable surface to the public web.

Phase 3 added .htaccess rules (and possibly a Cloudflare WAF rule) blocking /install, /update, and /upgrade-script. Comment them out so the wizard can load.

  1. Unblock the install routes and remove any stale lock.

    Terminal window
    # Is /install currently blocked?
    ssh <staging-alias> "grep 'RewriteRule ^install' ~/domains/staging.yourapp.com/deploy/current/public/.htaccess 2>/dev/null"
    # Comment out the blocking rules (idempotent — skip lines already commented)
    ssh <staging-alias> 'cd ~/domains/staging.yourapp.com/deploy/current/public && \
    grep -q "^RewriteRule ^install" .htaccess && \
    sed -i "s/^RewriteRule ^install/# RewriteRule ^install/" .htaccess; \
    grep -q "^RewriteRule ^update" .htaccess && \
    sed -i "s/^RewriteRule ^update/# RewriteRule ^update/" .htaccess; \
    grep -q "^RewriteRule ^upgrade-script" .htaccess && \
    sed -i "s/^RewriteRule ^upgrade-script/# RewriteRule ^upgrade-script/" .htaccess; \
    echo "install/update unblocked"'
    # Remove any stale install lock
    ssh <staging-alias> "rm -f ~/domains/staging.yourapp.com/deploy/shared/storage/installed 2>/dev/null && echo 'lock removed'"
    # Expected: "install/update unblocked" and "lock removed"
    • ✅ The blocking rules are commented out and any stale installed lock is removed.
  2. Confirm the wizard is reachable.

    Terminal window
    curl -sI https://staging.yourapp.com/install 2>&1 | head -1 # expect HTTP/2 200
    # Expected: HTTP/2 200
    • /install returns HTTP/2 200.

If you created a Cloudflare WAF rule in Phase 3, toggle it OFF now (👤): Cloudflare → Security → WAF → “Block install and update routes” → OFF.

The wizard is browser-only — an agent can’t click through it. Open https://staging.yourapp.com/install and walk the screens.

  1. Requirements — all checks green → Next. (Reds usually mean a missing PHP extension or a permission the page-3 chmod 777 should have fixed.)

    • ✅ Every requirement check is green.
  2. Database — Host localhost; database / username / password from .env.staging; Test Connection → Next.

    • ✅ Test Connection succeeds against the staging DB.
  3. Admin account — name, a staging admin email, and a strong password saved to your password manager now.

    • ✅ The admin account is created and its password is in the vault.
  4. Settings — app name (e.g. “Your App — Staging”), URL https://staging.yourapp.com.

    • ✅ App name and URL are set for staging.
  5. Install / Finish → confirm “Installation Complete”.

    • ✅ The wizard reports “Installation Complete”.

Use the table to recover from a wizard that won’t load or stalls:

Installer resultAction
Wizard loadsContinue
403 Forbidden.htaccess still blocking — re-run section 1
404Installer route missing — confirm the app ships one
500tail -50 …/deploy/current/storage/logs/laravel.log
504 Gateway TimeoutPHP timeout too low — confirm shared/.user.ini has max_execution_time = 300 (page 1, step 7), then retry
”Access Denied” mid-wizardStale cached config with old DB values — optimize:clear with the versioned PHP binary (page 3, step 2), then retry
”Already installed”Remove storage/installed (section 1)

Sign in and confirm the app is healthy after the wizard.

  1. Sign in at /login and walk the post-install checks.

    Visit https://staging.yourapp.com/login and sign in with the admin account.

    CheckPass
    Dashboard loads[ ]
    Navigation works[ ]
    No PHP errors[ ]
    CSS/JS loading[ ]
    SSL padlock shows[ ]
    • ✅ Admin login works and all five post-install checks pass.

The writable, installable surface must close as soon as the wizard finishes.

  1. Re-comment the blocking rules and confirm /install is forbidden.

    Terminal window
    ssh <staging-alias> 'cd ~/domains/staging.yourapp.com/deploy/current/public && \
    grep -q "^# RewriteRule ^install" .htaccess && \
    sed -i "s/^# RewriteRule ^install/RewriteRule ^install/" .htaccess; \
    grep -q "^# RewriteRule ^update" .htaccess && \
    sed -i "s/^# RewriteRule ^update/RewriteRule ^update/" .htaccess; \
    grep -q "^# RewriteRule ^upgrade-script" .htaccess && \
    sed -i "s/^# RewriteRule ^upgrade-script/RewriteRule ^upgrade-script/" .htaccess; \
    echo "install/update re-blocked"'
    curl -sI https://staging.yourapp.com/install 2>&1 | head -1 # expect HTTP/2 403
    # Expected: "install/update re-blocked" then HTTP/2 403
    • ✅ The rules are restored and /install returns HTTP/2 403.

Re-enable the Cloudflare WAF rule if you toggled it off (👤).

Walk back the temporary 777 from page 3 to least-privilege.

  1. Restore least-privilege on storage and .env.

    Terminal window
    # storage: dirs 775, files 664
    ssh <staging-alias> "cd ~/domains/staging.yourapp.com/deploy/shared/storage && \
    find . -type d -exec chmod 775 {} \; && find . -type f -exec chmod 664 {} \;"
    # .env: 640
    ssh <staging-alias> "chmod 640 ~/domains/staging.yourapp.com/deploy/shared/.env"
    # Expected: storage dirs 775 / files 664; .env 640
    • ✅ Storage dirs are 775, files 664, and .env is 640.

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

  • 👤 Wizard completed/install reachable (200), wizard completed, “Installation Complete” shown.
  • 👤 App verified — all five post-install checks pass; admin login works.
  • 🔀 Routes re-blocked/install re-blocked (403); Cloudflare WAF rule restored.
  • 🤖 Permissions re-hardened — storage dirs 775 / files 664; .env 640.