Nextcloud Self-Hosted: Il Salto da Setup Manuale a Infrastructure as Code

Link Progetto

Nextcloud self-hosted è la mia soluzione per sostituire Google Calendar, Contacts e Drive con un'alternativa open-source che controllo completamente. Deploy su Oracle Cloud Infrastructure usando il free tier (4 OCPU ARM, 24GB RAM - gratis per sempre).

Il problema: La prima versione funzionava, ma era fragile. Setup manuale con 50+ comandi, 1GB RAM che crashava, e soprattutto: zero garanzie che in caso di disaster potessi recuperare tutto.

La soluzione: Riscrivere l'intera infrastruttura con Infrastructure as Code (Terraform), aggiungere monitoring production-grade, implementare dual backup strategy, e testare ripetutamente il disaster recovery finché non potessi dire con certezza:
"Posso distruggere tutto e ricostruirlo in 10 minuti".

Questo articolo racconta il percorso da "pet server" curato manualmente a "cattle infrastructure" automatizzata, le decisioni architetturali chiave, le sfide affrontate, e cosa ho imparato nel processo.

Stack tecnico: Terraform, OCI, Docker compose, Nextcloud AIO, Borg Backup, Prometheus, Grafana, Caddy, DuckDNS, Cloud-init, Bash automation.

📖 Il Contesto: Dove Eravamo Rimasti

Nell' articolo di qualche giorno fa, vi avevo raccontato la mia prima esperienza con Nextcloud self-hosted. Era passata solo una settimana dal Linux Day e, piena di entusiasmo (e forse incoscienza), avevo deployato Nextcloud AIO su Oracle Cloud.

Spoiler: è stato un piccolo disastro.

Container che crashavano, sincronizzazioni sovrapposte dai vari dispositivi...notti passate a debuggare, e alla fine una soluzione minimale con solo 2 container per sopravvivere nei limiti di 1GB di RAM.

Ma funzionava. E per un paio di settimane è stata la mia soluzione.

---

🎯 Il Problema: Quando "Funziona" Non Basta

Dopo alcuni giorni di utilizzo quotidiano, ho iniziato a realizzare i limiti di quella soluzione "fatta a mano":

I Nodi Dolenti

1. Zero Disaster Recovery

  • Cosa succede se cancello l'istanza per sbaglio?
  • Come recupero i dati? Quanto tempo serve?
  • Spoiler: non lo sapevo. E questo mi terrorizzava.

2. Backup Artigianali

  • Script bash scritti di fretta
  • Path hardcoded ovunque
  • "Funziona sul mio PC"

3. Configurazione Manuale

  • Non so quante azioni manuali da eseguire

4. Scalabilità Zero

  • 1GB RAM = no monitoring, no extras
  • Impossibile aggiungere Grafana/Prometheus
  • "Se voglio aggiornare devo pregare"

Mi sono resa conto: avevo sostituito Google Calendar, ma avevo creato un "pet server" fragile che richiedeva cure manuali continue.

---

🏗️ La Visione: Infrastructure as Code

Volevo qualcosa di diverso. Non solo "far funzionare Nextcloud", ma costruire un'infrastruttura che fosse:

  • Riproducibile: `terraform apply` e in 10 minuti è online
  • Resiliente: posso distruggere e ricreare senza perdere dati
  • Documentata: il codice È la documentazione
  • Scalabile: aggiungere monitoring non deve far crashare tutto
  • Testabile: voglio SAPERE che il disaster recovery funziona

In pratica: passare da "pet server" a "cattle infrastructure".

---

🧠 Decisioni Architetturali Chiave

1. Terraform vs Ansible vs Manuale

La mia scelta: Terraform

Perché non manuale?

  • 50 comandi da ricordare? No grazie.

Perché non Ansible?

  • Ansible è imperativo: descrive "passi" da fare
  • Terraform è dichiarativo: descrive lo "stato finale"
  • Con Terraform: state drift detection automatico
  • (Momento super sincerità) Non ho ancora esplorato a fondo Ansible

Momento decisivo:

Quando ho scoperto che posso fare `terraform destroy` seguito da `terraform apply` e avere indietro l'intera infrastruttura in 10 minuti, ho capito che era la strada giusta.

2. Il Pattern "Pets vs Cattle"

Questo è stato il game changer mentale.

Prima (Pets):

