1 19/10/2026 12 min

CouchPotato è un progetto fermo da anni, quindi su Ubuntu 20.04 LTS non lo tratti come un’installazione “normale” ma come un software legacy da isolare. Il punto non è solo farlo partire: il punto è limitarne l’impatto, tenere sotto controllo le dipendenze e accettare che alcune librerie vecchie non siano più disponibili nei repository standard.

Se ti serve un gestore automatico per download e post-processing, questa guida ti porta a un’installazione funzionante con un servizio dedicato, permessi minimi e una superficie d’esposizione ridotta. Il flusso più pulito è usare un utente separato, una directory applicativa fuori da percorsi di sistema e un virtualenv Python 2.7, perché CouchPotato non è stato portato in modo affidabile a Python 3.

Prima di iniziare: cosa aspettarsi davvero

Ubuntu 20.04 non include Python 2 nei pacchetti base, e questo è il primo attrito. Il secondo è che CouchPotato dipende da librerie datate che potrebbero richiedere un po’ di manutenzione manuale. Se cerchi una soluzione mantenibile nel lungo periodo, valuta alternative più attive; se invece devi recuperare un’installazione esistente o mantenere compatibilità con una pipeline già costruita, la strada qui sotto è quella giusta.

In pratica lavorerai su tre livelli: sistema operativo, runtime Python, e servizio di avvio. Per evitare sorprese, conviene verificare subito che la macchina abbia spazio disco sufficiente, che la porta scelta non sia già occupata e che l’utente di servizio non abbia privilegi inutili.

Installazione dei prerequisiti su Ubuntu 20.04

Aggiorna l’indice pacchetti e installa i componenti base. Qui uso pacchetti standard e strumenti comuni per build e isolamento:

sudo apt update
sudo apt install -y git curl wget unzip ca-certificates \ build-essential python2.7 python2.7-dev python2-pip \ virtualenv libssl-dev libffi-dev zlib1g-dev \ libjpeg-dev libxml2-dev libxslt1-dev

Su alcune installazioni di Ubuntu 20.04, python2.7 e python2-pip potrebbero non essere disponibili nei repository standard. Se il comando fallisce, non forzare subito workaround casuali: verifica prima quali pacchetti sono presenti con apt-cache policy python2.7 python2-pip. Se non ci sono, la strada più pulita è usare un source esterno affidabile o un ambiente containerizzato; in alternativa puoi installare Python 2 da sorgente, ma è una scelta più fragile e va documentata bene.

Controlla anche la versione di OpenSSL e librerie correlate, perché alcuni moduli Python legacy possono fallire in fase di compilazione se mancano header o tool di build. Una verifica rapida è questa:

dpkg -l | egrep 'python2.7|libssl-dev|libffi-dev|zlib1g-dev'

Creare un utente dedicato e una directory applicativa

Non eseguire CouchPotato come root. Crea un utente dedicato senza shell interattiva e prepara una struttura ordinata per codice, configurazione e log. Questo riduce il blast radius se un plugin o una dipendenza si comporta male.

sudo useradd --system --home /opt/couchpotato --shell /usr/sbin/nologin couchpotato
sudo mkdir -p /opt/couchpotato /var/log/couchpotato /var/lib/couchpotato
sudo chown -R couchpotato:couchpotato /opt/couchpotato /var/log/couchpotato /var/lib/couchpotato

Il fatto che il codice viva in /opt/couchpotato non è cosmetico: separa l’applicazione dai dati persistenti e ti permette di aggiornare o sostituire il sorgente senza toccare la libreria di configurazione e i download incompleti. Se più avanti dovrai fare rollback, questa separazione ti semplifica molto la vita.

Scaricare CouchPotato in modo controllato

Il repository storico di CouchPotato è stato spostato o non sempre è affidabile nel tempo, quindi il primo passo è verificare la fonte del codice che vuoi usare. Se disponi già di un fork o di un archivio interno, usa quello. Altrimenti, recupera il sorgente da una sorgente nota e conserva un riferimento preciso della revisione.

