Skip to content
prod e051e98
Browse

1 · Prerequisites

Objective — verify the local toolchain, then create the private GitHub repo, hosting sites, and databases (and wire passwordless SSH to both servers) so nothing later in the phase depends on infrastructure that isn’t there yet.

Two kinds of prerequisite gate this phase: tools on your machine and infrastructure in the cloud (repo, hosting, databases, SSH). Verify both before you git init — a missing PHP version or an unprovisioned database surfaces far more painfully three steps later.

Confirm versions before anything depends on them. CodeCanyon Laravel apps are typically pinned to a PHP/Composer range, and a mismatch fails at composer install (Phase 3), not here.

  1. Print every tool version in one pass.

    Terminal window
    echo "PHP: $(php -v 2>/dev/null | head -1 || echo 'NOT INSTALLED')"
    echo "Composer: $(composer -V 2>/dev/null | head -1 || echo 'NOT INSTALLED')"
    echo "Node: $(node -v 2>/dev/null || echo 'NOT INSTALLED')"
    echo "NPM: $(npm -v 2>/dev/null || echo 'NOT INSTALLED')"
    echo "Git: $(git --version 2>/dev/null || echo 'NOT INSTALLED')"
    echo "Herd: $(herd --version 2>/dev/null || echo 'NOT INSTALLED')"
    # Expected: a version line for each tool — no "NOT INSTALLED"
    • ✅ Each tool prints a version, not NOT INSTALLED.
  2. Install only what’s missing, matching the app’s supported range (reference table below).

    • ✅ Every Required tool is present and within the app’s supported range.
ToolMinimumRequired?If missing
PHP8.1Yesherd use php@8.3 or brew install php@8.3 — match composer.json require.php
Composer2.xYescomposer self-update (from 1.x), or the getcomposer.org installer
Node18Yesnvm install 20 && nvm use 20
NPM9Yesships with Node
Git2.xYesxcode-select --install
Herd (or Valet/Sail/XAMPP)anyYesdownload from herd.laravel.com
Atlas / DockeranyOptionalschema tooling only — free alternatives: mysqldump --no-data, TablePlus, DBeaver, php artisan migrate:status

Editor extensions are a machine-wide install, covered once — canonically — in Machine setup, including the editor-CLI guard and the single-PHP-LSP rule. The repo also commits that same set as .vscode/extensions.json (Create the project), so opening the folder prompts you to install anything missing — there is one canonical list, not a second one to drift.

If you skipped AI System setup, install the canonical set now (idempotent), then continue:

Terminal window
CODE="$(command -v code || command -v cursor)"
for ext in bmewburn.vscode-intelephense-client onecentlin.laravel-blade \
onecentlin.laravel5-snippets amiralizadeh9480.laravel-extra-intellisense \
editorconfig.editorconfig; do
"$CODE" --install-extension "$ext"
done
# Expected: each reports "already installed" or installs cleanly
  • ✅ The one canonical set is installed (PHP IntelliSense via Intelephense, Blade, snippets, Laravel IntelliSense, EditorConfig).

Skip this freely — none of it blocks setup; the terminal tools work regardless.

Provision the repo, hosting sites, and databases now so later steps have somewhere to push and run. Repo creation is agent-first (gh); site creation is agent-first when your host exposes an MCP server.

  1. Create the private, empty GitHub repo (default: gh CLI).

    Vendor code is licensed, not yours to publish — use Title Case for the repo name (Waraq, not waraq). The remote must stay empty (no README, .gitignore, or license) or your first push collides.

    Terminal window
    gh auth status # Expected: Logged in to github.com — if not, run gh auth login (Machine setup §1)
    gh repo create "<ORG>/Waraq" --private
    gh repo view "<ORG>/Waraq" --json sshUrl -q .sshUrl
    # Expected: git@github.com:<ORG>/Waraq.git — repo exists with zero commits/files
    • ✅ A private, completely empty repo exists and you have its SSH URL.
  2. Create the staging + production sites (default: hosting MCP when wired).

    Option 1 — 🤖 agent + hosting MCP (default when available). Use the MCP server for your provider (e.g. Hostinger MCP in Cursor/Claude global config — run mcp_auth first if tools return 401):

    1. List hosting orders / existing sites (hosting_listOrdersV1, hosting_listWebsitesV1) — confirm the MCP responds.
    2. Productionhosting_createWebsiteV1 with <DOMAIN> + the hosting plan order_id (and datacenter_code on the first site of a new plan).
    3. Staginghosting_createWebsiteSubdomainV1 with subdomain staging on that website (username, domain, subdomain).
    4. Enable/confirm SSL in the panel if the MCP does not auto-issue — Hostinger usually provisions Let’s Encrypt once DNS points at the account.
    Terminal window
    dig +short staging.<DOMAIN> A
    dig +short <DOMAIN> A
    curl -I "https://staging.<DOMAIN>"
    curl -I "https://<DOMAIN>"
    # Expected: both A records return the hosting IP; HTTPS responds 200 or 301
    • ✅ Both sites resolve over HTTPS; both IPs recorded.
  3. Create the databases. One empty DB + a user per environment (local / staging / production) with distinct 20+ char passwords; grant ALL PRIVILEGES; store creds in your password manager immediately.

    • ✅ Three empty databases exist, each with its own user/password saved to the vault.

