Installare e usare Magento con Docker e Docker Compose

Questa guida mostra un flusso pratico per avviare un ambiente Magento Open Source in locale usando Docker e Docker Compose, con servizi separati per web/PHP, database e caching, e con comandi ripetibili per installazione, aggiornamenti e operazioni quotidiane.

Obiettivi e approccio

  • Isolare dipendenze (PHP, estensioni, MySQL/MariaDB, Elasticsearch/OpenSearch, Redis) in container.
  • Persistenza dati tramite volumi Docker.
  • Riproducibilità: stesso stack per tutti gli sviluppatori, CI e ambienti di test.
  • Workflow: installazione, build static content, cache, indicizzazione, backup, troubleshooting.

Prerequisiti

  • Docker Engine e Docker Compose v2 (plugin) installati.
  • Git e un terminale.
  • Accesso a un repository Magento o a un progetto già inizializzato.
  • Credenziali per scaricare Magento via Composer (repo.magento.com): pubblica/privata (keys).

Struttura consigliata del progetto

Una struttura minimale e chiara aiuta a gestire configurazioni e persistenze.

mkdir -p magento-docker/{docker,magento}
cd magento-docker

Organizzazione tipica:

magento-docker/
  docker/
    php/
      Dockerfile
      php.ini
    nginx/
      default.conf
  magento/                  # codice sorgente Magento (bind mount)
  docker-compose.yml
  .env

File .env per variabili riusabili

Con Compose è comodo centralizzare porte, credenziali e hostname.

# .env
PROJECT_NAME=magento
HTTP_PORT=8080

DB_HOST=db
DB_NAME=magento
DB_USER=magento
DB_PASSWORD=magento
DB_ROOT_PASSWORD=root

REDIS_HOST=redis
ELASTIC_HOST=elasticsearch

# Utile per UID/GID se vuoi evitare problemi di permessi su Linux
APP_UID=1000
APP_GID=1000

Dockerfile PHP per Magento

Magento richiede estensioni PHP specifiche e Composer. La base dipende dalla versione di Magento; qui si mostra un esempio generico con PHP-FPM e pacchetti comuni. Adatta la versione PHP alla tua release Magento.

# docker/php/Dockerfile
FROM php:8.2-fpm