cd /opt/couchpotato
sudo -u couchpotato git clone <URL_DEL_REPOSITORY> app

Se il clone non va a buon fine, non procedere con installazioni parziali: controlla prima con git ls-remote <URL_DEL_REPOSITORY> che il repository sia accessibile e che il branch previsto esista. In ambienti aziendali conviene salvare anche il commit esatto usato, così da poter ricostruire l’installazione in futuro.

Virtualenv Python 2.7 e dipendenze legacy

Una volta presente il codice, crea un virtualenv dedicato. Anche se Python 2 è obsoleto, il virtualenv aiuta a confinare le dipendenze e riduce il rischio di conflitti con il sistema operativo.

cd /opt/couchpotato/app
sudo -u couchpotato virtualenv -p python2.7 /opt/couchpotato/venv
sudo -u couchpotato /opt/couchpotato/venv/bin/pip install --upgrade pip setuptools wheel

A questo punto installa i requisiti dell’applicazione. Il nome del file dipende dal fork o dalla versione che hai scaricato, ma di solito trovi un requirements.txt nella root del progetto:

sudo -u couchpotato /opt/couchpotato/venv/bin/pip install -r /opt/couchpotato/app/requirements.txt

Se il pip fallisce su moduli come lxml, pyopenssl, cryptography o simili, il problema quasi sempre è una dipendenza di sistema mancante o una versione troppo nuova per Python 2. In quel caso il controllo utile non è “riprovare”, ma leggere l’errore completo e identificare il primo modulo che manca. Esempio pratico: se compare un errore su header C, verifica libxml2-dev e libxslt1-dev; se l’errore riguarda SSL, controlla libssl-dev.

Se il progetto include un file di installazione alternativo, non mescolare più procedure insieme. Scegli un solo percorso e mantieni coerenti il runtime, il path del codice e il file di servizio. La confusione tra installazione globale e virtualenv è una delle cause più comuni di avvio fallito su software vecchio.

Configurazione iniziale dell’applicazione

CouchPotato salva in genere configurazione, cache e stato in una directory interna o in un file di impostazioni. Il nome esatto cambia tra fork e versioni, quindi non conviene inventarlo: cerca i file di esempio nella root del progetto e usa quelli come base.

find /opt/couchpotato/app -maxdepth 2 \( -iname '*config*' -o -iname '*example*' -o -iname '*.ini' \) -type f

Se trovi un file di configurazione di esempio, copialo in una posizione persistente e leggibile solo dall’utente del servizio. Una convenzione sensata è tenere la configurazione in /var/lib/couchpotato o in una sottodirectory dedicata, così separi i dati runtime dal codice sorgente.

sudo -u couchpotato cp /opt/couchpotato/app/config.ini.example /var/lib/couchpotato/config.ini

Se il file non esiste, non forzare un nome a caso: apri il sorgente e individua il percorso effettivo usato dall’applicazione. Un controllo rapido si fa con grep -R nel repository per cercare stringhe come config.ini, settings o data_dir.

grep -RniE 'config\.ini|settings|data_dir|log_dir' /opt/couchpotato/app | head -n 20

Avvio manuale per validare il runtime

Prima di creare il servizio systemd, avvia l’applicazione in foreground o con il comando previsto dal progetto. L’obiettivo è vedere l’errore reale, non quello filtrato da systemd. Se il progetto ha uno script di start, usalo; se richiede un modulo Python specifico, lancia il processo nel virtualenv.

sudo -u couchpotato /opt/couchpotato/venv/bin/python /opt/couchpotato/app/CouchPotato.py

Il file esatto può cambiare in base al fork, quindi se CouchPotato.py non esiste elenca i file Python principali nella directory applicativa. L’importante è che il primo avvio avvenga in modo osservabile: output su terminale, errore leggibile, e nessuna modifica persistente non necessaria.