A public repo of CodeCanyon source violates the license, and an initialized remote causes a non-fast-forward collision on your first push — so the repo must be both private and empty.

4. Configure SSH access (you → hosting, hosting → GitHub)

Section titled “4. Configure SSH access (you → hosting, hosting → GitHub)”

This section wires two separate SSH paths — not GitHub login on your laptop (that is gh auth login in Machine setup for repo creation above).

HopWho connects to whomWhy
A — Hosting SSHYour machine → staging + production serversDeploy, scp, ServerSync, and manual server work without passwords
B — GitHub SSH (on the server)Each server → git@github.comgit pull / Deployer on the host can reach the private repo

Steps 1–4 set up hop A (~/.ssh/config, ssh-copy-id). Step 5 verifies hop B (and adds a server-side deploy key in GitHub if needed). Repeat the block for production after staging.

Audit ~/.ssh/config first — a prior project’s host block may already point at the same IP.

  1. Check for, or generate, a key.

    Terminal window
    ls -la ~/.ssh/id_ed25519.pub 2>/dev/null \
    || ssh-keygen -t ed25519 -C "your-email@example.com" # Enter for default path
    # Expected: the .pub path prints, or a new ed25519 key pair is created
    • ~/.ssh/id_ed25519.pub exists.
  2. Audit ~/.ssh/config for existing host blocks before adding new ones — prior CodeCanyon projects often left reusable aliases on the same VPS or shared host.

    Terminal window
    test -f ~/.ssh/config || touch ~/.ssh/config && chmod 600 ~/.ssh/config
    grep -nE '^Host ' ~/.ssh/config
    grep -B1 -A6 -E '^Host ' ~/.ssh/config 2>/dev/null \
    | grep -E '^Host |HostName|User|Port|IdentityFile'
    # Match against the staging + production IPs you recorded in step 3.2
    grep -nE '<STAGING_IP>|<PRODUCTION_IP>' ~/.ssh/config 2>/dev/null || true
    # Expected: either no hits (add fresh blocks next) or a Host block already pointing at those IPs
    What you findAction
    Block matches this project’s IP, user, port, and keyReuse that Host name as <STAGING_SSH> / <PRODUCTION_SSH> in _CUSTOMIZATIONS.md and deploy config — do not duplicate the stanza.
    Alias exists, wrong IP (same server re-provisioned)Update HostName (and Port/User if needed) in place.
    Alias exists for another live projectAdd a project-scoped alias (e.g. waraq-staging) so both projects keep working.
    No matching blockProceed to the next step and add new entries.
    • ✅ You know whether to reuse, update, or create host aliases — and the chosen names are recorded for later steps.
  3. Add or update host entries in ~/.ssh/config (one per server, only when step 2 did not already cover them), then lock the file down.

    Host <STAGING_SSH>
    HostName <STAGING_IP>
    User <SSH_USER>
    Port <SSH_PORT>
    IdentityFile ~/.ssh/id_ed25519
    AddKeysToAgent yes
    Terminal window
    chmod 600 ~/.ssh/config
    # Expected: no output (permissions set)
    • ssh <STAGING_SSH> resolves the alias without a full host string.
  4. Copy your key to the server, then confirm it no longer prompts for a password.

    Terminal window
    ssh-copy-id -i ~/.ssh/id_ed25519.pub -p <SSH_PORT> <SSH_USER>@<STAGING_IP>
    ssh <STAGING_SSH> "echo 'Staging SSH OK' && php -v | head -1"
    # Expected: "Staging SSH OK" + a PHP version — and NO password prompt
    • ✅ The server responds without asking for a password.
  5. Verify the server can reach GitHub (needed for git pull on deploy).

    Terminal window
    ssh <STAGING_SSH> "ssh -T git@github.com 2>&1 | head -2"
    # Expected: "Hi <name>! You've successfully authenticated..."
    • ✅ GitHub authenticates. If it returns Permission denied, generate a server-side deploy key and have the user add only the printed public key in GitHub → Settings → SSH keys:

      Terminal window
      ssh <STAGING_SSH> 'test -f ~/.ssh/id_ed25519.pub || ssh-keygen -t ed25519 -f ~/.ssh/id_ed25519 -N "" -C "<project>-staging"'
      ssh <STAGING_SSH> 'cat ~/.ssh/id_ed25519.pub'
      # Expected: one ssh-ed25519 public key; the user adds it in GitHub -> Settings -> SSH keys

      Then re-run the ssh -T git@github.com check from the server.

Repeat for the production server.

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

  • 🤖 Toolchain verifiedphp, composer, node, git all report supported versions.
  • 🤖 Repo created — a private, empty GitHub repo exists (gh repo create or dashboard fallback) and you have its SSH URL.
  • 🤖 Sites reachable — staging + production both resolve over HTTPS, IPs recorded (hosting MCP default, or panel Option 2).
  • 👤 Databases created — empty local + staging + production DBs, creds in the password manager (distinct per env).
  • 🔀 SSH works both ways — hop A: passwordless from your machine to both servers; hop B: both servers can ssh -T git@github.com.