┌─────────────────────┐
│ Istanza Unica       │ ← Se muore, panico totale
│ - OS                │
│ - Nextcloud         │
│ - TUTTI I DATI      │ ← Accoppiamento pericoloso
└─────────────────────┘

Dopo (Cattle + Pet):

┌─────────────────────┐
│ Istanza Compute     │ ← Cattle: ricreabile in 10 min
│ - OS                │
│ - Nextcloud         │
└────────┬────────────┘
         │ mount
         ↓
┌─────────────────────┐
│ Volume Persistente  │ ← Pet: protetto, mai distrutto
│ - Dati utente       │ prevent_destroy = true
│ - Database          │
│ - Backup Borg       │
└─────────────────────┘Code language: JavaScript (javascript)

La rivelazione: separare ciò che è ricreabile (compute) da ciò che deve sopravvivere (dati). Sembra ovvio, ma cambia tutto.

3. Monitoring Stack: Da Lusso a Necessità

Setup precedente: 1GB RAM, no monitoring, "speriamo funzioni"

Setup attuale: 24GB RAM gratuiti (ARM A1.Flex)

  • Prometheus: metriche sistema + container
  • Grafana: dashboard visuale
  • Node Exporter: CPU, RAM, disk, network
  • cAdvisor: metriche Docker real-time

Il valore: non più "è caduto tutto, aiuto!", ma "alert 2h prima che il disco si riempia".

---

🛠️ L'Implementazione: Le Fasi

Fase 1: Infrastructure as Code (Terraform)

Ho tradotto tutto il setup manuale in ~500 righe di Terraform:

resource "oci_core_instance" "nextcloud" {
  display_name        = "nextcloud-prod"
  availability_domain = data.oci_identity_availability_domain.ad.name
  compartment_id      = var.compartment_ocid
  shape               = "VM.Standard.A1.Flex"  # 4 OCPU, 24GB RAM, FREE!

  # cloud-init: installa Docker, firewall, deploy stack
  metadata = {
    user_data = base64encode(file("cloud-init.yaml"))
  }
}Code language: PHP (php)

Cloud-init: 150 righe YAML che automatizzano:

  • Sistema (updates, packages, firewall)
  • Docker + Docker Compose
  • DuckDNS + Caddy + Nextcloud
  • Prometheus + Grafana

Risultato: `terraform apply` e dopo ~8 minuti ho Nextcloud + monitoring funzionante, SSL incluso.

Fase 2: Backup Strategy Duale

Ho imparato che servono DUE tipi di backup:

1. Borg Backup (System-level)

Location: /mnt/nextcloud-data/borg-backups/  # Sul volume persistente!
Schedule: Daily 04:00 UTC
Retention: 7 giorni
Encryption: YesCode language: HTTP (http)

2. Export Leggibile (Data portability)

Location: ~/nextcloud-exports/ (PC locale)
Schedule: Weekly
Formato: .ics (calendari), .vcf (contatti)
Scopo: Import in altri dispositivi se serveCode language: HTTP (http)

Fase 2.5: Il Superpotere degli Script Shell 🚀

E qui arriva la parte che mi ha fatto innamorare di questo progetto: lo script `local-backup-sync.sh`.

Non è solo "uno script di backup". È un esempio perfetto di quanto potere ci sia in poche centinaia di righe di Bash.

Il problema che risolve:

  • Borg backups sono encrypted sul server OCI
  • Come li sincronizzo sul mio PC senza sbattermi?
  • Come verifico l'integrità senza fare tutto a mano?
  • Come estraggo i file quando serve?

La magia dello script:

# Uso interattivo - ti guida passo passo
./local-backup-sync.sh

# Automazione completa - perfetto per cron
./local-backup-sync.sh --sync-only

# Solo estrazione ultimo backup
./local-backup-sync.sh --extract-onlyCode language: PHP (php)

Cosa fa in automatico*(e qui mi stupisco ogni volta):

1. rsync incrementale intelligente

# Solo le differenze, non riscarica tutto!
   rsync -avzh --delete \
     -e "ssh -i ~/.ssh/key" \
     server:/mnt/nextcloud-data/borg-backups/ \
     ~/nextcloud-backups/Code language: PHP (php)

2. Verifica integrità automatica

  # Controlla che i backup non siano corrotti
  borg check ~/nextcloud-backups/Code language: PHP (php)

