logo

Perché comprare un Raspberry quando hai un Redmi?

Ho tolto Android da un vecchio telefono e l'ho trasformato in un vero server Linux. Poi, ovviamente, le cose sono degenerate... 🔌

LinuxPostmarketOSHomelabHardware
post_image
11/10/2026
1
Cristian Di CarloCristian Di Carlo

Da anni racconto a Marco delle mie disavventure con Raspberry Pi, VPS, Docker, reti e homelab. A lui è sempre piaciuto smanettare con le cose: stampante 3D, elettronica, hardware, piccoli progetti. La programmazione pura, invece, non è mai riuscita a prenderlo allo stesso modo. A un certo punto gli ho proposto una cosa molto semplice: invece di studiare programmazione nel vuoto, perché non prendere un piccolo computer, metterci Linux e iniziare semplicemente a romperlo? Un Raspberry Pi, un SBC qualsiasi, qualche container, un paio di servizi, magari Hermes Agent ad aiutarlo quando qualcosa inevitabilmente smette di funzionare.

C'era solo un problema: per questo esperimento il budget ideale era esattamente zero. Poi mi è tornata in mente una cosa.

Aspetta, non avevi ancora quel Redmi?

Prima del suo Pixel 8, Marco usava un Redmi Note 9 Pro. Era ancora da qualche parte. La mia prima idea è stata banalissima: recuperiamolo, mettiamoci Debian in una VM e usiamolo come piccolo server.

Poi ho iniziato a pensarci. Negli ultimi anni abbiamo visto software partire su hardware per cui non era mai stato pensato: console jailbroken, port improbabili, sistemi operativi alternativi su dispositivi sempre più chiusi. Un telefono, alla fine, è già un computer ARM completo: CPU, parecchia RAM, storage, Wi-Fi, USB, batteria, display, sensori.

Quindi perché tenere Android sotto? Possibile che non ci fosse un modo per toglierlo del tutto e usare direttamente Linux? A quel punto mi sono ricordato di postmarketOS.

Questa cosa la volevo fare da anni

La parte divertente è che non era affatto la prima volta che pensavo a una cosa del genere. Volevo poter trattare un telefono come un normale computer Linux da molto prima di comprare i miei primi Raspberry Pi, alla fine del 2021.

Mi ha sempre fatto impazzire il modo in cui viene trattato gran parte dell'hardware ARM consumer. Su un normale PC x86 puoi almeno entrare nel BIOS o nella UEFI, cambiare il boot order, disabilitare hardware, scegliere cosa avviare e avere un minimo di controllo prima ancora che parta il sistema operativo. Su tantissimi dispositivi ARM compri fisicamente l'hardware, ma buona parte del controllo resta vincolata alla piattaforma del vendor: boot chain custom, firmware proprietari, descrizioni hardware specifiche, periferiche che funzionano davvero solo con il software previsto dal produttore.

È una filosofia che non mi è mai piaciuta. Se compro qualcosa, voglio poterla rompere. Voglio poter cambiare sistema operativo, configurarla come mi pare e prendermi la responsabilità delle mie scelte, anche quando la conseguenza è passare un pomeriggio a capire perché non funziona più niente.

Quando ho controllato postmarketOS e ho visto che la famiglia miatoll era ancora mantenuta, anche se in stato testing, la decisione era praticamente già presa. Il telefono di Marco era un Redmi Note 9 Pro Global, variante joyeuse, e il bootloader era già sbloccato. Ci siamo organizzati quasi immediatamente.

Prima di rompere tutto, facciamo un backup

Qualche giorno dopo ero a casa di Marco con il telefono sulla scrivania. Ho aperto una sessione con GPT Luna/Codex, il coding agent che uso per questo tipo di lavoro, e gli ho dato un obiettivo preciso: identificare correttamente il dispositivo, verificare ogni passaggio e salvare le partizioni utili prima di iniziare a modificarlo. Non volevo una lista di comandi da copiare alla cieca. Volevo che l'agent controllasse lo stato del telefono, mi dicesse cosa stava per fare e si fermasse se qualcosa non tornava.

Abbiamo usato anche OrangeFox e fastboot. Alla fine il backup conteneva 77 immagini .img più un file SHA256SUMS: boot, DTBO, modem e una quantità di partizioni Qualcomm di cui ancora oggi non saprei spiegare la funzione senza andare a rileggere la documentazione. userdata, volutamente, non c'era. Non era un restore point magicamente garantito, perché quel backup non è mai stato ripristinato come test. Ma prima di cancellare Android avevamo almeno salvato tutto quello che ritenevamo utile.

backup imagesbackup images

