++ Primo Caricamento

This commit is contained in:
2026-03-30 19:15:13 +02:00
commit 663a68d59b
47 changed files with 3561 additions and 0 deletions

60
docker/nginx/default.conf Normal file
View File

@@ -0,0 +1,60 @@
server {
listen 80;
server_name localhost;
# La root punta a public/ di Laravel, NON alla root del progetto.
# Motivo: public/ è l'unica cartella esposta al web.
# Il resto del codice (app/, config/, .env…) è fuori dalla webroot = sicuro.
root /var/www/public;
index index.php index.html;
# Charset e log
charset utf-8;
access_log /var/log/nginx/portale_access.log;
error_log /var/log/nginx/portale_error.log;
# Dimensione massima upload (per allegati cliente, loghi, ecc.)
client_max_body_size 50M;
# ─────────────────────────────────────────────────────────────
# Regola principale: "try_files"
# Per ogni richiesta, Nginx prova nell'ordine:
# 1. $uri → cerca il file esatto (es. /css/app.css)
# 2. $uri/ → cerca come directory
# 3. /index.php?$query_string → passa tutto a Laravel (front controller)
# ─────────────────────────────────────────────────────────────
location / {
try_files $uri $uri/ /index.php?$query_string;
}
# ─────────────────────────────────────────────────────────────
# Gestione file PHP: passa le richieste a PHP-FPM
# "app:9000" → nome del container PHP nel docker-compose + porta FPM
# ─────────────────────────────────────────────────────────────
location ~ \.php$ {
fastcgi_pass app:9000;
fastcgi_index index.php;
# SCRIPT_FILENAME: percorso assoluto del file PHP da eseguire
fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
include fastcgi_params;
# Timeout generosi per operazioni lunghe (import, report, ecc.)
fastcgi_read_timeout 300;
}
# ─────────────────────────────────────────────────────────────
# Blocca accesso ai file nascosti (es. .env, .git, .htaccess)
# IMPORTANTE: non esporre mai il .env al web!
# ─────────────────────────────────────────────────────────────
location ~ /\.(?!well-known).* {
deny all;
}
# Cache browser per asset statici (performance)
location ~* \.(css|js|jpg|jpeg|png|gif|ico|svg|woff|woff2|ttf|eot)$ {
expires 1y;
add_header Cache-Control "public, immutable";
access_log off;
}
}

93
docker/php/Dockerfile Normal file
View File

@@ -0,0 +1,93 @@
# ────────────────────────────────────────────────────────────────
# Immagine base: PHP 8.2 in modalità FPM (FastCGI Process Manager)
# FPM è la modalità usata in produzione con Nginx.
# ────────────────────────────────────────────────────────────────
FROM php:8.2-fpm
# Argomenti di build (puoi sovrascriverli con --build-arg)
ARG USER_ID=1000
ARG GROUP_ID=1000
# ────────────────────────────────────────────────────────────────
# 1. Dipendenze di sistema e estensioni PHP necessarie a Laravel
# ────────────────────────────────────────────────────────────────
RUN apt-get update && apt-get install -y \
# Strumenti base
git \
curl \
unzip \
zip \
# Librerie per le estensioni PHP
libpng-dev \
libonig-dev \
libxml2-dev \
libzip-dev \
libpq-dev \
libredis-dev \
# Per generazione immagini/PDF (opzionale ma comune)
libfreetype6-dev \
libjpeg62-turbo-dev \
# Pulizia cache apt per ridurre dimensione immagine
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*
# ────────────────────────────────────────────────────────────────
# 2. Estensioni PHP
# docker-php-ext-install → estensioni native PHP
# pecl install → estensioni da PECL (es. Redis)
# ────────────────────────────────────────────────────────────────
RUN docker-php-ext-configure gd --with-freetype --with-jpeg \
&& docker-php-ext-install \
pdo_mysql \
mbstring \
exif \
pcntl \
bcmath \
gd \
zip \
xml \
opcache
# Estensione Redis via PECL
RUN pecl install redis \
&& docker-php-ext-enable redis
# ────────────────────────────────────────────────────────────────
# 3. Composer: gestore dipendenze PHP
# Lo copiamo dall'immagine ufficiale di Composer (multi-stage)
# ────────────────────────────────────────────────────────────────
COPY --from=composer:2.7 /usr/bin/composer /usr/bin/composer
# ────────────────────────────────────────────────────────────────
# 4. Utente non-root per sicurezza
# Usiamo lo stesso UID/GID del tuo utente host per evitare
# problemi di permessi sui file montati con volume.
# ────────────────────────────────────────────────────────────────
RUN groupmod -o -g ${GROUP_ID} www-data \
&& usermod -o -u ${USER_ID} -g www-data www-data
# ────────────────────────────────────────────────────────────────
# 5. Directory di lavoro e permessi
# ────────────────────────────────────────────────────────────────
WORKDIR /var/www
RUN mkdir -p \
storage/app/public \
storage/framework/cache/data \
storage/framework/sessions \
storage/framework/testing \
storage/framework/views \
storage/logs \
bootstrap/cache \
&& chown -R www-data:www-data /var/www
# ────────────────────────────────────────────────────────────────
# 6. Script di avvio
# ────────────────────────────────────────────────────────────────
COPY docker/php/entrypoint.sh /usr/local/bin/entrypoint.sh
RUN chmod +x /usr/local/bin/entrypoint.sh
USER www-data
ENTRYPOINT ["/usr/local/bin/entrypoint.sh"]
CMD ["php-fpm"]

112
docker/php/entrypoint.sh Normal file
View File