# Dipendenze di sistema e strumenti
RUN apt-get update && apt-get install -y --no-install-recommends \
    git unzip libzip-dev libpng-dev libjpeg-dev libfreetype6-dev \
    libicu-dev libxslt1-dev libonig-dev libxml2-dev \
    libcurl4-openssl-dev libreadline-dev \
    && rm -rf /var/lib/apt/lists/*

# Estensioni PHP richieste (set minimo comune)
RUN docker-php-ext-configure gd --with-freetype --with-jpeg \
    && docker-php-ext-install -j$(nproc) \
      bcmath intl pdo_mysql soap xsl zip gd opcache sockets

# Composer
COPY --from=composer:2 /usr/bin/composer /usr/bin/composer

# Config PHP
COPY php.ini /usr/local/etc/php/conf.d/zz-magento.ini

WORKDIR /var/www/html

Esempio di file ini (valori tipici per sviluppo):

; docker/php/php.ini
memory_limit = 2G
max_execution_time = 1800
upload_max_filesize = 64M
post_max_size = 64M
date.timezone = Europe/Rome

; OpCache (sviluppo: spesso meglio disattivare o rendere "soft")
opcache.enable=1
opcache.validate_timestamps=1
opcache.revalidate_freq=0

Configurazione Nginx

Nginx espone l'app su una porta locale e inoltra le richieste PHP a PHP-FPM. Il document root deve puntare alla cartella pub/ di Magento.

# docker/nginx/default.conf
server {
  listen 80;
  server_name localhost;
  root /var/www/html/pub;
  index index.php;

  # Magento: regole base
  location / {
    try_files $uri $uri/ /index.php?$args;
  }

  location ~ \.php$ {
    try_files $uri =404;
    include fastcgi_params;
    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    fastcgi_pass php:9000;
    fastcgi_read_timeout 1800;
  }

  # Statici
  location ~* \.(jpg|jpeg|gif|png|css|js|ico|svg|woff|woff2|ttf)$ {
    expires 1d;
    access_log off;
    try_files $uri $uri/ /index.php?$args;
  }

  client_max_body_size 64M;
}

docker-compose.yml: stack di base

Lo stack seguente include:

  • nginx come web server
  • php come runtime applicativo (PHP-FPM + Composer)
  • db (MariaDB) per persistenza dati
  • redis per cache/sessioni
  • elasticsearch per catalog search (o sostituiscilo con OpenSearch se richiesto dalla tua versione)
# docker-compose.yml
services:
  nginx:
    image: nginx:1.27-alpine
    depends_on:
      - php
    ports:
      - "${HTTP_PORT}:80"
    volumes:
      - ./magento:/var/www/html:delegated
      - ./docker/nginx/default.conf:/etc/nginx/conf.d/default.conf:ro

  php:
    build:
      context: ./docker/php
    volumes:
      - ./magento:/var/www/html:delegated
    environment:
      - PHP_MEMORY_LIMIT=2G

  db:
    image: mariadb:10.6
    command: --max_allowed_packet=64M
    environment:
      - MARIADB_ROOT_PASSWORD=${DB_ROOT_PASSWORD}
      - MARIADB_DATABASE=${DB_NAME}
      - MARIADB_USER=${DB_USER}
      - MARIADB_PASSWORD=${DB_PASSWORD}
    volumes:
      - dbdata:/var/lib/mysql

  redis:
    image: redis:7-alpine
    volumes:
      - redisdata:/data

  elasticsearch:
    image: docker.elastic.co/elasticsearch/elasticsearch:7.17.22
    environment:
      - discovery.type=single-node
      - xpack.security.enabled=false
      - ES_JAVA_OPTS=-Xms1g -Xmx1g
    volumes:
      - esdata:/usr/share/elasticsearch/data

volumes:
  dbdata:
  redisdata:
  esdata:

Note pratiche:

  • Le versioni dei container (MariaDB/Elasticsearch/PHP) vanno allineate alla tua versione Magento.
  • Se sei su macOS/Windows, i bind mount possono essere più lenti. Valuta opzioni come delegated o soluzioni di sync.
  • Elasticsearch richiede spesso aumentare memoria/limiti del sistema (es. vm.max_map_count su Linux).

Avvio dello stack

docker compose up -d --build
docker compose ps

Verifica log in caso di problemi:

docker compose logs -f --tail=200 nginx
docker compose logs -f --tail=200 php
docker compose logs -f --tail=200 db

Ottenere il codice Magento nel volume bind

Hai due strade comuni:

  1. Progetto già esistente: clona nel path ./magento.
  2. Nuova installazione via Composer: crea il progetto dentro ./magento.

Opzione A: clonare un repository

git clone <repo> magento

Opzione B: creare un nuovo progetto Magento con Composer

Se usi Composer dal container PHP, non installi nulla sul sistema host. Prima configura le chiavi Magento (una sola volta):

docker compose exec php composer config --global http-basic.repo.magento.com <PUBLIC_KEY> <PRIVATE_KEY>

Poi crea il progetto (adatta il package alla versione desiderata):

docker compose exec php bash -lc "composer create-project --repository=https://repo.magento.com/ magento/project-community-edition /var/www/html"

Se la cartella magento/ è vuota e montata su /var/www/html, il comando popolerà direttamente la directory sul tuo host.

Permessi file e utenti: evitare attriti

Magento scrive in var/, generated/, pub/static/ e app/etc. In sviluppo, un approccio comune è far girare PHP come utente che corrisponde al tuo UID/GID, oppure applicare permessi coerenti.

Esempio rapido (sviluppo):

docker compose exec php bash -lc "chown -R www-data:www-data var generated pub/static pub/media app/etc || true"
docker compose exec php bash -lc "find var generated pub/static pub/media app/etc -type d -exec chmod 775 {} \; || true"
docker compose exec php bash -lc "find var generated pub/static pub/media app/etc -type f -exec chmod 664 {} \; || true"

In ambienti di team su Linux conviene allineare UID/GID nel Dockerfile o via entrypoint, ma in locale questa soluzione spesso è sufficiente.

Installazione di Magento via CLI

Magento si installa tipicamente usando bin/magento setup:install. Ecco un esempio completo che usa i servizi del Compose.

docker compose exec php bash -lc "php -d memory_limit=-1 bin/magento setup:install   --base-url=http://localhost:${HTTP_PORT}/   --db-host=${DB_HOST}   --db-name=${DB_NAME}   --db-user=${DB_USER}   --db-password=${DB_PASSWORD}   --admin-firstname=Admin   --admin-lastname=User   --admin-email=admin@example.com   --admin-user=admin   --admin-password='Admin12345!'   --backend-frontname=admin   --language=it_IT   --currency=EUR   --timezone=Europe/Rome   --use-rewrites=1   --search-engine=elasticsearch7   --elasticsearch-host=${ELASTIC_HOST}   --elasticsearch-port=9200   --session-save=redis   --session-save-redis-host=${REDIS_HOST}   --cache-backend=redis   --cache-backend-redis-server=${REDIS_HOST}   --cache-backend-redis-db=0"

Se la tua versione usa OpenSearch o un motore differente, cambia i flag relativi al search engine in base alla documentazione della tua release.

Post-install: comandi tipici di build

Dopo l'installazione, in sviluppo spesso conviene usare la modalità developer e rigenerare cache e contenuti statici quando necessario.

docker compose exec php bash -lc "bin/magento deploy:mode:set developer"
docker compose exec php bash -lc "bin/magento cache:flush"
docker compose exec php bash -lc "bin/magento indexer:reindex"

Per ambienti simili a staging/produzione (più lenti ma più fedeli):

docker compose exec php bash -lc "bin/magento deploy:mode:set production"
docker compose exec php bash -lc "bin/magento setup:di:compile"
docker compose exec php bash -lc "bin/magento setup:static-content:deploy -f it_IT en_US"
docker compose exec php bash -lc "bin/magento cache:flush"

Configurare host e URL

Con la compose sopra, Magento è raggiungibile su http://localhost:8080 (o la porta impostata). Se devi aggiornare base URL e secure URL:

docker compose exec php bash -lc "bin/magento config:set web/unsecure/base_url http://localhost:${HTTP_PORT}/"
docker compose exec php bash -lc "bin/magento config:set web/secure/base_url http://localhost:${HTTP_PORT}/"
docker compose exec php bash -lc "bin/magento cache:flush"

Workflow quotidiano con Docker Compose

Entrare nel container PHP

docker compose exec php bash

Eseguire comandi Magento

docker compose exec php bin/magento cache:status
docker compose exec php bin/magento cache:flush
docker compose exec php bin/magento indexer:status
docker compose exec php bin/magento indexer:reindex

Gestire Composer dipendenze

docker compose exec php composer install
docker compose exec php composer update vendor/package

Abilitare/disabilitare moduli

docker compose exec php bin/magento module:status
docker compose exec php bin/magento module:enable Vendor_Module
docker compose exec php bin/magento module:disable Vendor_Module
docker compose exec php bin/magento setup:upgrade
docker compose exec php bin/magento cache:flush

Import/export database e backup

Per fare un dump dal container DB verso il tuo host:

docker compose exec db bash -lc "mysqldump -uroot -p${DB_ROOT_PASSWORD} ${DB_NAME} > /tmp/db.sql"
docker cp $(docker compose ps -q db):/tmp/db.sql ./db.sql

Ripristino:

docker cp ./db.sql $(docker compose ps -q db):/tmp/db.sql
docker compose exec db bash -lc "mysql -uroot -p${DB_ROOT_PASSWORD} ${DB_NAME} < /tmp/db.sql"

Ottimizzazioni utili

Mailcatcher/Mailpit per email in locale

Per testare l'invio email senza spedire davvero, aggiungi un servizio come Mailpit e configura Magento/SMTP di conseguenza.

# Esempio (aggiunta a docker-compose.yml)
  mailpit:
    image: axllent/mailpit:latest
    ports:
      - "8025:8025"   # UI
      - "1025:1025"   # SMTP

Varnish (opzionale)

Magento supporta Varnish come full-page cache. In sviluppo è spesso superfluo, ma può essere utile per test più realistici. Integrare Varnish richiede configurazione aggiuntiva (porte, backends, export della VCL da Magento).

Modalità developer e symlink statici

In developer mode, molte risorse vengono gestite in modo più dinamico, riducendo la necessità di deploy statico ad ogni modifica. Se lavori spesso su frontend, questo migliora la velocità del ciclo modifica-verifica.

Troubleshooting: problemi comuni e soluzioni

Elasticsearch non parte o va in crash

  • Su Linux, verifica vm.max_map_count (spesso deve essere almeno 262144).
  • Aumenta ES_JAVA_OPTS se hai dataset grandi; riducilo se hai poca RAM.
  • Controlla i log: docker compose logs -f elasticsearch.

Errori 502/504 su Nginx

  • PHP-FPM non risponde: controlla docker compose logs -f php.
  • Timeout durante install/compile: aumenta fastcgi_read_timeout e max_execution_time.
  • Permessi: Magento può bloccarsi se non riesce a scrivere in var/ e generated/.

Schermata bianca o assets mancanti

  • Pulisci cache e static content: bin/magento cache:flush.
  • In produzione, riesegui: setup:static-content:deploy.
  • Verifica che il document root sia pub/ e che Nginx serva correttamente gli statici.

Problemi di performance su macOS/Windows

  • Riduci il numero di bind mount, usa volumi per vendor/ o caching dove possibile.
  • Abilita caching Composer e usa composer install con cache persistente.
  • Considera un filesystem di sync (a seconda della tua toolchain) per migliorare I/O.

Comandi rapidi di riferimento

# Build e avvio
docker compose up -d --build

# Stop e rimozione container (conserva volumi)
docker compose down

# Stop e rimozione anche dei volumi (ATTENZIONE: elimina DB e dati ES/Redis)
docker compose down -v

# Logs
docker compose logs -f --tail=200

# Magento CLI
docker compose exec php bin/magento cache:flush
docker compose exec php bin/magento indexer:reindex

Conclusione

Con Docker e Docker Compose puoi ottenere un ambiente Magento ripetibile e controllato, riducendo drasticamente i problemi legati a versioni di PHP/servizi e rendendo più lineare il lavoro in team. La chiave è allineare le versioni dei servizi alla tua release Magento, mantenere volumi per la persistenza e trasformare le operazioni comuni (install, upgrade, compile, deploy) in comandi standardizzati eseguibili dal container PHP.

Torna su