Poi abbiamo iniziato a preparare postmarketOS.

postmarketos imagespostmarketos images

Mi aspettavo almeno qualche ora di problemi. Invece dopo un po' di armeggi è comparso il logo di postmarketOS. E il boot è arrivato fino in fondo.

first bootfirst boot

Okay. È davvero Linux.

Siamo entrati via SSH attraverso USB. La prima cosa che abbiamo installato è stata, inevitabilmente, fastfetch. Non perché servisse realmente a qualcosa. Dopo aver appena tolto Android da un telefono di qualche anno prima volevo semplicemente vedere nero su bianco cosa stesse girando.

fastfetchfastfetch

Kernel 6.14.7-sm7125, ARM64, più di 5 GiB di RAM visibili al sistema, filesystem Linux, shell, networking. Nessun Android sotto. Nessuna VM. Nessun proot. Linux nativo.

Un telefono che probabilmente sarebbe rimasto in un cassetto per anni era appena diventato una piccola macchina ARM accessibile in SSH, senza che avessimo comprato un altro computer. Durante tutta la sessione continuavo a mandare video agli amici. Visto da fuori credo fosse ancora più assurdo: due persone davanti a un vecchio Xiaomi, entusiaste perché finalmente potevano trattarlo come un server.

A quel punto potevamo tranquillamente fermarci. Naturalmente non lo abbiamo fatto.

Avevamo ancora un intero telefono attaccato al server

Se avessimo voluto semplicemente un server headless, il progetto era praticamente concluso. Wi-Fi, SSH, Linux nativo e una microSD da 128 GB montata come storage aggiuntivo. Fine.

Ma davanti a noi non c'era una scheda senza periferiche. C'era ancora un telefono. Avevamo un display 1080×2400, touchscreen, sensore di luminosità, accelerometro, batteria e USB-C. Lasciare tutta quella roba inutilizzata iniziava a sembrarmi uno spreco.

Quindi ho proposto a Marco di usare direttamente lo schermo come dashboard del server: uptime, rete, indirizzi IP, temperatura, servizi e informazioni sui container se e quando ne avesse installati. L'agent ha costruito una prima versione testuale con curses.

Funzionava. Solo che c'era un problema piuttosto evidente: il telefono era in verticale.

Va bene, disegniamo lo schermo noi

Pensavo che ruotare la console fosse una stupidaggine. Non lo era. Il kernel che stavamo usando non aveva abilitato la rotazione della framebuffer console:

text # CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set

Una delle strade possibili era iniziare a toccare la configurazione del kernel. Non era esattamente il rabbit hole che volevo aprire per ruotare del testo di novanta gradi.

La soluzione proposta dall'agent era più interessante: smettere di trattare lo schermo come una normale console e disegnare direttamente la dashboard. Il renderer crea con Pillow un'immagine landscape da 2400×1080, la ruota in userspace, la converte nel formato richiesto dal framebuffer e la scrive direttamente su /dev/fb0.

Non saprei ancora spiegare nei dettagli tutto quello che succede tra Pillow, framebuffer, kernel e display controller. Ma il concetto era abbastanza semplice da seguire: il kernel non voleva ruotare la console, quindi abbiamo smesso di chiederglielo e abbiamo disegnato noi quello che volevamo vedere. E ha funzionato.

Se abbiamo i sensori, usiamo anche quelli

A quel punto la dashboard era leggibile e mostrava quello che ci serviva. E ovviamente ho iniziato a chiedermi cos'altro potessimo recuperare dall'hardware.

Prima domanda: il sensore di luminosità funziona ancora sotto Linux? Sì. Quindi abbiamo aggiunto un servizio che legge la luce ambientale e regola automaticamente la luminosità del display, con un po' di smoothing per evitare cambiamenti continui per ogni minima variazione.

Poi ho notato un'altra cosa: se Marco avesse appoggiato il telefono sull'altro lato, la dashboard sarebbe stata sottosopra. Pensavo di usare il giroscopio. Peccato che il giroscopio non fosse esposto dall'interfaccia sensori disponibile. L'accelerometro invece sì. E alla fine non ci serviva davvero sapere come il telefono stesse ruotando. Ci bastava sapere da che parte tirava la gravità.

Ogni circa cinque secondi il renderer legge l'accelerometro e decide quale dei due orientamenti landscape usare. È molto più lento della rotazione automatica di uno smartphone, ma per un display fermo su una mensola è più che sufficiente. Già che c'eravamo, abbiamo anche aggiunto una piccola gestione notturna: da mezzanotte alle 08:00 il backlight va a zero mentre il server continua a funzionare. Se qualcuno tocca il touchscreen, lo schermo si riaccende per 30 secondi e poi torna spento.

