1. Prerequisiti e installazione Podman
Installare Podman su Windows 11
Scarica e installa Podman per Windows dall'indirizzo ufficiale:
https://podman.io/
Scarica il file .exe dell'ultima versione stabile (es. podman-v5.x.x-setup.exe) ed eseguilo.
Inizializzare la Podman Machine
Podman su Windows utilizza una macchina virtuale Linux in background. Inizializzala con risorse adeguate allo sviluppo:
podman machine init --memory 4096
Viene creata una macchina virtuale con nome podman-machine-default. Volendo posso anche dare un nome alla macchina usando il comando podman machine init nome-macchina
Per avviare e fermare la macchina usa questi comandi
podman machine start
podman machine stop
I container possono girare in due modalità
- Rootless: I container girano senza privilegi di root
- Rootful: I container girano come root dentro la VM
Se voglio far girare la macchine con privilegi di root lanciare il seguente comando e poi fermare e riavviare la macchina
podman machine set --rootful podman machine stop podman machine start
Per vedere la macchina virtuale installata
podman machine list
Nel caso in cui desideri cancellare e ricreare la macchina usa
podman machine rm
Verifica che tutto funzioni:
podman version
podman info
Per vedere la macchina installa con wsl lanciare il seguente comando
wsl -l -v
Installare podman-compose
podman-compose permette di orchestrare più container tramite un file compose.yaml, ed è l'equivalente di docker-compose per Podman.
pip install podman-compose
Se non hai Python installato, scaricalo da https://python.org e assicurati di aggiungere Python al PATH durante l'installazione.
2. Struttura del progetto
Crea questa struttura di cartelle. La cartella D:\temp\wamp-podman contiene tutta la configurazione dei container. I tuoi siti web risiedono nella sottocartella www e vengono montati nel container senza essere copiati al suo interno.
D:\temp\wamp-podman\
│
├── .env ← tutte le variabili configurabili qui
├── compose.yaml ← orchestrazione dei container
│
├── php-apache\
│ ├── Dockerfile ← immagine custom PHP 8.5.4-fpm + Apache
│ ├── apache\
│ │ ├── vhosts.conf ← configurazione virtual host Apache
│ │ └── start.sh ← script di avvio PHP-FPM + Apache
│ └── php\
│ ├── custom.ini ← impostazioni PHP aggiuntive
│ ├── xdebug.ini ← configurazione Xdebug
│ └── fpm-pool.conf ← configurazione pool PHP-FPM
│
└── www\ ← i tuoi siti (solo montata nel container)
├── sito1\
├── sito2\
└── ...
3. File di configurazione centrale .env
Questo è il punto unico dove modificare tutte le variabili dell'ambiente. Non dovrai mai toccare altri file per cambiare porte, credenziali o percorsi.
Percorso: D:\temp\wamp-podman\.env
# ─────────────────────────────────────────────
# PERCORSI
# ─────────────────────────────────────────────
# Percorso della cartella che contiene i tuoi siti web.
# Usa la sintassi con slash (/).
SITES_ROOT=D:/temp/wamp-podman/www
# ─────────────────────────────────────────────
# PORTE HOST
# ─────────────────────────────────────────────
# Porta su cui Apache risponde su Windows (http://localhost:APACHE_PORT)
APACHE_PORT=8080
# Porta interna del container su cui Apache ascolta
# Per wordpress tenere allineato questo valore con APACHE_PORT
APACHE_INTERNAL_PORT=8080
# Porta su cui phpMyAdmin è raggiungibile da Windows
PHPMYADMIN_PORT=8081
# Porta interna del container su cui phpMyAdmin ascolta
PHPMYADMIN_INTERNAL_PORT=80
# Porta per MariaDB (utile per client esterni come DBeaver)
MARIADB_PORT=3306
# ─────────────────────────────────────────────
# MARIADB
# ─────────────────────────────────────────────
MARIADB_ROOT_PASSWORD=root
# ─────────────────────────────────────────────
# XDEBUG
# ─────────────────────────────────────────────
# Porta su cui VSCode ascolta per le connessioni Xdebug
XDEBUG_PORT=9003
# ─────────────────────────────────────────────
# NOMI CONTAINER
# ─────────────────────────────────────────────
COMPOSE_PROJECT_NAME=devenv
4. Dockerfile per PHP-FPM + Apache
Questo Dockerfile usa come base php:8.5.4-fpm, che include PHP-FPM ma non un web server.
Apache viene installato tramite apt-get e configurato per comunicare con PHP-FPM
tramite FastCGI usando il modulo mod_proxy_fcgi.
PHP-FPM ascolta su socket Unix per prestazioni migliori rispetto a TCP.
Percorso: D:\temp\wamp-podman\php-apache\Dockerfile
FROM php:8.5.4-fpm
RUN apt-get update
RUN apt-get install -y apache2 libapache2-mod-fcgid
RUN apt-get install -y libzip-dev libpng-dev libjpeg62-turbo-dev libwebp-dev libfreetype6-dev libonig-dev libxml2-dev libcurl4-openssl-dev libssl-dev libmagickwand-dev libicu-dev libxslt1-dev libsqlite3-dev unzip curl git nano
RUN docker-php-ext-configure gd --with-freetype --with-jpeg --with-webp && docker-php-ext-install gd
RUN docker-php-ext-install bcmath calendar exif gettext
RUN docker-php-ext-install intl mbstring mysqli
RUN docker-php-ext-install pcntl pdo pdo_mysql pdo_sqlite
RUN docker-php-ext-install soap sockets xsl zip
RUN pecl install imagick
RUN docker-php-ext-enable imagick
RUN pecl install redis
RUN docker-php-ext-enable redis
RUN pecl install xdebug
RUN docker-php-ext-enable xdebug
COPY --from=composer:latest /usr/bin/composer /usr/bin/composer
# proxy_fcgi permette ad Apache di passare le richieste PHP a PHP-FPM via FastCGI
# setenvif è richiesto da proxy_fcgi
RUN a2enmod proxy_fcgi setenvif rewrite headers expires deflate ssl vhost_alias
COPY apache/vhosts.conf /etc/apache2/sites-available/000-default.conf
COPY php/custom.ini /usr/local/etc/php/conf.d/custom.ini
COPY php/xdebug.ini /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini
COPY php/fpm-pool.conf /usr/local/etc/php-fpm.d/www.conf
COPY apache/start.sh /usr/local/bin/start.sh
RUN chmod +x /usr/local/bin/start.sh
RUN usermod -u 1000 www-data
RUN groupmod -g 1000 www-data
WORKDIR /var/www/html
EXPOSE 80
CMD ["/usr/local/bin/start.sh"]
Script di avvio
Poiché il container deve eseguire sia PHP-FPM che Apache, serve uno script che li avvii entrambi.
L'immagine base php:8.5.4-fpm ha come CMD predefinito solo php-fpm:
lo script lo sostituisce avviando entrambi i processi.
Percorso: D:\temp\wamp-podman\php-apache\apache\start.sh
#!/bin/bash
export APACHE_LOG_DIR=/var/log/apache2
export APACHE_RUN_DIR=/var/run/apache2
export APACHE_RUN_USER=www-data
export APACHE_RUN_GROUP=www-data
export APACHE_LOCK_DIR=/var/lock/apache2
export APACHE_PID_FILE=/var/run/apache2/apache2.pid
# Porta dinamica da variabile d'ambiente, default 80 se non impostata
APACHE_INTERNAL_PORT=${APACHE_INTERNAL_PORT:-80}
# Imposta la porta di ascolto
echo "Listen ${APACHE_INTERNAL_PORT}" > /etc/apache2/ports.conf
# Sostituisce la porta nei VirtualHost
sed -i "s/\*:APACHE_PORT/\*:${APACHE_INTERNAL_PORT}/g" /etc/apache2/sites-available/000-default.conf
mkdir -p /var/run/php
chown www-data:www-data /var/run/php
php-fpm &
apache2ctl -D FOREGROUND
5. Configurazione Apache
Apache riceve le richieste HTTP e passa quelle PHP a PHP-FPM tramite FastCGI
usando la direttiva SetHandler proxy:unix.
Il socket Unix /var/run/php/php-fpm.sock è il canale di comunicazione
tra Apache e PHP-FPM all'interno del container.
Percorso: D:\temp\wamp-podman\php-apache\apache\vhosts.conf
# ─── Virtual Host di default ─────────
<VirtualHost *:APACHE_PORT>
ServerName localhost
DocumentRoot /var/www/html
<Directory /var/www/html>
Options Indexes FollowSymLinks
AllowOverride All
Require all granted
</Directory>
<FilesMatch "\.php$">
SetHandler "proxy:unix:/var/run/php/php-fpm.sock|fcgi://localhost"
</FilesMatch>
ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>
# ─── Virtual Host dedicato per progetti Laravel ──────────
# La DocumentRoot punta alla sottocartella /public.
# Duplica questo blocco per ogni progetto Laravel aggiuntivo.
# Ricorda di aggiungere il dominio al file hosts di Windows:
# C:\Windows\System32\drivers\etc\hosts
# 127.0.0.1 sito1.localhost
<VirtualHost *:APACHE_PORT>
ServerName sito1.localhost
DocumentRoot /var/www/html/sito1/public
<Directory /var/www/html/sito1/public>
AllowOverride All
Require all granted
</Directory>
<FilesMatch "\.php$">
SetHandler "proxy:unix:/var/run/php/php-fpm.sock|fcgi://localhost"
</FilesMatch>
</VirtualHost>
# ─── Virtual Host wildcard per WordPress e siti senza /public ────────────────
# Gestisce automaticamente tutti i siti la cui DocumentRoot
# è la cartella radice del progetto, senza aggiungere un VirtualHost per ognuno.
<VirtualHost *:APACHE_PORT>
ServerName wildcard.localhost
ServerAlias *.localhost
UseCanonicalName Off
VirtualDocumentRoot /var/www/html/%1
<Directory /var/www/html>
AllowOverride All
Require all granted
</Directory>
<FilesMatch "\.php$">
SetHandler "proxy:unix:/var/run/php/php-fpm.sock|fcgi://localhost"
</FilesMatch>
</VirtualHost>
Configurazione pool PHP-FPM
Sovrascrive la configurazione di default del pool PHP-FPM per usare un socket Unix invece di TCP, che è più performante per comunicazioni locali all'interno del container.
Percorso: D:\temp\wamp-podman\php-apache\php\fpm-pool.conf
[www]
user = www-data
group = www-data
listen = /var/run/php/php-fpm.sock
listen.owner = www-data
listen.group = www-data
listen.mode = 0660
pm = dynamic
pm.max_children = 20
pm.start_servers = 4
pm.min_spare_servers = 2
pm.max_spare_servers = 6
6. Configurazione PHP
Percorso: D:\temp\wamp-podman\php-apache\php\custom.ini
; ─── Impostazioni generali ───────────────────────────────────────────────────
display_errors = On
display_startup_errors = On
error_reporting = E_ALL
log_errors = On
; ─── Limiti di risorse ───────────────────────────────────────────────────────
memory_limit = 512M
max_execution_time = 120
max_input_time = 120
max_input_vars = 3000
; ─── Upload ──────────────────────────────────────────────────────────────────
upload_max_filesize = 64M
post_max_size = 64M
; ─── Timezone ────────────────────────────────────────────────────────────────
date.timezone = Europe/Rome
; ─── OPcache ─────────────────────────────────────────────────────────────────
opcache.enable = 1
opcache.memory_consumption = 128
opcache.max_accelerated_files = 10000
; 0 = nessuna cache del timestamp: Apache vede sempre i file aggiornati
opcache.revalidate_freq = 0
; ─── Sessioni ────────────────────────────────────────────────────────────────
session.gc_maxlifetime = 3600
7. Configurazione Xdebug per VSCode
Percorso: D:\temp\wamp-podman\php-apache\php\xdebug.ini
zend_extension=/usr/local/lib/php/extensions/no-debug-non-zts-20250925/xdebug.so
[xdebug]
xdebug.mode = debug
xdebug.start_with_request = yes
; host.containers.internal è l'indirizzo speciale che Podman usa per
; raggiungere il sistema host (Windows) dal container.
xdebug.client_host = host.containers.internal
; Deve corrispondere a XDEBUG_PORT nel file .env
xdebug.client_port = 9003
xdebug.log_level = 0
xdebug.idekey = VSCODE
8. File compose.yaml
Percorso: D:\temp\wamp-podman\compose.yaml
name: ${COMPOSE_PROJECT_NAME}
networks:
devnet:
driver: bridge
volumes:
mariadb_data:
driver: local
services:
php-apache:
build:
context: ./php-apache
dockerfile: Dockerfile
container_name: ${COMPOSE_PROJECT_NAME}_php
restart: unless-stopped
ports:
- "${APACHE_PORT}:${APACHE_INTERNAL_PORT}"
volumes:
- "./www:/var/www/html:z"
environment:
- XDEBUG_CONFIG=client_host=host.containers.internal
- APACHE_INTERNAL_PORT=${APACHE_INTERNAL_PORT}
extra_hosts:
- "host.containers.internal:host-gateway"
networks:
- devnet
depends_on:
- mariadb
mariadb:
image: mariadb:12.2
container_name: ${COMPOSE_PROJECT_NAME}_db
restart: unless-stopped
ports:
- "${MARIADB_PORT}:3306"
volumes:
- mariadb_data:/var/lib/mysql:z
environment:
MARIADB_ROOT_PASSWORD: ${MARIADB_ROOT_PASSWORD}
networks:
- devnet
phpmyadmin:
image: phpmyadmin:latest
container_name: ${COMPOSE_PROJECT_NAME}_pma
restart: unless-stopped
ports:
- "${PHPMYADMIN_PORT}:${PHPMYADMIN_INTERNAL_PORT}"
environment:
PMA_HOST: mariadb
PMA_PORT: 3306
UPLOAD_LIMIT: 64M
networks:
- devnet
depends_on:
- mariadb
9. Avvio e gestione dell'ambiente
Apri PowerShell nella cartella D:\temp\wamp-podman.
Prima build
Da eseguire solo la prima volta, o dopo modifiche al Dockerfile:
cd D:\temp\wamp-podman
podman-compose build
Nel caso in cui si verificono problemi, a container avviati, per ricostruire tutto
# ferma e rimuove i container in esecuzione. I dati nel volume MariaDB restano intatti.
podman-compose down
# ricostruisce le immagini leggendo il Dockerfile da zero, ignorando qualsiasi layer memorizzato nella cache.
# Necessario quando modifichi il Dockerfile o i file che copia
podman-compose build --no-cache
# crea e avvia i container basandosi sulle immagini appena costruite
podman-compose up -d
Avviare, fermare e verificare i container
# Avvia tutti i container in background
podman-compose up -d
# Verifica che i container siano in esecuzione
podman ps
# Ferma i container senza rimuoverli
podman-compose stop
# Ferma e rimuove i container (i dati del DB rimangono nel volume)
podman-compose down
Accedere ai servizi
Siti web → http://localhost:8080
Sito specifico → http://sito1.localhost:8080
phpMyAdmin → http://localhost:8081
Log e shell
# Log in tempo reale di tutti i container
podman-compose logs -f
# Log di un singolo container
podman logs -f devenv_php
# Aprire una shell nel container PHP
podman exec -it devenv_php bash
All'interno del container puoi eseguire comandi Composer e Artisan direttamente nell'ambiente PHP:
composer install
php artisan migrate
php -m
10. Configurazione VSCode per il debug
Installare l'estensione PHP Debug
In VSCode installa l'estensione PHP Debug di Xdebug (id: xdebug.php-debug).
Creare il file launch.json
Percorso: D:\temp\wamp-podman\www\sito1\.vscode\launch.json
{
"version": "0.2.0",
"configurations": [
{
"name": "Listen for Xdebug (Podman)",
"type": "php",
"request": "launch",
"port": 9003,
"pathMappings": {
"/var/www/html/sito1": "${workspaceFolder}"
}
}
]
}
Il nodo pathMappings è fondamentale: mappa il percorso del file dentro il container
con il percorso corrispondente su Windows. Aggiorna /var/www/html/sito1
con il nome effettivo della cartella del tuo progetto.
Avviare una sessione di debug
- Apri il progetto in VSCode
- Vai nel pannello Run and Debug (
Ctrl+Shift+D) - Seleziona Listen for Xdebug (Podman)
- Premi F5 o clicca il triangolo verde
- Naviga nel browser: Xdebug si connette automaticamente e si ferma ai breakpoint
11. Uso quotidiano
Avvio/Stop rapido
podman machine start
cd D:\temp\wamp-podman
podman-compose up -d
podman-compose stop
Modificare una variabile
Apri D:\temp\wamp-podman\.env, modifica il valore desiderato, poi riavvia i container:
podman-compose down
podman-compose up -d
Aggiungere un nuovo sito
Crea la cartella del sito in D:\temp\wamp-podman\www\nuovo-sito\, poi aggiungi una riga al file hosts di Windows (come amministratore):
127.0.0.1 nuovo-sito.localhost
Il file hosts si trova in C:\Windows\System32\drivers\etc\hosts.
Se il sito usa Laravel, aggiungi un VirtualHost dedicato in vhosts.conf con DocumentRoot che punta a /var/www/html/nuovo-sito/public, poi ricostruisci:
podman-compose down
podman-compose build
podman-compose up -d
Se il sito è WordPress o ha la DocumentRoot nella root del progetto, il virtual host wildcard lo gestisce automaticamente senza modifiche.
Gestire i database
# Via browser
http://localhost:8081
# Via CLI nel container
podman exec -it devenv_db mariadb -u root -p
Backup e ripristino del database
# Esporta tutti i database
podman exec devenv_db mariadb-dump -u root -prootpassword --all-databases > backup.sql
# Ripristino
podman exec -i devenv_db mariadb -u root -prootpassword < backup.sql
Controllare i moduli PHP attivi
podman exec devenv_php php -m
Avviare Podman machine automaticamente con Windows
Per evitare di eseguire manualmente podman machine start ogni giorno, crea un Task nel Task Scheduler di Windows con questi parametri:
Trigger: All'avvio di Windows
Programma: podman
Argomenti: machine start