Sviluppo locale di Maho con Harbor
Avvia da zero un ambiente di sviluppo Maho completo con Harbor e scopri come usarlo ogni giorno: FrankenPHP, MySQL 8.4, Mailpit, cron, profili opzionali e personalizzazioni, tutto da un unico launcher Docker Compose.
Immagina un porto in cui la tua nave è già in acqua, equipaggiata e pronta a salpare. Non hai
montato banchine, gru o fari: li ha messi in piedi qualcun altro per te. Questo è Harbor, il
launcher Docker Compose e lo stack di sviluppo per Maho: un progetto open source di MageMEGA,
ispirato a Laravel Sail, usato in casa e donato alla community. Con un pugno di comandi costruisci
l’intero ambiente: l’app (FrankenPHP con Caddy e PHP), un database MySQL 8.4, Mailpit per le mail
in uscita e Ofelia per il cron. Il binario harbor fa da wrapper a docker compose, quindi non
devi mai scrivere a mano né il file compose né i comandi docker compose che ne derivano. Harbor
conosce il file generato, i profili e i nomi dei servizi al posto tuo e ti offre comandi brevi.
Concretamente:
# quello che dovresti digitare a mano ogni volta...
docker compose -f .harbor/compose.yaml exec app php ./maho cache:flush
docker compose -f .harbor/compose.yaml exec app bash
# ...diventa semplicemente
./vendor/bin/harbor maho cache:flush
./vendor/bin/harbor shell
⚓ Nota di bordo. Harbor è un porto, non il mare aperto. In produzione affonderebbe: il suo stesso README ne vieta l’uso. Qui siamo in rada, al sicuro, con la libertà di speronare tutto e ricostruire da zero quando serve.
Requisiti
Sulla macchina host servono:
- Docker con il plugin Compose v2 (Harbor preferisce
docker composee ripiega sudocker-compose). - PHP >= 8.3, solo per eseguire Composer con
create-projecterequire. Tutto il resto vive nel container, che monta PHP 8.4 di default.
Quick start: dallo zero allo store in funzione
1. Crea il progetto
Parti dallo starter ufficiale e aggiungi Harbor come dipendenza di sviluppo:
composer create-project mahocommerce/maho-starter my-store
cd my-store
composer require --dev empiricompany/harbor # oppure :dev-main per l'ultima versione
2. Inizializza e avvia lo stack
harbor init genera la cartella .harbor/ con i file del progetto: .env, compose.yaml,
docker.override.yaml e docker.install.yaml (questi ultimi due partono vuoti). Poi costruisci e
avvia lo stack. La prima build richiede dai 5 ai 20 minuti: il momento giusto per farsi un caffè,
non per premere Ctrl+C.
./vendor/bin/harbor init
./vendor/bin/harbor up -d --build
./vendor/bin/harbor ps
--build serve ogni volta che cambi il Dockerfile o le estensioni PHP dell’immagine. ps conferma
che i container siano attivi.
3. Installa le dipendenze e Maho
Installa le dipendenze PHP dentro il container dell’app, poi lancia l’installer di Maho:
./vendor/bin/harbor composer install
./vendor/bin/harbor maho install --license_agreement_accepted yes \
--locale it_IT --timezone Europe/Rome --default_currency EUR \
--db_host db --db_name maho --db_user maho --db_pass maho \
--url 'https://localhost:8443/' --use_secure 1 --secure_base_url 'https://localhost:8443/' \
--use_secure_admin 1 --admin_username admin --admin_password 'cambiami-forte' \
--sample_data 1
Una nota su --url: deve combaciare con l’URL configurato in Harbor. Se i due valori non
coincidono, Maho salva i base URL puntati altrove e ogni link generato si rompe.
4. Reindex, cache e primo accesso
Chiudi con un reindex e uno svuotamento della cache, poi apri lo store:
./vendor/bin/harbor maho index:reindex:all && ./vendor/bin/harbor maho cache:flush
./vendor/bin/harbor open admin
Lo storefront ora è su https://localhost:8443/ (HTTPS, con la CA interna di Caddy o un
certificato self-signed). harbor open apre nel browser l’admin o Mailpit (open mailpit). Per
accorciare i comandi puoi aggiungere un alias alla tua shell:
alias harbor='./vendor/bin/harbor'
Come si usa Harbor
Lancia harbor dalla root del progetto: i comandi girano nel container, quindi non devi installare
nulla dell’applicazione sulla tua macchina. harbor composer e harbor maho coprono quasi tutto
il lavoro quotidiano, e qualsiasi comando che Harbor non riconosce viene passato direttamente a
Docker Compose. In pratica non impari un nuovo strumento: parli al tuo Docker Compose, ma con un
maggiordomo che lo traduce.
Ciclo di vita e diagnostica
./vendor/bin/harbor up -d [--build] # avvia (e ricostruisce) lo stack
./vendor/bin/harbor ps # stato dei container
./vendor/bin/harbor logs -f app # log in streaming
./vendor/bin/harbor stop [servizio] # ferma
./vendor/bin/harbor restart [servizio] # riavvia
./vendor/bin/harbor down # ferma e rimuove container e reti
./vendor/bin/harbor config # mostra la configurazione Compose finale
./vendor/bin/harbor doctor # valida Docker, Compose e lo stack
down -v è distruttivo: rimuove anche i volumi, quindi il database viene azzerato. L’app
scrive sia l’access log di Caddy sia gli errori PHP su stdout/stderr, quindi tutto arriva in un
unico flusso con logs app.
⚓ Nota di bordo.
down -vè il tasto che affonda la nave con tutto l’equipaggio, database compreso. Prima di premerlo esporta un backup conharbor maho db:export: il porto si ricostruisce, i dati no.
Quando ti serve entrare nei container:
./vendor/bin/harbor shell # bash nel container app
./vendor/bin/harbor shell --service db # bash in un altro servizio
./vendor/bin/harbor root-shell # bash come root in app
./vendor/bin/harbor exec --service app php -v
./vendor/bin/harbor mysql maho --execute='SHOW TABLES'
./vendor/bin/harbor redis --raw ping
Per le query preferisci harbor maho db:query; harbor mysql è per il lavoro grezzo o
interattivo con il client.
Composer e la CLI di Maho
Composer passa attraverso Harbor con un passthrough completo (install, update, require,
remove e così via):
./vendor/bin/harbor composer update
./vendor/bin/harbor composer require vendor/package
harbor composer update reinstalla i package locali a path e ripubblica gli asset dei moduli
in public/. Se modifichi un file sotto il public/ di un package, rilancia composer update
per ripubblicarlo.
La CLI di Maho è harbor maho <comando> e legge le credenziali da app/etc/local.xml. I comandi
che userai di più:
migrate: applica gli aggiornamenti dichiarativi di schema e dati. Lancialo dopo aver installato un modulo o modificato i suoi script di setup.cache:flush: obbligatorio dopo aver rinominato blocchi, layout handle o alias di configurazione. La cache di layout e config sopravvive alle modifiche dei file e continua a servire XML vecchio.db:query "SELECT ...": il modo giusto per fare SQL, perché legge le credenziali dalocal.xml. Comodo per verificarecore_resourcee le personalizzazioni incore_config_data.config:get|set|delete <path>: leggi e scrivi i valori dicore_config_datarisolvendo per te gli scope. Preferiscili a SQL scritto a mano.db:export/db:import: dump e restore del database. Indica la compressione con--compression=gzip|zstde usa--drop-tablesper ricreare il database prima di importare.health-check,admin:user:*,shell,accessibility:scan: diagnostica, gestione degli admin, PHP shell con Maho avviato e scansione di accessibilità.
Un ciclo tipico per installare o aggiornare un modulo locale e verificarne il setup:
./vendor/bin/harbor composer update
./vendor/bin/harbor maho migrate
./vendor/bin/harbor maho db:query "SELECT * FROM core_resource WHERE code LIKE '%<alias>%'"
./vendor/bin/harbor maho cache:flush
Per riportare lo store a uno stato noto:
./vendor/bin/harbor maho db:export var/backups/backup.sql.gz --compression=gzip
./vendor/bin/harbor maho db:import var/backups/backup.sql.gz --compression=gzip --drop-tables
./vendor/bin/harbor maho cache:flush
Servizi opzionali e profili
Lo stack di base contiene quattro container: app, db, mailpit e cron. I servizi opzionali
si gestiscono con i profili, elencati in .harbor/.env.
Profili inclusi:
redis: server Redis suredis:6379(dall’host127.0.0.1:6379), con database separati per sessioni e cache.adminer: web UI suhttp://localhost:8082, con il serverdbgià precompilato.phpmyadmin: web UI suhttp://localhost:8081, con accesso automatico alle credenziali del database.cloudflaredecloudflared-quick: tunnel Cloudflare, descritti più avanti.
./vendor/bin/harbor services list
./vendor/bin/harbor services add phpmyadmin # oppure redis, adminer, cloudflared
./vendor/bin/harbor services add redis
./vendor/bin/harbor up -d # applica il cambio di profilo
./vendor/bin/harbor ps # verifica
services add e services remove aggiornano solo .harbor/.env: non avviano né fermano
container. È anche il meccanismo per personalizzare lo stack: dichiari un servizio con
profiles: [nome] in .harbor/docker.override.yaml e Harbor lo scopre e lo gestisce come i
profili inclusi. Se ometti del tutto la chiave profiles, il servizio entra nello stack di
default e parte a ogni up.
Mail, cron e tunnel
Mailpit è un servizio di base, sempre attivo: è un SMTP catch-all, quindi tutte le email dello
store restano in locale. La UI è su http://localhost:8025. Dall’host la porta SMTP è
localhost:1025, mentre le applicazioni nei container inviano a mailpit:1025. Mailpit non ha
autenticazione: non esporlo mai.
⚓ Nota di bordo. Mailpit intercetta ogni mail in uscita del porto: la trattiene invece di spedirla al mondo. Perfetto per testare conferme d’ordine e newsletter senza spammare clienti veri.
Il servizio cron esegue Ofelia, che pianifica i job di Maho attraverso label Docker. Va avviato
esplicitamente:
./vendor/bin/harbor cron
Due job sono definiti di default: maho-cron-always ogni minuto (cron:run always) e
maho-cron-default ogni cinque minuti (cron:run default), entrambi senza sovrapposizione. Se
non avvii Ofelia, i job di Maho restano a dormire. Per aggiungere job tuoi usa le label
ofelia.job-exec.<nome>.* in .harbor/docker.override.yaml, poi up -d per ricreare il servizio
e logs cron per controllare.
Se ti serve esporre lo store fuori dalla tua macchina senza aprire porte, Harbor ha i profili Cloudflare Tunnel:
./vendor/bin/harbor tunnel quick --autoconfig # URL effimero *.trycloudflare.com
./vendor/bin/harbor tunnel down --autoconfig # ripristina l'URL locale
--autoconfig punta i base URL di Maho all’URL pubblico e li ripristina alla chiusura.
Configurazione: cosa modificare e dove
Il file generato .harbor/compose.yaml non va mai modificato a mano. Le tue modifiche locali
vanno in .harbor/docker.override.yaml (oppure .harbor/docker.install.yaml), che Harbor unisce
a quelle generate.
Solo per cambiare i binding delle porte serve toccare gli stub in .harbor/stubs/: tienili
allineati con vendor/empiricompany/harbor/resources/stubs/ quando aggiorni Harbor.
Due ricette pratiche per iniziare.
Abilitare la developer mode
# .harbor/docker.override.yaml, unito sopra il compose.yaml generato
services:
app:
environment:
MAGE_IS_DEVELOPER_MODE: "1"
Applica la modifica con ./vendor/bin/harbor up -d: Maho passa in developer mode, con il logging
e la gestione degli errori più verbosi che servono mentre sviluppi.
Aggiungere un servizio allo stack
Nel file di override puoi dichiarare un servizio tu stesso. Con la chiave profiles diventa
opzionale e Harbor lo scopre e lo gestisce come i profili inclusi. L’esempio aggiunge
phpRedisAdmin, la web UI per Redis (richiede che anche il profilo redis sia attivo, per avere il
server a cui connettersi):
# .harbor/docker.override.yaml
services:
# phpRedisAdmin: web UI per Redis (profilo opzionale). Richiede il profilo
# "redis" attivo per avere il server Redis a cui connettersi.
phpredisadmin:
image: erikdubbelboer/phpredisadmin:latest
profiles: [phpredisadmin]
environment:
REDIS_1_HOST: "${HARBOR_REDIS_HOST:-redis}"
REDIS_1_PORT: "${HARBOR_REDIS_PORT:-6379}"
ports:
- "${HARBOR_PHPREDISADMIN_PORT:-8084}:80"
networks:
- harbor
Poi abilita i profili e avvia:
./vendor/bin/harbor services add redis
./vendor/bin/harbor services add phpredisadmin
./vendor/bin/harbor up -d
La UI è su http://localhost:8084. Se invece togli del tutto la chiave profiles, il servizio
entra nello stack di default e parte a ogni up.
Queste sono solo le basi. La guida completa, con tutti i comandi e le opzioni, è nel README di Harbor: https://github.com/empiricompany/harbor.
VS Code e Dev Container
Harbor genera la configurazione Dev Container con un solo comando:
./vendor/bin/harbor devcontainer --force
Scrive .devcontainer/devcontainer.json: punta a ../.harbor/compose.yaml, apre il servizio
app e usa /app come workspace. Con l’estensione Dev Containers di VS Code, quando apri il
progetto compare la richiesta di riaprire nel container. La configurazione installa anche
l’estensione Maho per VS Code.
Per far usare a quell’estensione il PHP del container, aggiungi in .vscode/settings.json:
{
"maho.phpCommand": "./vendor/bin/harbor php"
}
Così ogni comando PHP dell’estensione passa da Harbor e gira dove gira Maho, senza dover installare PHP sull’host.
Debug con Xdebug
Xdebug è già incluso nell’immagine dell’app: si accende da .harbor/.env.
HARBOR_XDEBUG_MODE=debug
Xdebug si ricollega all’IDE sulla porta 9003. Per verificare che sia attivo:
./vendor/bin/harbor php -m | grep -i '^xdebug$'
./vendor/bin/harbor php -i | grep -E 'xdebug.mode|xdebug.client'
In VS Code, con l’estensione PHP Debug, la configurazione di lancio mappa /app sulla root del
progetto:
{
"version": "0.2.0",
"configurations": [
{
"name": "Listen for Xdebug",
"type": "php",
"request": "launch",
"port": 9003,
"pathMappings": { "/app": "${workspaceFolder}" }
}
]
}
Avvia “Listen for Xdebug” (F5), metti un breakpoint e lancia
./vendor/bin/harbor debug script.php, oppure apri una pagina nel browser. Su un host remoto la
combinazione più pulita è VS Code Remote-SSH con harbor devcontainer --force: l’extension host
gira sul server e la porta 9003 è raggiungibile senza tunnel aggiuntivi.
Altre funzionalità di Harbor
-
MCP server di Maho: Harbor lo avvia su stdio, così i client AI compatibili possono dialogare con lo store. Nella configurazione del client:
{ "mcpServers": { "maho-stdio": { "command": "./vendor/bin/harbor", "args": ["maho", "dev:mcp:start"] } } } -
Scansione di accessibilità: installa il runtime Playwright una volta con
./vendor/bin/harbor maho accessibility:install, poi analizza una pagina con./vendor/bin/harbor maho accessibility:scan https://localhost:8443/. -
Strumenti di qualità:
./vendor/bin/harbor test,./vendor/bin/harbor phpunite./vendor/bin/harbor phpstangirano dentro il container, comeharbor phpeharbor bin. -
Apertura rapida:
./vendor/bin/harbor openapre la UI;open admineopen mailpitle pagine corrispondenti. -
Esperienza di sviluppo:
empiricompany/maho-ignitionaggiunge pagine d’errore illuminate, con eventuali soluzioni generate, ecomposer require intervention/image-driver-vipsabilita l’elaborazione immagini ad alte prestazioni. Entrambi sono opzionali.
Troubleshooting rapido
./vendor/bin/harbor config # verifica la configurazione Compose effettiva
./vendor/bin/harbor doctor # valida Docker, Compose e lo stack
./vendor/bin/harbor ps # controlla cosa sta girando
./vendor/bin/harbor logs app # errori PHP e access log di Caddy
./vendor/bin/harbor logs cron # job pianificati
Esegui sempre il launcher dalla cartella che contiene vendor/, .harbor/ e i file del progetto
Maho.
⚓ Ultima nota di bordo. Il porto è pronto e le banchine pure. Alza il braccio, dai corrente e lascia che Harbor si occupi della logistica: alle tue idee resta solo il mare da esplorare. Buon vento!
Nota di redazione.Testo preparato con l'aiuto dell'AI e verificato sulla fonte prima della pubblicazione. Può contenere errori: se ne trovi uno, segnalalo.Leggi il Manifesto
Il tuo negozio vende ancora?
Raccontaci da dove parti: ti rispondiamo con una prima valutazione, senza impegno.
Chiedi l'analisi del negozio