Non era più semplicemente un vecchio smartphone che faceva girare Linux. Stava iniziando ad assomigliare a un piccolo appliance costruito apposta. E ancora una volta, avremmo potuto fermarci lì.

Il giorno dopo ho trovato un altro problema

Il telefono era letteralmente sopra il router. Il Wi-Fi funzionava bene. Ma il giorno dopo ho iniziato comunque a pensare a cosa sarebbe successo se Marco avesse deciso di usarlo davvero come server: WireGuard, NetBird, servizi raggiungibili da fuori casa, trasferimenti più pesanti.

A quel punto una connessione cablata mi sembrava molto più sensata: più throughput disponibile, latenza meno variabile e nessuna dipendenza dal Wi-Fi per una macchina che sarebbe rimasta ferma a pochi centimetri dal router. Gli ho detto di cercare un adattatore USB-C con due caratteristiche: Gigabit Ethernet e Power Delivery passthrough.

Ne ha trovato uno esattamente del tipo che serviva, con Realtek RTL8153 e una porta PD dichiarata fino a 100 W. Lo ha ordinato. Due giorni dopo ero di nuovo a casa sua.

Ethernet funziona. Poi colleghiamo la corrente.

La prima parte è andata sorprendentemente bene. Il dongle veniva riconosciuto, il kernel caricava il driver r8152 e eth0 compariva regolarmente. Ottimo.

Poi abbiamo collegato anche l'alimentazione attraverso la porta PD dell'hub. E Linux ha iniziato a esplodere. Non nel senso che il telefono si riavviasse da solo. Restava acceso, ma la rete poteva morire completamente e sul display comparivano kernel Oops e stack trace. In uno dei casi che ricordo meglio, i messaggi attraversavano verticalmente il framebuffer ormai stale della dashboard.

Questa è una foto di uno dei crash più pesanti che siamo riusciti a catturare:

kernel oopskernel oops

Non è esattamente il crash con la dashboard congelata sotto, ma rende abbastanza bene l'idea: call trace del kernel, teardown xHCI e il dongle Realtek che continua a comparire e sparire. La parte strana era che Ethernet, presa da sola, funzionava. Il problema compariva quando cercavamo di far convivere sulla stessa USB-C il telefono come host del dongle e contemporaneamente come dispositivo alimentato.

Okay agent, dimmi che cosa è appena esploso

Dopo un riavvio manuale ho mandato l'agent a scavare nel journal persistente e nei log del kernel. È qui che la mia comprensione tecnica inizia a diventare parecchio più superficiale. Non voglio raccontare questa storia come se dopo una giornata fossi diventato capace di leggere uno stack trace ARM64 e diagnosticare da solo un bug nello stack USB di Linux. Non è successo.

L'agent ha trovato più istanze dello stesso tipo di problema: un use-after-free durante il teardown di r8152 e xHCI mentre userspace stava interrogando lo stato delle interfacce di rete. In termini molto semplificati: il device USB spariva, una parte dello stack lo stava smontando, mentre un'altra provava ancora ad accedere a dati che nel frattempo non erano più validi.

Nel frattempo abbiamo trovato anche qualcosa di molto più banale: mancava linux-firmware-rtl_nic, il pacchetto con il firmware richiesto dal Realtek RTL8153. Lo abbiamo installato. Riavvio. Nuovo test.

La parte firmware era sistemata. Il problema principale no.

Il momento in cui ho iniziato a temere la parola "kernel"

A quel punto abbiamo iniziato a considerare qualsiasi cosa: workaround in userspace, driver, firmware, configurazione USB, patch, ricompilazioni. Ogni nuova possibilità sembrava portarci più vicino a una zona in cui personalmente non avevo quasi nessuna competenza reale.

Io faccio sviluppo web e mobile. Termini come TCPM, DTS, DTB, xHCI e PMIC li avevo già sentiti negli anni. Questo non significa che sapessi davvero cosa facessero.

Ed è qui che l'agent ha trovato qualcosa di molto più concreto. Il problema non richiedeva necessariamente di ricompilare il kernel. Era nella descrizione hardware che il kernel stava usando.

Il telefono pensava di essere una power bank

Nel device tree della piattaforma sm7125-xiaomi, il connettore USB-C era dichiarato così:

dts power-role = "source";

Detta nel modo più grezzo possibile: Linux stava partendo dall'idea che quella porta dovesse dare corrente. Il telefono poteva fare da USB host per il dongle Ethernet, ma il port mainline non era descritto in modo da negoziare correttamente anche l'alimentazione in ingresso come sink.

