Diagnosi PrestaShop senza SSH: cosa si legge con il solo FTP
Shop lento o in errore e niente SSH? L'ordine con cui leggo header, log del pannello, back office e file via FTP prima di chiedere altre credenziali.
Lo shop rallenta, ogni tanto tira su una pagina di errore, e chi lo guarda ti chiede subito un accesso SSH al server. Solo che il tuo PrestaShop sta su un hosting condiviso: hai un pannello (CloudPanel, cPanel, DirectAdmin o Plesk), un utente FTP e le credenziali del back office. Di SSH, nemmeno l’ombra. La domanda vera non è come procurarti quell’accesso, ma quanto si riesce a capire senza. La risposta, per esperienza, è: quasi tutto quello che serve alla prima diagnosi.
⚠️ Cosa perdi davvero senza SSH (e cosa no)
Senza shell perdi tre cose: il tail -f sui log in tempo reale mentre riproduci il problema, la console CLI di PrestaShop (bin/console) per svuotare la cache o lanciare comandi, e la vista sui processi (chi sta mangiando CPU e memoria in questo momento).
Non perdi, invece, la parte che chiude la maggioranza dei casi: sapere se le pagine sono servite dalla cache o rigenerate a ogni hit, sapere quali errori il server sta scrivendo, sapere che versioni girano e quali file ci sono davvero sul disco. Sono quattro domande a cui si risponde con un browser, un client FTP e il pannello dell’hosting.
🛠️ Passo 1: quello che si legge da fuori, senza credenziali
Il primo giro non tocca nulla del sito e non richiede nemmeno di esserne il proprietario. Gli header di risposta dicono lo stack (server web, versione PHP quando esposta, presenza di un layer di cache) e soprattutto la cacheability pagina per pagina:
curl -sI https://tuoshop.it/ -> home
curl -sI https://tuoshop.it/<categoria-piena> -> categoria pesante
curl -sI https://tuoshop.it/<scheda-prodotto> -> prodotto
Quello che cerco è la coppia cache-control più l’header di stato della cache (x-litespeed-cache: hit|miss, o l’equivalente del layer in uso). Se la home risponde public e in hit mentre categorie e prodotti rispondono no-cache o no-store, la diagnosi ha già fatto metà strada: il catalogo viene rigenerato in PHP a ogni singola richiesta, quindi basta un crawler insistente per mettere in ginocchio il backend. È il controllo che tengo come runbook fisso dopo ogni deploy su un cliente PrestaShop, e più di una volta ha intercettato una configurazione della cache che si era disallineata da sola.
Nello stesso giro guardo robots.txt e sitemap (cosa lasci scansionare), il sorgente della home (quali script di terzi partono su ogni pagina) e i dati di campo di PageSpeed Insights, che raccontano cosa vede l’utente reale invece del tuo portatile in fibra. Se lo shop arranca ma il TTFB misurato da fuori resta basso, il problema sta davanti, nel tema e nei moduli, non dietro: quel bivio lo approfondisco nella guida sui Core Web Vitals di PrestaShop.
🛠️ Passo 2: i log del pannello, quelli che non sai di avere
Qui casca la convinzione più diffusa: “senza SSH non posso leggere i log”. Falso. Ogni pannello serio espone access log ed error log del dominio, e spesso permette di scaricarli. Su CloudPanel e cPanel sono una voce di menu; su DirectAdmin esiste anche un’API dedicata, che su un cliente ho usato al posto della shell: una Login Key limitata al solo comando di lettura dei log e vincolata al mio indirizzo IP, interrogata via HTTP indicando dominio, tipo di log (accessi o errori) e numero di righe. Nessuna password del pannello in giro, nessun permesso di scrittura, e l’error log del dominio davanti agli occhi: quella volta era pulito, solo bot bloccati e qualche 404 di immagini già noto, il che a sua volta è un’informazione (il problema non stava in PHP).
Leggere i log, però, è pieno di trappole. Tre che mi sono costate tempo, e che ti risparmio:
- Un 200 non vuol dire che PHP ha lavorato. Con una cache full-page davanti, gli hit di cache compaiono nel log come normalissimi 200: contare le righe 200 per stimare il carico sul database porta fuori strada.
- Lo stesso URL a volte 200 e a volte 500 non indica un bug nel codice. Indica una risorsa satura. Su uno shop che andava in 500 intermittente il colpevole era il pool di connessioni MySQL saturato dal flood dei crawler, non il deploy del giorno prima: un errore fatale nel codice sarebbe stato deterministico, quello no.
- Non fidarti dei riepiloghi dei tool. Analizzando un giorno di access log mi sono trovato in coda un blocco di conteggi per codice di risposta che non tornava: dichiarava centinaia di 429 che nel file grezzo non esistevano proprio. Era un aggregato di più sessioni dello strumento, non della giornata. Se un numero conta, si riconta sulle righe.
🛠️ Passo 3: il back office dice più di quanto sembri
Con le sole credenziali admin, in dieci minuti raccogli la carta d’identità dell’installazione. In Parametri avanzati -> Informazioni trovi versione di PrestaShop, PHP, MySQL e i controlli sui permessi delle cartelle. In Parametri avanzati -> Prestazioni vedi lo stato reale della cache, dello Smarty e della combinazione di CSS e JS. In Parametri avanzati -> Log trovi la tabella degli errori applicativi registrati da PrestaShop: filtrando per gravità alta salta fuori il pattern che si ripete. In Gestore moduli conti i moduli attivi e quelli con aggiornamento in sospeso.
Prima di ipotizzare, faccio l’inventario.
Versioni, cache, moduli, errori registrati: quattro schermate di back office.
Un dettaglio che vale come regola generale: la versione dichiarata non fa da prova. Verificando un modulo colpito da una vulnerabilità critica su alcuni shop, la versione riportata dalla configurazione diceva “vulnerabile” anche dove la falla era già stata chiusa a mano, perché una patch manuale non tocca il numero di versione. L’unico modo per sapere come stava davvero quel modulo era leggere il file. Il che ci porta all’FTP.
🛠️ Passo 4: l’FTP serve a leggere, non a modificare
Con il solo FTP si fa un’analisi statica seria. Le cartelle che guardo per prime sono var/logs/ (i log applicativi di Symfony, dove finiscono gli errori che il back office non mostra), override/ (le modifiche al core: la sorgente numero uno di sorprese dopo un aggiornamento), modules/ per i moduli custom o modificati a mano, e la root, dove capita di trovare script dimenticati da chi è passato prima.
Sul modulo vulnerabile di cui sopra il metodo, tutto in lettura, ha funzionato così: recuperare la versione dichiarata, poi aprire davvero il file incriminato per vedere quale funzione veniva chiamata, poi scansionare tutti i .php della cartella del modulo alla ricerca di indicatori di compromissione e file estranei. Anche lì una lezione presa sul campo: un controllo ingenuo produce falsi positivi e falsi negativi in entrambe le direzioni, perché nella stessa cartella convivono righe commentate e un metodo che si chiama come la funzione pericolosa senza esserlo. Il grep va scritto con la testa, e il risultato va guardato con gli occhi.
⚠️ Debug mode: sì, ma non per tutto il mondo
La modalità debug di PrestaShop mostra l’errore vero al posto della pagina bianca, e il profiler aggiunge il conteggio delle query, le più lente e il tempo speso per hook. Su un problema che non si spiega altrimenti, resta lo strumento decisivo.
Accenderla su uno shop live e lasciarla accesa, però, diventa un autogol: stack trace, percorsi assoluti del server e nomi delle tabelle diventano visibili a chiunque passi, bot compresi. Il modo in cui procedo io: limito il debug al mio indirizzo IP - nel file dei define la costante si attiva solo se l’IP del visitatore coincide con il mio - e rimetto tutto a posto appena finito. Stessa disciplina che uso quando accendo il debug di un modulo su un sito in produzione: attivo per il mio IP, guardo, spengo. Il profiler in particolare pesa: si tiene acceso il tempo di caricare le due o tre pagine che interessano, non per un pomeriggio.
✅ Quando serve eseguire qualcosa: lo script read-only
Arriva il punto in cui leggere non basta e devi far girare del codice sullo shop: interrogare il database, chiamare un hook e vedere cosa restituisce davvero, verificare come si comporta un servizio interno. Senza SSH il modo che uso resta uno solo: un singolo file PHP di servizio, caricato via FTP, protetto da un token nell’URL e progettato per non poter scrivere niente.
- token obbligatorio nell'URL, altrimenti risponde e basta
- sessione MySQL in sola lettura: il database rifiuta le scritture lato server
- whitelist di comandi: SELECT, SHOW, DESCRIBE, EXPLAIN. Nient'altro
- una sola istruzione per chiamata, niente concatenazioni
- credenziali lette dalla configurazione di PrestaShop, mai scritte nel file
- rimozione a fine lavoro, con verifica che l'URL risponda 404
Con questo pattern ho chiuso il caso in cui ps_checkout spariva dal checkout per colpa di LiteSpeed Cache: il cliente aveva soltanto l’FTP, e lo script serviva a eseguire lo stesso hook in due modi diversi. Chiamato direttamente restituiva l’array corretto, passando dal dispatcher sovrascritto dalla cache si rompeva. Senza quella prova sarebbe rimasta un’ipotesi.
⚠️ Quando i sintomi bastano e quando servono altri accessi
Con il giro qui sopra si chiudono da soli i casi in cui il sintomo si vede dall’esterno: cacheability sbagliata, lentezza tutta front-end, moduli che si pestano i piedi, errori applicativi ripetuti, pagine pesantissime che vanno in timeout. Su un catalogo, per dire, un report di Google segnalava decine di pagine “non disponibili”: non erano né prodotti disattivati né un filtro anti-bot, era lentezza pura, perché le schede con centinaia di combinazioni impiegavano quasi mezzo minuto a rispondere mentre le altre stavano sotto i tre secondi. Quel dato l’ho ricavato cronometrando le pagine dall’esterno, senza toccare il server.
Servono invece altri accessi quando la domanda diventa chi e quando, non cosa: capire quale crawler sta generando il carico, correlare un errore intermittente con l’orario dei cron, distinguere una cache che serve risposte vuote da un errore applicativo. Lì i log completi diventano indispensabili, e se il pannello non li espone bisogna chiederli. La richiesta onesta resta mirata: l’access log delle ultime 24 ore, oppure un accesso in sola lettura, oppure una finestra concordata in cui guardo io con qualcuno del team a fianco. Non “mandami tutte le credenziali”.
▸ Caso studio realeQuando i log sono l'unica strada: 5.047 errori 503 in 24hUna categoria di catalogo che cedeva sotto i bot. Non il server né la versione di PrestaShop: una cache disallineata, individuata contando i codici di risposta nell'access log.Leggi il caso →✅ L’ordine, in sei righe
1. header e cacheability dall'esterno -> il catalogo viene cachato o no?
2. log del pannello (accessi + errori) -> il server cosa sta scrivendo?
3. back office: versioni, cache, log -> come risulta fatta l'installazione?
4. FTP in lettura: override, var/logs -> cosa c'è davvero sul disco?
5. debug e profiler, solo sul mio IP -> l'errore vero e le query lente
6. script read-only con token -> la prova, quando serve eseguire
Ogni passo costa poco e restringe il campo. Si sale di invasività solo quando il passo precedente non ha risposto: così si evita di chiedere a un merchant credenziali che non ha, o peggio di farsele dare tutte “per sicurezza”.
✅ Hai uno shop e nessun accesso al server?
Se il tuo PrestaShop rallenta o restituisce errori e hai in mano soltanto un pannello con l’FTP, si lavora lo stesso: diagnostico con quello che c’è e ti dico, con le prove alla mano, se il problema si chiude così o se servono davvero altri accessi. Fa parte del mio servizio di assistenza PrestaShop.
Raccontami il sintomo da uno dei canali qui sotto: se hai già un log o uno screenshot dell’errore, allegalo, si parte molto più veloci.
❓ Domande frequenti
Posso davvero leggere i log del server senza SSH?
Attivare la modalità debug su uno shop online è pericoloso?
Perché il mio shop dà un errore 500 solo ogni tanto?
Devo installare un modulo di diagnostica per capire cosa non va?
Se ti do solo FTP e back office, cosa riesci a dirmi?
Hai un progetto in testa?
Raccontami cosa ti serve o cosa non funziona. Rispondo entro 24 ore, senza preventivi a scatola chiusa.