Il comando funziona nel tuo terminale e alle tre di notte non produce niente. Cron non è rotto. Esegue il tuo comando in un ambiente che non somiglia quasi per nulla alla tua shell, e quella differenza è tutta la risposta.

Guarda cosa è successo

grep CRON /var/log/syslog | tail -20

Se il tuo lavoro lì non compare affatto, cron non ci ha nemmeno provato. Se compare, cron l'ha eseguito ed è andato storto qualcos'altro.

1. PATH è quasi vuoto

La tua shell sa dove sta php. Cron no: il suo PATH di solito è soltanto /usr/bin:/bin. Usa sempre il percorso completo.

which php
# /usr/bin/php8.3

# in the crontab
0 3 * * * /usr/bin/php8.3 /var/www/site/cron.php

2. L'output non va da nessuna parte

Un lavoro senza redirezione manda il proprio output a una posta che non è configurata, e così gli errori svaniscono. Mandalo in un file, e il prossimo guasto si spiegherà da sé.

0 3 * * * /usr/bin/php8.3 /var/www/site/cron.php >> /var/log/site-cron.log 2>&1

3. L'utente sbagliato

Un lavoro nel crontab di root scrive file di proprietà di root, che il server web poi non può modificare. Mettilo nel crontab dell'utente che possiede il sito.

crontab -u youruser -l

4. Un segno di percentuale

In un crontab % significa a capo. Un formato di data come +%Y-%m-%d diventa in silenzio tre righe e il comando si rompe. Proteggilo così: \%.

Provalo come lo eseguirà cron

env -i /bin/sh -c "/usr/bin/php8.3 /var/www/site/cron.php"

Questo lo esegue con un ambiente vuoto, che è esattamente ciò che fa cron. Se fallisce qui, fallirà anche alle tre.

Il cron di WordPress non è cron: parte al caricamento delle pagine, quindi un sito poco visitato non esegue mai i suoi lavori. Spegni WP_CRON e chiama wp-cron.php da un vero lavoro pianificato.