La patch proposta dall'agent cambiava il ruolo in dual, preferendo sink, e aggiungeva dei sink PDO limitati volutamente a 5 V:

dts power-role = "dual"; try-power-role = "sink";

Non abbiamo ricompilato l'intero kernel. Abbiamo modificato e ricompilato il DTB, cioè la forma binaria del device tree che descrive al kernel parte dell'hardware della macchina. Questa è la spiegazione corretta.

La mia comprensione reale quel pomeriggio era più vicina a:

Okay, apparentemente questo file dice a Linux che la porta può solo dare corrente. Noi vogliamo che possa anche riceverla. Proviamo.

Ovviamente il fix corretto non veniva caricato

Abbiamo patchato il DTB. Riavviato. Niente. Il sistema continuava a comportarsi come prima.

Altro giro di debugging. Alla fine abbiamo scoperto che mettere semplicemente il file modificato in /boot/dtbs non significava affatto che il sistema lo avrebbe usato: U-Boot stava fornendo il proprio FDT durante il boot. Abbiamo provato anche bootctl set-oneshot, per poi scoprire che in quella configurazione le variabili EFI di U-Boot non persistevano come ci aspettavamo.

Alla fine l'override devicetree è finito direttamente nella entry pmos.conf, puntando esplicitamente al DTB patchato. Altro riavvio. Altro controllo. Questa volta la porta risultava finalmente dual.

Ethernet attiva. Colleghiamo il caricatore. Power Delivery negoziato a 5 V / 2 A. eth0 ancora su. E il fuel gauge, per quanto incompleto e poco affidabile su questo port, iniziava almeno a mostrare un comportamento coerente con la carica.

Funzionava. O almeno così pensavamo.

Cavi, alimentatori e altre forme di sofferenza

Abbiamo passato il resto del pomeriggio a provare combinazioni. Alimentatori PD più potenti. Un alimentatore da laptop da 100 W. Il vecchio alimentatore Xiaomi QC con USB-A. Cavi USB-C diversi. Cavi Ethernet diversi.

Alcune combinazioni erano stabili. Altre iniziavano a oscillare tra sink e source. In altre tornavano i problemi. Il caricatore PD da 20 W che Marco aveva comprato apposta per il serverino sembrava inizialmente uno dei peggiori. A un certo punto lo avevamo praticamente dichiarato colpevole. Poi, dopo ore di prove, lo abbiamo riprovato con il suo cavo USB-C originale. E ha funzionato.

Stabile. Ethernet attiva. PD attivo. Batteria in carica. Nessun nuovo Oops durante i test finali.

Il risultato è rimasto pulito anche nei reboot verificati con la procedura che avevamo ormai imparato: lasciare stabilizzare il boot e collegare la PD dopo, invece di partire con tutto già attaccato. Non siamo mai riusciti a isolare scientificamente quale variabile avesse causato i fallimenti precedenti. Il primo cavo C-to-C? Caduta di tensione? Stato della batteria? Carico del display? Una combinazione? Non lo sappiamo. E preferisco scriverlo così piuttosto che inventare una spiegazione a posteriori.

Il risultato finale che abbiamo verificato era quello che ci interessava: hub USB-C, Gigabit Ethernet, alimentatore PD da 20 W con il suo cavo, telefono alimentato e collegato alla LAN. Abbiamo spento il Wi-Fi, spostato il traffico su eth0 e aggiornato la dashboard per mostrare anche stato LAN, IPv4 cablato e gateway.

end resultend result

Da esperimento nostro a qualcosa che forse può servire ad altri

Verso la fine della giornata l'agent mi ha suggerito una cosa che inizialmente non avevo considerato: questa modifica poteva valere la pena di essere documentata bene e, forse, proposta upstream. Di solito i miei rabbit hole finiscono nel mio homelab. Configuro qualcosa, lo faccio funzionare, magari apro una repo perché mi torna utile, e finisce lì.

Questa volta avevamo trovato un problema reale nel supporto di un dispositivo, prodotto una patch riproducibile e raccolto anche i log degli Oops. Quindi ho chiesto all'agent di prendere tutto quello che avevamo scoperto e trasformarlo in qualcosa di riutilizzabile. È nata miatoll-usb-pd-ethernet-fix, con la patch al device tree, uno script per riapplicarla dopo gli aggiornamenti del kernel e i crash log raccolti durante i test.

La repo ora appartiene a Marco, che ha anche un sito personale. Mi sembrava giusto così: il telefono è suo, il server è suo e l'intero progetto era nato per dargli qualcosa con cui smanettare.