3. Lista backup con metadati

  # Mostra tutti i backup disponibili con date, dimensioni, stats
  borg list ~/nextcloud-backups/Code language: PHP (php)

4. Statistiche del repository

   # Quanto spazio risparmio con deduplica? Quanto è compresso?
   borg info ~/nextcloud-backups/Code language: PHP (php)

5. Estrazione interattiva intelligente

  • Identifica automaticamente il backup più recente
  • Chiede conferma prima di sovrascrivere
  • Sistema i permessi automaticamente (`chown`)
  • Gestisce directory esistenti

6. Logging completo

  • Ogni operazione loggata
  • Timestamp, exit codes, errori
  • Output colorato per scannerizzazione veloce

Ma la cosa più bella? Una volta configurato con cron poi te ne dimentichi. Ogni domenica alle 22:00, silenziosamente:

  • Sincronizza i backup dal server
  • Verifica l'integrità
  • Logga tutto
  • Se qualcosa va storto, lo trovi nel log

Perché mi entusiasma così tanto?

Perché è l'essenza del buon scripting:

  • DRY: scritto una volta, usato ovunque
  • Idempotente: posso eseguirlo 100 volte, fa sempre la cosa giusta
  • Self-documenting: le opzioni `--help` spiegano tutto
  • Fail-safe: controlla errori, non rompe nulla
  • Automatable: perfetto per cron, ma anche usabile manualmente

Il potere degli script shell è proprio questo: prendere operazioni complesse, ripetitive e prone-to-error, e renderle:

  • Automatiche
  • Affidabili
  • Documentate nel codice stesso
  • Riproducibili

E quando funziona così bene che te ne dimentichi? Quella è la vera automazione. 🎯

Fase 3: Disaster Recovery Testing

Qui è dove molti progetti "production" falliscono: testare veramente il disaster recovery.

Il test:

terraform state pull > before.json
borg list /mnt/nextcloud-data/borg-backups/

# 2. DISTRUGGI TUTTO (solo compute, non volume)
terraform destroy -target=oci_core_instance.nextcloud

# 3. Ricrea da zero
terraform apply

# 4. Verifica dati intatti
# Login Nextcloud → Tutti i file presenti ✅
# Calendari sincronizzati ✅
# Backup Borg ancora lì ✅Code language: PHP (php)

Risultati dopo 3 test completi:

  • ✅ Recovery time: ~10 minuti
  • ✅ Data loss: 0 byte
  • ✅ Confidence level: 100%

Lezione fondamentale: Se non l'hai testato, non funziona.

---

Convincermi a "Distruggere Tutto"

Problema emotivo:

Fare `terraform destroy` sulla mia produzione attiva mi terrorizzava.

**La paura**:

  • "E se i backup sono corrotti?"
  • "E se dimentico qualcosa?"
  • "E se ho hardcoded qualcosa che non ricordo?"

La soluzione:

  1. Primo test su istanza separata
  2. Backup offline sul PC prima di destroy
  3. Screenshot di tutto
  4. YOLO(You Only Live Once!) e destroy 🚀

Risultato:

Dopo il primo test riuscito, ho fatto altri 2 cicli per validare.

Ora dormo tranquilla sapendo di poter ricostruire tutto in 10 minuti.

---

📊 Prima vs Dopo: I Numeri

MetricaSetup InizialeSetup Attuale
Deployment Time~2 ore manuali10 minuti automatici
RAM Disponibile1GB (cramming)24GB (comfortable)
Monitoring❌ Niente✅ Prometheus + Grafana
Disaster Recovery❌ "Speriamo bene"✅ Testato 3 volte
Backup Automation⚠️ Script fragili✅ Dual strategy + integrity checks
Documentation⚠️ Sparsa✅ Codice IS documentazione
Confidence Level😰 Ansia costante😎 Tranquillità
Infrastructure Cost$0/mese$0/mese (yay free tier!)

---

📌 Quick note sul pattern "Pets vs Cattle":

  • Pets 🐶: Server trattati come animali domestici (nomi, cure manuali, se muoiono → panico)
  • Cattle 🐄: Server trattati come bestiame (numerati, automatizzati, se muoiono → rimpiazzati automaticamente)

Il trick: separare ciò che è ricreabile (compute = cattle) da ciò che deve sopravvivere (dati = pet protetto).


💭 Riflessioni: Cosa Ho Imparato

1. Infrastructure as Code Non è "Nice to Have"

