Skip to content
prod e051e98
Browse

3 · Storage, symlinks & SSL

Objective — make the public directory serveable and give the project a secure local domain: create the storage symlink, detect and wire the app’s addon system (Modules vs packages vs addons), then link the project to Herd over HTTPS and prove the installer route is reachable.

Before the installer can run, the public directory needs its symlinks and the project needs a secure local domain. Addon systems differ — get the detection right and you avoid a whole class of “missing assets” bugs.

php artisan storage:link errors with “The [public/storage] link already exists” on re-runs — ugly, not fatal. Make it idempotent.

  1. Create the link only if it’s missing.

    Terminal window
    if [ -L public/storage ]; then
    echo "✅ public/storage symlink already exists"
    readlink public/storage # sanity-check the target
    else
    php artisan storage:link
    fi
    # Expected: either the existing target prints, or a fresh symlink is created
    • public/storage is a symlink and its target is verified.

CodeCanyon apps deliver addon assets in one of three ways. Detect which yours uses — the action differs.

  1. Probe for the four addon directory shapes.

    Terminal window
    [ -d Modules ] && echo "📦 Modules/ — nwidart/laravel-modules (copy-based, NO symlink)"
    [ -d packages ] && echo "📦 packages/ — in-tree packages (symlink required)"
    [ -d addons ] && echo "📦 addons/ — in-tree addons (symlink required)"
    [ -d uploads ] && echo "📦 uploads/ — root uploads dir (symlink required)"
    # Expected: a line per directory that exists — tells you which mechanism applies
    • ✅ The app’s addon mechanism is identified.
  2. Match it to the correct action.

    MechanismExample appsHow assets reach public/Action
    Symlink (packages/, uploads/, addons/)MagicAI, WorkDo, older CodeCanyon appspublic/packages → ../packages lets the server serve addon files directlyCreate the symlink (§3)
    Copy (Modules/ via nwidart/laravel-modules)ResiDoro, Worksuite, SocietyPro, Froiden appsphp artisan module:publish-assets copies into public/modules/<name>/No symlink — the installer (page 4) runs module:publish-assets. Re-run after manual module updates.
    Build output (Modules/*/public/ compiled)Newer modular appsVite builds module assets into public/build/No symlink — handled by npm run build (page 1)
    • ✅ The right action for this app’s mechanism is identified.

Run these only when §2 detected the directory and it’s a symlink-based system (not Modules/).

  1. Create the symlinks for whichever directories exist.

    Terminal window
    if [ -d packages ] && [ ! -L public/packages ]; then
    ln -s ../packages public/packages && echo "✅ public/packages → ../packages"
    fi
    if [ -d uploads ] && [ ! -L public/uploads ]; then
    ln -s ../uploads public/uploads && echo "✅ public/uploads → ../uploads"
    fi
    if [ -d addons ] && [ ! -L public/addons ]; then
    ln -s ../addons public/addons && echo "✅ public/addons → ../addons"
    fi
    # Expected: a ✅ line per symlink created (nothing for Modules/ apps)
    • ✅ Each required addon symlink exists (or nothing, correctly, for Modules/).
  2. Verify what exists before moving on.

    Terminal window
    ls -la public/ | grep "^l" || echo "(none — normal for Modules/ apps)"
    [ -d storage/app/public ] && echo "✅ storage/app/public" || echo "❌ MISSING"
    # Expected: the symlinks list + "✅ storage/app/public"
    • ✅ Symlinks and storage/app/public are confirmed present.
Section titled “4. Link the project to Herd and secure it with TLS”

Give the project a local .test domain and a trusted certificate, then prove both routes resolve.

  1. Link the project to Herd.

    Terminal window
    herd link [PROJECT_NAME]
    herd links | grep -i "[PROJECT_NAME]"
    # Expected: the project appears in the Herd links list
    • [PROJECT_NAME].test is registered with Herd.
  2. If the link is stale or wrong, remove and recreate it.

    Terminal window
    rm ~/Library/Application\ Support/Herd/config/valet/Sites/[PROJECT_NAME]
    herd link [PROJECT_NAME]
    # Expected: a fresh, correct link entry
    • ✅ The link points at the right project root.
  3. Secure it with TLS and restart Herd.

    Terminal window
    herd secure [PROJECT_NAME]
    herd restart
    # Expected: a certificate is issued and Herd reloads
    • ✅ HTTPS is enabled for [PROJECT_NAME].test.
  4. Confirm the cert exists and both routes resolve.

    Terminal window
    ls -la ~/Library/Application\ Support/Herd/config/valet/Certificates/ | grep -i "[PROJECT_NAME].test" \
    || echo "❌ No cert — re-run herd secure"
    curl -sI -o /dev/null -w "root: HTTP %{http_code} | TLS %{ssl_verify_result}\n" https://[PROJECT_NAME].test
    curl -sI -o /dev/null -w "install: HTTP %{http_code}\n" https://[PROJECT_NAME].test/install
    # Expected: a cert file listed; /install returns HTTP 200 (root 500 is acceptable here)
    • ✅ The cert file exists and /install returns HTTP 200.

The expected route states depend on whether the installer has run yet:

URLExpected (empty DB, first run)After installer (page 4)
https://[PROJECT_NAME].test (root)HTTP 500 acceptable — see below200 or 302 (redirect to login)
https://[PROJECT_NAME].test/installHTTP 200 — REQUIRED404 or 403 (blocked on page 6)

5. Confirm the installer page in a browser

Section titled “5. Confirm the installer page in a browser”

The curl check proves the route responds; only a human can confirm the certificate is trusted and the welcome page renders.

  1. Open the installer page and confirm the welcome screen + padlock. A cert warning means the TLS install failed; re-run herd secure and restart Herd.

    • ✅ The installer welcome page renders with a valid TLS padlock.

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

  • 🤖 Storage symlink presentpublic/storage linked and target verified.
  • 🤖 Addon system identified — Modules / packages / addons / uploads.
  • 🤖 Addon symlinks created — or correctly skipped for Modules/.
  • 🤖 Herd + TLS doneherd link + herd secure; cert file present.
  • 🔀 Routes verifiedcurl shows /install = HTTP 200; browser (👤) shows the welcome page with a valid padlock.