Il prossimo passo che ci piacerebbe provare è capire se almeno parte di questo lavoro possa avere senso upstream. Non c'è ancora nessuna PR e non voglio fingere che ci sia. Per entrambi sarebbe una cosa nuova: invece di fare l'ennesimo progetto per i cazzi nostri, provare a entrare davvero nel processo di un progetto open source e vedere cosa succede quando una patch incontra dei maintainer veri. Anche se ci dicessero che è completamente sbagliata, probabilmente impareremmo qualcosa.

No, non ho imparato lo sviluppo kernel in un pomeriggio

Questa parte per me è importante. Dopo tutto questo non so sviluppare il kernel Linux. Non saprei implementare da zero il supporto USB-C di questo telefono. Non saprei progettare correttamente un device tree per una piattaforma Qualcomm. Se domani mi dessero un altro dispositivo con un problema diverso, senza l'agent e senza documentazione sarei di nuovo quasi al punto di partenza.

Ho capito abbastanza da seguire il filo: vedere cosa veniva modificato, chiedere perché, confrontare il comportamento prima e dopo e fermarmi quando qualcosa non tornava. Ma non voglio confondere "sono riuscito a fare questa cosa con un agent" con "ora possiedo tutte le competenze che ci sono dietro".

È proprio questo, però, uno degli aspetti che trovo più interessanti degli agent moderni. Non ti regalano anni di esperienza. Possono però abbassare abbastanza la barriera d'ingresso da permetterti di mettere le mani su problemi che fino a poco tempo fa avresti semplicemente evitato perché non avresti nemmeno saputo da dove iniziare. Poi sta a te decidere quanto vuoi capire davvero, quanto vuoi fidarti e quanta responsabilità sei disposto a prenderti quando tocchi qualcosa che può smettere di bootare al prossimo riavvio.

Perché comprare un Raspberry, allora?

La risposta seria è che, se vuoi semplicemente un server piccolo, prevedibile e ben supportato, comprare un Raspberry Pi o un altro SBC rimane una scelta molto più semplice. Ma in questo caso il punto non era trovare la strada più semplice.

Potevamo usare Android e una VM. Potevamo fermarci appena SSH ha iniziato a funzionare. Potevamo lasciare spento il display. Potevamo ignorare i sensori. Potevamo tenere il Wi-Fi. Potevamo abbandonare Ethernet appena sono comparsi i primi kernel Oops. In ognuno di quei punti fermarsi sarebbe stata la scelta più ragionevole.

Però a volte complicarsi la vita in questo modo ti fa vivere esperienze che altrimenti non avresti mai avuto. Durante quei giorni abbiamo toccato, anche solo superficialmente, framebuffer, sensori Qualcomm, systemd, USB-C Power Delivery, U-Boot, device tree e pezzi dello stack USB di Linux. Non posso dire di averli imparati davvero, ma adesso almeno li ho visti fallire davanti ai miei occhi per un motivo concreto.

E soprattutto abbiamo recuperato quasi tutto quello che quel telefono aveva da offrire. CPU, RAM, storage, display, touchscreen, accelerometro, sensore di luce, USB-C. Hardware che poteva restare anni in un cassetto ora sta facendo qualcosa di utile.

Questa cosa mi gasa molto più del risparmio dei soldi in sé. Mi piace l'idea che l'hardware che possiedo possa continuare a essere mio anche quando il vendor ha smesso di interessarsene. Voglio poter cambiare software, rimuovere quello che non mi serve, usare una periferica in un modo non previsto e prendermi la responsabilità quando rompo tutto.

Zero vendor lock-in, per quanto possibile. Controllo totale, con tutti i problemi che comporta.

Non è ancora finita

Il port rimane incompleto. La gestione della batteria, per esempio, è ancora rotta a metà: il gauge espone capacità, tensione, corrente e temperatura, ma lo stack di charging non è completo e status può rimanere Unknown.

Se avessi davvero le competenze per lavorare a quel livello, probabilmente sarebbe la prossima cosa che proverei a sistemare. Per ora non le ho. E i token dell'AI, purtroppo, non sono infiniti.

Restano anche almeno due cose interessanti da approfondire: la modifica al device tree e il use-after-free che abbiamo osservato durante il teardown improvviso della scheda USB di rete. Vedremo se da questo esperimento uscirà davvero un contributo upstream.

Per ora mi basta sapere che tutto è iniziato con una domanda molto più stupida:

"Ma Marco non aveva ancora quel vecchio Redmi?"

E qualche giorno dopo quel Redmi stava girando Linux nativo, mostrava la sua dashboard, si regolava la luminosità da solo e prendeva rete e corrente dallo stesso dongle USB-C. Direi che siamo andati abbastanza lontano.