@@ -0,0 +1,112 @@
#!/bin/bash
# ─────────────────────────────────────────────────────────────────────────────
# Entrypoint: eseguito ad ogni avvio del container.
# Si occupa di preparare l'applicazione la prima volta e ad ogni restart.
# ─────────────────────────────────────────────────────────────────────────────
set -e # Interrompi se un comando fallisce
echo "────────────────────────────────────────"
echo " Avvio Portale Clienti"
echo "────────────────────────────────────────"
# ─────────────────────────────────────────────
# 1. Installa le dipendenze PHP con Composer
# --no-interaction → niente domande interattive
# --optimize-autoloader → più veloce in produzione
# ─────────────────────────────────────────────
if [ ! -d "vendor" ]; then
echo "→ vendor/ non trovata. Eseguo composer install..."
composer install --no-interaction --optimize-autoloader
else
echo "→ vendor/ già presente. Salto composer install."
fi
# ─────────────────────────────────────────────
# 2. Genera APP_KEY se non è impostata
# La chiave è usata per cifrare sessioni e cookie.
# ─────────────────────────────────────────────
if grep -q "^APP_KEY=$" .env 2>/dev/null || ! grep -q "^APP_KEY=" .env 2>/dev/null; then
echo "→ APP_KEY non trovata. La genero..."
php artisan key:generate --no-interaction
else
echo "→ APP_KEY già impostata."
fi
# ─────────────────────────────────────────────
# 3. Permessi sulle cartelle di storage
# Laravel deve poter scrivere qui (log, cache, sessioni…)
# ─────────────────────────────────────────────
echo "→ Imposto permessi su storage/ e bootstrap/cache/"
chmod -R 775 storage bootstrap/cache
# ─────────────────────────────────────────────
# 4. Crea il link symbolico storage → public/storage
# Necessario per servire file caricati dall'utente
# ─────────────────────────────────────────────
if [ ! -L "public/storage" ]; then
echo "→ Creo symlink public/storage → storage/app/public"
php artisan storage:link --no-interaction
fi
# ─────────────────────────────────────────────
# 5. Attende che il database sia pronto
# MySQL impiega qualche secondo ad avviarsi.
# ─────────────────────────────────────────────
echo "→ Attendo che il database sia disponibile..."
MAX_TRIES=30
TRIES=0
until php artisan db:monitor 2>/dev/null || [ $TRIES -ge $MAX_TRIES ]; do
echo " Database non pronto, riprovo tra 2s... ($((TRIES+1))/$MAX_TRIES)"
sleep 2
TRIES=$((TRIES+1))
done
if [ $TRIES -ge $MAX_TRIES ]; then
echo "⚠ Database non raggiungibile dopo $MAX_TRIES tentativi."
echo " Continuo comunque (potresti essere in modalità manutenzione)."
fi
# ─────────────────────────────────────────────
# 6. Esegui le migration
# --force → necessario in ambiente non-TTY (es. Docker)
# Le migration vengono eseguite solo se ci sono nuove
# ─────────────────────────────────────────────
echo "→ Eseguo le migration del database..."
php artisan migrate --force --no-interaction
# ─────────────────────────────────────────────
# 7. Esegui i seeder solo al primo avvio
# Controlla se la tabella settings è vuota
# ─────────────────────────────────────────────
SETTINGS_COUNT=$(php artisan tinker --execute="echo \App\Models\Setting::count();" 2>/dev/null | tail -1 || echo "0")
if [ "$SETTINGS_COUNT" = "0" ]; then
echo "→ Tabella settings vuota. Eseguo i seeder..."
php artisan db:seed --force --no-interaction
else
echo "→ Dati già presenti. Salto i seeder."
fi
# ─────────────────────────────────────────────
# 8. Ottimizzazioni (cache config, routes, views)
# In development potrebbe essere più utile saltare questo,
# in produzione invece migliora le performance.
# ─────────────────────────────────────────────
if [ "${APP_ENV}" = "production" ]; then
echo "→ Ambiente produzione: ottimizzazione cache..."
php artisan config:cache
php artisan route:cache
php artisan view:cache
else
echo "→ Ambiente development: svuoto cache esistente..."
php artisan config:clear
php artisan route:clear
php artisan view:clear
fi
echo "────────────────────────────────────────"
echo " Portale Clienti pronto!"
echo " URL: http://localhost:${NGINX_PORT:-8080}"
echo "────────────────────────────────────────"
# Avvia il processo principale (php-fpm)
exec "$@"

34
docker/php/php.ini Normal file
View File

@@ -0,0 +1,34 @@
; ─────────────────────────────────────────────────────────────
; Configurazione PHP personalizzata per il Portale Clienti
; Questo file sovrascrive i default di PHP dentro il container.
; ─────────────────────────────────────────────────────────────
[PHP]
; Dimensione massima memoria per richiesta (utile per import grandi)
memory_limit = 256M
; Dimensione massima upload file
upload_max_filesize = 50M
post_max_size = 50M
; Timeout di esecuzione (secondi) - aumentare per job lunghi
max_execution_time = 300
; Mostra errori: ON in development, OFF in production
; (in Docker gestiamo questo tramite APP_DEBUG nel .env)
display_errors = Off
log_errors = On
error_log = /var/www/storage/logs/php_errors.log
[Date]
; Fuso orario di default
date.timezone = "Europe/Rome"
[opcache]
; OPcache: compila PHP in bytecode → applicazione più veloce
opcache.enable = 1
opcache.memory_consumption = 128
opcache.interned_strings_buffer = 8
opcache.max_accelerated_files = 10000
opcache.revalidate_freq = 0 ; In dev: 0 = ricompila sempre | In prod: 60
opcache.save_comments = 1