Se l’app si avvia ma non risponde sulla porta prevista, verifica subito con ss o curl locale. Questo ti dice se il problema è di binding, crash immediato o configurazione errata della porta.

ss -ltnp | grep -E ':(5050|5000|8080)'
curl -I http://127.0.0.1:5050/

Creare il servizio systemd

Quando l’avvio manuale è stabile, crea un’unità systemd semplice e leggibile. Evita wrapper inutili e tieni espliciti il working directory, l’utente e il virtualenv. Un servizio minimale è più facile da debuggare e da ripristinare.

sudo tee /etc/systemd/system/couchpotato.service > /dev/null <<'EOF'
[Unit]
Description=CouchPotato
After=network.target [Service]
Type=simple
User=couchpotato
Group=couchpotato
WorkingDirectory=/opt/couchpotato/app
ExecStart=/opt/couchpotato/venv/bin/python /opt/couchpotato/app/CouchPotato.py
Restart=on-failure
RestartSec=5
UMask=0027
NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=full
ProtectHome=true
ReadWritePaths=/var/lib/couchpotato /var/log/couchpotato [Install]
WantedBy=multi-user.target
EOF

Le direttive di hardening qui sopra sono conservative ma utili. ProtectSystem=full impedisce scritture accidentali fuori dai percorsi consentiti, PrivateTmp=true isola i file temporanei, e ReadWritePaths limita la scrittura alle sole directory necessarie. Se la tua versione dell’app scrive altrove, dovrai correggere il path o allargare solo quel permesso specifico, non aprire tutto il filesystem.

sudo systemctl daemon-reload
sudo systemctl enable --now couchpotato.service
sudo systemctl status couchpotato.service --no-pager

Se il servizio fallisce, la prima fonte da leggere è il journal, non il browser. Il comando utile è questo:

journalctl -u couchpotato.service -b --no-pager -n 100

Esposizione web: reverse proxy e porta locale

Non esporre direttamente il backend su Internet se puoi evitarlo. Metti CouchPotato dietro Nginx o Apache e lascia il servizio in ascolto solo su localhost. Questo ti permette di gestire TLS, header e accesso in modo più pulito.

Se usi Nginx, un blocco minimale può essere questo, adattando porta e hostname reali:

