Errore “externally-managed-environment” di pip su Debian/Ubuntu: come risolverlo bene
L’errore “externally-managed-environment” di pip: cosa significa e come gestirlo
Chi lavora regolarmente con script Python su server Debian o Ubuntu recenti si sarà imbattuto, prima o poi, in questo errore lanciando un banale pip install:
error: externally-managed-environment
Non è un bug, ma una scelta consapevole delle distribuzioni più recenti, che però disorienta chi è abituato al vecchio comportamento di pip.
Perché succede
A partire dalle versioni più recenti (Debian 12 “Bookworm” e Ubuntu 23.04+ in poi), il pip di sistema è “protetto” secondo la PEP 668: l’obiettivo è evitare che un pip install lanciato senza attenzione vada a sovrascrivere pacchetti Python gestiti dal sistema operativo stesso tramite apt, causando conflitti difficili da diagnosticare (pacchetti di sistema che smettono di funzionare dopo un aggiornamento pip non coordinato).
Le opzioni disponibili (e quale scegliere)
Ci sono sostanzialmente tre strade, con compromessi diversi:
- Virtual environment (consigliato nella maggior parte dei casi):
python3 -m venv venvseguito dasource venv/bin/activatee poipip installnormalmente. È la soluzione “corretta” secondo le best practice Python, isola completamente le dipendenze del progetto da quelle di sistema, ed è quella che uso di default per ogni nuovo script. - pipx per tool standalone: se devi installare un tool a riga di comando (non una libreria per uno script tuo),
pipx install nome-pacchettolo installa in un ambiente isolato dedicato, gestendo automaticamente PATH ed eseguibili. - –break-system-packages (da usare con cautela):
pip install --break-system-packages nome-pacchettoforza l’installazione ignorando la protezione. Va bene solo per ambienti usa-e-getta, container isolati, o quando sai esattamente cosa stai facendo e accetti il rischio di conflitti con i pacchetti apt.
Il caso pratico: script di automazione su server di produzione
Nel mio caso, gestendo diversi script Python di automazione su un server Ubuntu (bot Telegram, script di categorizzazione, orchestrazione), la scelta più sensata è stata creare un virtual environment dedicato per ogni progetto, invocato direttamente dal systemd service tramite il path completo dell’eseguibile Python del venv (es. /root/script/nome-progetto/venv/bin/python3), invece di affidarmi al Python di sistema.
Questo approccio ha il vantaggio aggiuntivo di rendere ogni progetto completamente riproducibile: basta un requirements.txt e il venv per ricreare l’ambiente identico su un altro server, senza sorprese dovute a versioni di pacchetti di sistema diverse tra macchine.
Un avvertimento
Se decidi di usare --break-system-packages su un server che esegue anche altri servizi gestiti da apt (praticamente qualsiasi server di produzione), tieni presente che un futuro apt upgrade potrebbe sovrascrivere o entrare in conflitto con i pacchetti Python installati forzatamente via pip, con comportamento imprevedibile. È un rischio da valutare consapevolmente, non un’opzione da usare per pigrizia.