Prima pensavo: "IaC serve solo per le grandi aziende"

Ora so: Anche per un progetto personale, la capacità di distruggere e ricreare l'infrastruttura in minuti vale ogni riga di Terraform scritta.

2. "Pets vs Cattle" è un Mindset, Non una Tecnica

Il vero cambio mentale è stato separare:

  • Ciò che posso permettermi di perdere (compute)
  • Ciò che non posso perdere MAI (dati)

Una volta capito questo, le decisioni architetturali diventano ovvie.

3. Testare il Disaster Recovery è Come l'Assicurazione

Sembra una perdita di tempo finché non ne hai bisogno. Poi capisci che è l'unica cosa che conta.

4. Gli Script Shell Sono Superpotenze Sottovalutate

Per automazione di sistema, pochi tool battono uno script shell ben scritto:

  • Zero dipendenze (bash è ovunque)
  • Perfetto per orchestrare altri tool (rsync, borg, ssh)
  • Facile da debuggare (esegui riga per riga)
  • Immediato da modificare (niente compilazione)

Il vero potere: prendere task complessi e renderli "fire and forget".

5. La Documentazione è un Debito Continuo

Non basta scriverla una volta. Deve evolvere col codice.

6. Il Fallimento Iniziale Era Necessario

Senza l'esperienza del primo setup "fatto a mano" con 1GB RAM e crash continui, non avrei apprezzato il valore di un'architettura ben pensata.

A volte devi toccare il ferro caldo per imparare.

---

🔮 Next Steps: Cosa Manca

Nonostante i progressi, ci sono ancora aree da migliorare:

1. Alerting Automatico

Status: ⚠️ Monitoring passivo

Goal: Alertmanager + notifiche Telegram

  • Alert se CPU > 80% per 5 minuti
  • Alert se disco > 85%
  • Alert se backup fallisce

2. Off-site Backup su Object Storage

Status: ⚠️ Backup solo su volume OCI

Goal: Sync automatico su OCI Object Storage

  • 10GB free tier disponibile
  • Vera separazione geografica
  • Protection contro delete accidentale volume

3. CI/CD Pipeline Testing

Status: ✅ GitHub Actions per validation

Goal Futuro: Test automatici disaster recovery

  • Nightly deploy su istanza test
  • Restore backup + verifica integrità
  • Report automatico

---

🎯 Conclusioni: Il Viaggio Continua

Due settimane fa scrivevo:

> "Self-hosting is hard. But it's worth it."

Oggi aggiungo:

> "Infrastructure as Code makes self-hosting sustainable."

Non basta far funzionare qualcosa. Serve costruire sistemi che:

  • Sopravvivono al tempo
  • Sopravvivono agli errori umani
  • Sopravvivono alla tua memoria a breve termine

Questo progetto mi ha insegnato che l'obiettivo non è "deployare Nextcloud", ma costruire un sistema resiliente che possa evolvere, rompersi, e auto-ripararsi.

E soprattutto: che posso distruggere e ricostruire in 10 minuti mentre bevo un caffè. ☕

Per i curiosi*

P.S. Se state considerando di fare self-hosting, il mio consiglio è: iniziate semplice (come ho fatto io), rompete tutto (come ho fatto io), e poi ricostruite bene (come sto facendo ora).

Il fallimento è il miglior teacher. 🚀

Related Projects

Marzo 18, 2025
Averna Spazio Open

• Sviluppo del sito web di Averna Spazio Open utilizzando WordPress, con Oxygen Builder per un design personalizzato e Advanced Custom Fields (ACF) per la gestione dinamica del contenuto. • Creato un sistema di invio di idee degli utenti, che venivano pubblicate sul sito, con una funzione di voto per selezionare l’idea migliore annualmente. • […]

Maggio 1, 2025
NutriCHOice - Sistema multi-agente

Introduzione al Progetto NutriCHOice rappresenta un'innovativa soluzione nell'ambito della nutrizione personalizzata, sviluppata come progetto finale del Bootcamp AI di Edgemony. Il sistema utilizza un approccio "Generate then Fix" (Genera e Correggi) per creare ricette personalizzate che rispettano specifici obiettivi nutrizionali, con particolare attenzione al contenuto di carboidrati (CHO). Evoluzione del Progetto: Da RAG a "Generate […]

veronicaschembri
Copyright © Veronica Schembri

Privacy Policy
Cookie Policy
💬