server { listen 80; server_name couchpotato.example.com; location / { proxy_pass http://127.0.0.1:5050; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; }
}

Se vuoi usare HTTPS, aggiungi un certificato valido e una redirezione da HTTP a HTTPS. Non è solo una questione di privacy: un backend di automazione accessibile in chiaro è un bersaglio facile per credenziali intercettate, sessioni rubate o accessi non autorizzati dalla rete locale.

Permessi, directory di download e post-processing

CouchPotato interagisce spesso con directory di download, rinomina file e lancia post-processing. Qui gli errori nascono quasi sempre da permessi sbagliati o da mount con ownership incoerente. Se il download client scrive con un utente diverso, devi allineare gruppo e permessi in modo esplicito.

sudo chown -R couchpotato:media /srv/downloads /srv/media
sudo chmod -R 2775 /srv/downloads /srv/media

Il bit 2 nei permessi mantiene il gruppo ereditato nelle nuove cartelle, utile quando più servizi devono lavorare sugli stessi file. Se usi NAS o mount SMB/NFS, verifica anche che l’UID/GID lato server corrispondano a quelli attesi, altrimenti i permessi locali non bastano.

Un controllo pratico consiste nel creare un file di test dall’utente del servizio e verificare che venga visto anche dal client di download o dal player downstream:

sudo -u couchpotato touch /srv/downloads/.couchpotato-test
ls -l /srv/downloads/.couchpotato-test

Debug dei problemi più comuni

Il caso più frequente è l’avvio che parte e poi si ferma subito. In genere le cause sono tre: dipendenza mancante, percorso file sbagliato o incompatibilità tra codice e Python 2. Per distinguerle rapidamente, guarda prima il journal, poi esegui il processo manualmente nel virtualenv.

Se la pagina web resta bianca, controlla i log applicativi e i log del reverse proxy. Una pagina bianca può essere un crash del backend, un errore JS lato browser o un problema di routing del proxy. Il browser da solo non basta.

journalctl -u couchpotato.service -b --no-pager -n 100
sudo tail -n 100 /var/log/couchpotato/*.log

Se il processo ascolta ma l’interfaccia non è raggiungibile dall’esterno, verifica nell’ordine: binding su localhost, firewall locale e configurazione del proxy. Un controllo sintetico è:

ss -ltnp | grep couchpotato
sudo ufw status verbose
curl -I http://127.0.0.1:5050/

Se la UI carica ma le operazioni di download non partono, il problema è spesso nei permessi della directory di destinazione o nel client esterno configurato male. Qui la verifica più utile è controllare il path configurato nell’interfaccia e confrontarlo con i permessi reali del filesystem.

Backup e rollback prima di toccare l’installazione

Dato che stai lavorando con un progetto legacy, ogni modifica importante va fatta con una via di ritorno chiara. Prima di cambiare dipendenze, servizio o configurazione, salva almeno il file di unità systemd, la configurazione applicativa e l’eventuale directory dati.

sudo cp /etc/systemd/system/couchpotato.service /etc/systemd/system/couchpotato.service.bak
sudo tar -czf /root/couchpotato-backup-$(date +%F).tar.gz /var/lib/couchpotato /var/log/couchpotato

Il rollback minimo consiste nel ripristinare il file di servizio, ricaricare systemd e riavviare il demone. Se hai aggiornato anche il codice, conserva il vecchio checkout come directory separata finché non hai verificato che la nuova versione sia stabile per almeno un ciclo completo di utilizzo reale.

sudo cp /etc/systemd/system/couchpotato.service.bak /etc/systemd/system/couchpotato.service
sudo systemctl daemon-reload
sudo systemctl restart couchpotato.service

Quando ha senso containerizzare invece di installare sul sistema host

Se l’obiettivo è solo mantenere vivo CouchPotato senza sporcare l’host, un container può essere una scelta più ordinata. Il vantaggio non è “moderno” in astratto: è che puoi congelare le dipendenze vecchie in un ambiente isolato e limitare l’impatto sul sistema operativo principale. Il rovescio della medaglia è che devi gestire storage persistente, rete e aggiornamenti dell’immagine con disciplina.

Su Ubuntu 20.04, installare direttamente sul sistema ha senso solo se vuoi semplicità operativa o hai già una base legacy da rispettare. Se invece stai partendo da zero, valuta seriamente se ti conviene mettere il progetto in un container con volumi montati per configurazione e download. In quel caso il flusso di troubleshooting cambia, ma la separazione tra runtime e host migliora parecchio.

Verifica finale dell’installazione

La verifica finale non è “la pagina si apre una volta”. Devi controllare almeno tre cose: il servizio resta attivo, la UI risponde localmente e il reverse proxy espone correttamente il sito all’host esterno. Una checklist minima è questa:

  1. systemctl is-active couchpotato.service restituisce active.

  2. curl -I http://127.0.0.1:5050/ restituisce un codice HTTP coerente, tipicamente 200 o 302.

  3. Il browser raggiunge il dominio configurato dietro proxy senza errori di mixed content o redirect loop.

  4. I log non mostrano eccezioni ripetute all’avvio o durante una richiesta normale.

Se uno di questi punti fallisce, non andare per tentativi casuali: torna al layer corrispondente. Se il servizio non parte, il problema è runtime o configurazione; se la UI locale risponde ma il dominio no, il problema è proxy o DNS; se la UI funziona ma i job falliscono, guarda permessi e path di lavoro.

Assunzione operativa: il sistema host è Ubuntu 20.04 LTS aggiornato, CouchPotato viene eseguito come servizio dedicato non privilegiato, e il tuo obiettivo è un’installazione funzionante ma confinata, non una piattaforma da esporre senza controllo.