Complete guide for setting up and running the application locally.
| Tool | Purpose | Install |
|---|---|---|
| Multipass | VM manager (runs Ubuntu guests) | multipass.run |
| Innkeeper 3.2+ | Wrapper CLI for Multipass + Ansible | git.willettstech.com/tools/innkeeper |
| Docker | Runs MySQL on the host (recommended) | docker.com |
| SSH key pair | VM access and Ansible | ~/.ssh/id_rsa + id_rsa.pub |
| watchman (recommended) | File watcher for host→VM sync | brew install watchman |
git clone <repo-url> myapp
cd myappcp .innkeeper.env.example .innkeeper.env
cp config/app_local.example.php config/app_local.php
cp ansible/inventories/development/group_vars/all.yml.example ansible/inventories/development/group_vars/all.ymlReview .innkeeper.env — defaults are sensible for most setups. Update all.yml with your project name and settings.
innkeeper upOn first run, Innkeeper will:
- Create a Multipass VM
- Mount the project directory into the VM
- Rsync files to the runtime directory (
SHADOW_DEST) - Run the Ansible playbook (
ansible/playbooks/development.yml) to install PHP 8.4, Nginx, Node.js, Memcached, Mailpit, etc. - Start the file watcher (host→VM sync)
- Add local domain to
/etc/hosts
This takes several minutes the first time. Subsequent starts are fast.
See database.md for full details. The quick Docker approach:
docker run -d --name myapp-mysql \
-e MYSQL_ROOT_PASSWORD=secret \
-e MYSQL_DATABASE=myapp \
-e MYSQL_USER=myapp \
-e MYSQL_PASSWORD=myapp \
-p 3307:3306 mysql:8.4Then update config/app_local.php with the correct host IP (see database.md).
innkeeper exec composer install
innkeeper exec npm installImportant: Always install dependencies via
innkeeper exec, never directly on macOS. The VM has the correct PHP version, Node version, and Linux paths.
innkeeper exec gulpOpen the configured local domain in your browser. Accept the self-signed certificate warning. You should see the CakePHP default home page.
# Start of day — resume the VM
innkeeper up
# Edit files in VS Code on macOS (file watcher syncs to VM automatically)
# Run any command on the VM
innkeeper exec <command>
# After changing SCSS or JS
innkeeper exec gulp
# After changing database schema
innkeeper exec bin/cake migrations migrate
# Pull build artifacts from VM
innkeeper sync from-vm
# End of day
innkeeper suspendAfter changing Ansible playbooks or roles:
innkeeper provision # full playbook
innkeeper provision --tags nginx # just one role
innkeeper reload --provision # restart + provisioninnkeeper destroy --purge
innkeeper up
innkeeper exec composer install
innkeeper exec npm install
innkeeper exec gulp