SSD Nodes Learn 🎉 VPS da $5.50/mese
Guide Matt ConnorDi Matt Connor

Gestione log self-hosted su un solo VPS

Confronta journald, logrotate, Loki e OpenSearch su un solo VPS: scopri RAM minima, ricerca full text e regole di retention prima di archiviare i log.

Qual è il costo reale della gestione dei log self-hosted su un solo VPS

La gestione dei log self-hosted su un solo VPS (virtual private server) si riduce a una domanda: serve un cluster di ricerca oppure bastano la rotazione e grep? La maggior parte delle guide dei vendor parte da tre nodi e 12 GB di RAM, prima ancora di inviare una singola riga di log. Su un solo server, questa risposta non è utile. Il confronto seguente indica quindi cosa richiede ciascuna soluzione da una macchina con risorse limitate, prima di poter archiviare qualsiasi dato.

Se gestisci uno o due server e vuoi sapere cosa è successo martedì scorso, systemd-journald e logrotate svolgono già questo compito. Puoi quindi fermarti dopo la sezione successiva. Se invece più macchine devono inviare i log a un unico punto, con la possibilità di eseguire ricerche su diverse settimane, Grafana Loki è adatto a una macchina con risorse limitate, perché indicizza le label e non il testo delle righe. Elasticsearch e OpenSearch offrono una vera ricerca full text, ma richiedono più memoria, perché l'heap della JVM (Java virtual machine) ha una dimensione minima che non può essere ridotta ulteriormente.

Inizia da journald: nella maggior parte dei casi è sufficiente

systemd-journald è già in esecuzione su qualsiasi server Ubuntu o Debian attuale. Acquisisce l’output standard di ogni unità di servizio, i messaggi del kernel e tutto ciò che viene inviato a syslog. Quattro comandi coprono la maggior parte degli incidenti.

journalctl -u nginx.service --since "2026-08-14 09:00" --until "2026-08-14 10:00"
journalctl -p err -b
journalctl -f -u ssh.service
journalctl --disk-usage

L’ultimo stampa una riga come Archived and active journals take up 1.1G in the file system.. Questo è il valore che determina se serve intervenire ulteriormente. Se indica alcune centinaia di megabyte e riesci a trovare ciò che ti serve con -u e --since, hai terminato.

La sopravvivenza del journal a un riavvio dipende da Storage= e dall’esistenza di /var/log/journal. Con l’impostazione comune Storage=auto, journald scrive in /var/log/journal quando quella directory è presente e in /run/log/journal quando non lo è. /run risiede in memoria, quindi su un sistema senza quella directory tutti i log vengono cancellati al riavvio, cioè proprio nel momento in cui potresti volerli consultare. Le immagini Ubuntu includono la directory. Le immagini minimali e basate su container spesso non la includono.

ls -d /var/log/journal
sudo mkdir -p /var/log/journal
sudo systemctl restart systemd-journald
journalctl --disk-usage

Dopo il riavvio, journalctl --disk-usage dovrebbe riportare una dimensione inferiore a /var/log/journal, non a /run. I valori predefiniti sono già limitati. Questo è il motivo principale per cui journald è una soluzione adeguata e non un ripiego. La pagina man di journald.conf imposta SystemMaxUse= al 10% delle dimensioni del file system e SystemKeepFree= al 15%, limitando ogni valore predefinito calcolato a 4G. SystemMaxFileSize= ha come valore predefinito un ottavo di SystemMaxUse=, con un limite di 128M. In genere vengono quindi conservati sette file ruotati. MaxRetentionSec= ha come valore predefinito 0, che disabilita l’eliminazione basata sull’età. Rileggi quest’ultimo valore predefinito: nella configurazione iniziale il journal è limitato soltanto dalle dimensioni, mai dall’età.

[Journal]
Storage=persistent
SystemMaxUse=2G
MaxRetentionSec=30day

Scrivi il valore in /etc/systemd/journald.conf.d/99-size.conf, riavvia journald, quindi verifica che journalctl --disk-usage si sia spostato verso il nuovo limite massimo. Per recuperare subito spazio, senza attendere la rotazione successiva, esegui sudo journalctl --vacuum-size=500M o sudo journalctl --vacuum-time=14d. Entrambi mostrano ogni file rimosso, quindi un’esecuzione senza output indica che non c’era nulla da eliminare.

Tutto ciò che non rientra nel journal, come /var/log/nginx/access.log, è gestito da logrotate, che viene eseguito ogni giorno da un timer systemd. È utile conoscere un caso di errore perché può sembrare un problema di df. Dopo una rotazione, il vecchio file scompare dall’elenco della directory mentre il demone continua a tenerlo aperto. Di conseguenza df -h segnala che il disco è pieno, mentre du -sh /var/log riporta un valore molto inferiore. Lo spazio torna disponibile solo quando il processo riapre il log. A questo serve la riga di reload postrotate nella configurazione. sudo lsof -nP +L1 elenca i file eliminati che sono ancora aperti e indica il processo che mantiene aperto ciascuno di essi. Verifica una regola senza apportare modifiche usando sudo logrotate -d /etc/logrotate.d/nginx.

Inviare i log da più server a un unico collector

Quando i server sono più di uno, gestire più server Linux contemporaneamente diventa più semplice se i relativi log arrivano in un unico punto. rsyslog è già installato nella maggior parte delle distribuzioni, quindi il collector centralizzato più semplice consiste in un file su ogni server mittente.

*.* action(type="omfwd" target="logs.example.com" port="514" protocol="tcp")

Salvare il contenuto in /etc/rsyslog.d/50-forward.conf, verificarlo con sudo rsyslogd -N1, che convalida la configurazione ed esce senza avviare nulla, quindi riavviare rsyslog. Sul collector, abilitare l'input TCP.

module(load="imtcp")
input(type="imtcp" port="514")

Due avvertenze, entrambe di natura pratica. Il syslog in chiaro non offre cifratura né autenticazione, quindi qualsiasi host che possa raggiungere la porta 514 può iniettare righe di log apparentemente identiche alle vostre. Vincolare il servizio a una rete privata o a una VPN e filtrare la porta con il firewall. Inoltre, la coda dell'azione predefinita risiede in memoria. Quando il collector non è raggiungibile, la coda si riempie e i messaggi vengono scartati senza conservarne una copia. Per questo caso, rsyslog documenta una coda assistita da disco nel tutorial sull'inoltro affidabile.

Perché lo stack ELK non è adatto a un VPS di piccole dimensioni

ELK indica Elasticsearch per l'archiviazione e la ricerca, Logstash per la pipeline di acquisizione e Kibana per l'interfaccia. Il limite minimo è rappresentato dall'heap della JVM, che viene impostato prima dell'arrivo dei log.

La documentazione di Elastic indica di impostare l'heap a non più del 50% della memoria totale disponibile per ogni nodo Elasticsearch, perché il processo usa anche buffer off-heap e dipende dalla cache dei file del sistema operativo per leggere rapidamente i file degli indici. Quindi un heap da 2 GB richiede una macchina da 4 GB, prima di considerare Kibana e il carico per cui il server è stato acquistato. Elastic specifica inoltre che Elasticsearch dimensiona automaticamente l'heap in base ai ruoli del nodo e alla memoria totale. Di conseguenza, una macchina con poche risorse ottiene un heap ridotto e trascorre gran parte del tempo eseguendo la garbage collection.

Logstash è il componente che rende subito insostenibile il consumo di memoria su un server piccolo. La pagina di Elastic dedicata alle impostazioni della JVM raccomanda, per una pipeline di acquisizione tipica, un heap non inferiore a 4GB e non superiore a 8GB. Su un VPS da 4 GB, questo equivale all'intera memoria disponibile per un solo processo nel punto centrale della pipeline.

ChartDocumented JVM heap settings, from each project's own docs
The data behind this chart
[
  {
    "label": "Loki plus Alloy (no JVM)",
    "documented_heap_mb": 0
  },
  {
    "label": "OpenSearch demo compose",
    "documented_heap_mb": 512
  },
  {
    "label": "OpenSearch production example",
    "documented_heap_mb": 2048
  },
  {
    "label": "Logstash recommended minimum",
    "documented_heap_mb": 4096
  }
]

Questi sono i valori pubblicati da ciascun progetto nella propria documentazione. Non sono misurazioni eseguite su una macchina di test e il carico di lavoro può modificarli. Il file compose di esempio di OpenSearch imposta 512 MB per nodo nella configurazione dimostrativa e 2048 MB nell'esempio per la produzione, mentre il limite inferiore raccomandato per Logstash è 4096 MB. La colonna dell'heap riporta 0 per Loki e Alloy perché sono programmi Go e non devono riservare un heap JVM. Questa è l'intera differenza espressa da un singolo numero: un componente basato sulla JVM riserva quella quantità di memoria indipendentemente dall'arrivo dei log.

Se vuoi comunque usare lo stack Elastic su un unico server piccolo, elimina Logstash e invia i dati direttamente a Elasticsearch tramite un collector leggero. Logstash serve per analizzare e trasformare grandi volumi di dati. Su una singola macchina puoi eseguire queste operazioni all'origine oppure ometterle.

Sia Elasticsearch sia OpenSearch richiedono inoltre di aumentare vm.max_map_count a 262144, perché usano il memory mapping per i file degli indici e il limite predefinito di Linux è troppo basso. Se un container termina pochi secondi dopo l'avvio su una macchina appena configurata, nella maggior parte dei casi la causa è questa.

OpenSearch o Elasticsearch: quale puoi distribuire?

Una breve cronologia delle licenze, perché determina ciò che puoi eseguire. A gennaio 2021 Elastic ha spostato Elasticsearch e Kibana da Apache 2.0 a un modello doppio basato su SSPL (Server Side Public License) ed Elastic License 2.0. AWS ha creato un fork dell'ultimo codice Apache 2.0 e lo ha chiamato OpenSearch, che resta sotto Apache 2.0. A settembre 2024 Elastic ha aggiunto AGPLv3 (GNU Affero General Public License versione 3) come ulteriore opzione per il codice sorgente gratuito. Se esegui il self-hosting per una sola persona su un unico VPS, tutte queste licenze consentono ciò che stai facendo. Le licenze diventano rilevanti quando offri il software ad altre persone come servizio gestito.

Su un server di piccole dimensioni, la differenza pratica è più contenuta di quanto suggerisca la cronologia, perché sotto il cofano entrambi usano lo stesso motore. Cambiano i nomi: in OpenSearch la gestione del ciclo di vita degli indici è ISM (index state management), mentre in Elasticsearch è ILM (index lifecycle management). Ad agosto 2026, OpenSearch 2.12 e versioni successive rifiutano di avviarsi se alla prima esecuzione non è stata impostata una password amministrativa.

sudo sysctl -w vm.max_map_count=262144
printf 'vm.max_map_count = 262144\n' | sudo tee /etc/sysctl.d/99-opensearch.conf
docker run -d -p 9200:9200 -p 9600:9600 -e "discovery.type=single-node" \
  -e "OPENSEARCH_INITIAL_ADMIN_PASSWORD=<custom-admin-password>" \
  opensearchproject/opensearch:latest

La riga sysctl -w applica subito l'impostazione, mentre il file in /etc/sysctl.d/ contiene la parte che resta dopo un riavvio. Verifica che il container sia stato avviato con curl -k -u admin:<password> https://localhost:9200. Risponde tramite https usando un certificato dimostrativo, quindi -k salta la verifica; una risposta corretta è un piccolo blocco JSON che indica il cluster e la versione. La pagina di installazione di OpenSearch specifica inoltre agli utenti di Docker Desktop di assegnare all'host almeno 4 GB di memoria. È un'indicazione ragionevole delle risorse che il processo si aspetta di avere.

Come Loki rimane leggero: le label invece di un indice full-text

Loki mantiene un unico indice sulle label e memorizza le righe di log in chunk compressi. Una query seleziona prima gli stream e filtra il testo in un secondo momento. {unit="ssh.service"} |= "Failed password" seleziona lo stream in base alla label, quindi cerca la stringa in quei chunk. Il contenuto delle righe non viene indicizzato, quindi l’ingestione rimane economica e non è necessario mantenere in memoria un indice inverso. Il costo si sposta sul momento della query. È un compromesso vantaggioso quando normalmente si sa quale servizio si sta analizzando.

La documentazione di Grafana indica la modalità monolitica, cioè l’esecuzione dell’intero Loki in un unico processo con -target=all, per volumi di lettura e scrittura ridotti, fino a circa 20GB al giorno. Un singolo VPS rientra ampiamente in questo limite.

Il rischio principale è la cardinalità delle label. Ogni combinazione distinta di valori delle label costituisce uno stream. Il numero di stream determina la memoria utilizzata da Loki e le dimensioni dell’indice. Una label che contiene l’indirizzo IP di un client o un identificativo della richiesta crea uno stream per ogni valore. Un server web sotto carico può quindi produrre decine di migliaia di stream in un giorno e il processo continua a crescere finché il kernel lo arresta. Limitare le label a valori che si potrebbero contare su carta: unit, host, job, level. Inserire i dati variabili direttamente nella riga, dove un’espressione di filtro può individuarli al momento della query.

Installare Loki e Alloy su un singolo VPS

Due processi svolgono il lavoro. Loki memorizza i log e risponde alle query. Grafana Alloy legge i log e li invia. In precedenza il componente di invio era Promtail, che ha raggiunto il fine vita il 2 marzo 2026. Le nuove installazioni usano quindi Alloy e l'esempio Docker fornito da Loki include ora una configurazione per Alloy.

wget https://raw.githubusercontent.com/grafana/loki/v3.7.0/cmd/loki/loki-local-config.yaml -O loki-config.yaml

Leggere quel file prima di usarlo. Imposta path_prefix: /tmp/loki con i chunk sotto /tmp/loki/chunks, una configurazione corretta per una demo ma non per un server: nulla di ciò che si trova sotto /tmp del container sopravvive alla ricreazione del container, quindi la cronologia scompare al successivo aggiornamento dell'immagine. Configurarlo invece su un percorso montato.

common:
  instance_addr: 127.0.0.1
  path_prefix: /loki
  storage:
    filesystem:
      chunks_directory: /loki/chunks
      rules_directory: /loki/rules
  replication_factor: 1
  ring:
    kvstore:
      store: inmemory
docker volume create loki-data
docker run --name loki -d \
  -v $(pwd):/mnt/config -v loki-data:/loki \
  -p 127.0.0.1:3100:3100 \
  grafana/loki:3.7.0 -config.file=/mnt/config/loki-config.yaml
curl -s -o /dev/null -w '%{http_code}\n' http://127.0.0.1:3100/ready

L'ultimo comando dovrebbe stampare 200, perché /ready restituisce HTTP 200 quando Loki è pronto ad accettare traffico. Qualsiasi altro risultato indica che il processo è ancora in avvio oppure che la configurazione è stata rifiutata; docker logs loki indica quale delle due condizioni si è verificata. Due dettagli del comando di avvio sono intenzionali. La porta è pubblicata soltanto su 127.0.0.1, perché la configurazione di esempio contiene auth_enabled: false e Loki non include una propria autenticazione. Di conseguenza, chiunque possa raggiungere la porta 3100 può leggere tutti i log e scriverne di falsi. Lasciarla in ascolto su loopback oppure dietro una VPN o un reverse proxy con autenticazione. Il volume denominato è importante perché l'immagine viene eseguita dall'utente loki con UID 10001. Una directory host montata con bind e di proprietà di root non è quindi scrivibile dal container.

sudo apt-get update && sudo apt-get install -y gpg wget
sudo mkdir -p /etc/apt/keyrings/
sudo wget -O /etc/apt/keyrings/grafana.asc https://apt.grafana.com/gpg-full.key
echo "deb [signed-by=/etc/apt/keyrings/grafana.asc] https://apt.grafana.com stable main" \
  | sudo tee /etc/apt/sources.list.d/grafana.list
sudo apt-get update
sudo apt-get install -y alloy

Alloy legge /etc/alloy/config.alloy. Questa configurazione acquisisce il journal di sistema e un insieme di file, quindi invia entrambi al Loki locale.

loki.write "local" {
  endpoint {
    url = "http://127.0.0.1:3100/loki/api/v1/push"
  }
}

loki.relabel "journal" {
  forward_to = []
  rule {
    source_labels = ["__journal__systemd_unit"]
    target_label  = "unit"
  }
}

loki.source.journal "read" {
  forward_to    = [loki.write.local.receiver]
  relabel_rules = loki.relabel.journal.rules
  labels        = {job = "systemd-journal", host = "app-01"}
}

local.file_match "nginx" {
  path_targets = [{"__path__" = "/var/log/nginx/*.log", "job" = "nginx", "host" = "app-01"}]
}

loki.source.file "nginx" {
  targets    = local.file_match.nginx.targets
  forward_to = [loki.write.local.receiver]
}

La regola di relabeling copia il campo del journal __journal__systemd_unit in un'etichetta denominata unit. È questo che consente di usare {unit="ssh.service"} in seguito. Senza questa regola, il nome dell'unità si trova all'interno dell'entry anziché in un'etichetta. Non è quindi possibile selezionarlo e ogni query deve analizzare tutto il contenuto.

sudo systemctl reload alloy
systemctl show -p User alloy
sudo journalctl -n 5
sudo -u alloy journalctl -n 5

È in questo punto che la maggior parte delle configurazioni si blocca. Alloy viene eseguito con un proprio account di servizio, non come root. Per leggere il journal di sistema è necessario appartenere al gruppo systemd-journal, mentre su Debian e Ubuntu i file sotto /var/log/nginx appartengono al gruppo adm. Sostituire nell'ultimo comando l'account stampato da systemctl show. Se restituisce un numero di entry molto inferiore rispetto all'esecuzione come root, quell'account non può leggere il journal di sistema. Loki resterà quindi vuoto, anche se la configurazione è corretta. Aggiungere i gruppi e riavviare con sudo usermod -aG systemd-journal,adm alloy seguito da sudo systemctl restart alloy.

curl -G -s "http://127.0.0.1:3100/loki/api/v1/query_range" \
  --data-urlencode 'query={job="systemd-journal"}' \
  --data-urlencode 'limit=5' | jq '.data.result | length'

Un numero superiore a 0 indica che esistono stream con quell'etichetta e che contengono entry. 0 indica che finora non è arrivato nulla con quell'etichetta. Un'impostazione predefinita spiega un falso allarme comune: loki.source.journal imposta max_age su 7h, quindi un avvio pulito legge le ultime sette ore del journal e nessun dato precedente. Per un'interfaccia grafica, eseguire Grafana sullo stesso host e configurare una sorgente dati Loki su http://127.0.0.1:3100.. I log dei container richiedono una sorgente diversa: Alloy rileva i container Docker in esecuzione e ne acquisisce i log, come nell'esempio introduttivo fornito da Loki. In un cluster k3s a nodo singolo su un VPS, quel job utilizza invece la directory dei log dei pod in cui scrive kubelet.

Conservazione: scegli quando eliminare i log

Quasi nessuno sceglie un periodo di conservazione finché il disco non si riempie. A quel punto la decisione viene presa alle 3 del mattino, con il servizio non disponibile. Definiscilo il primo giorno rispondendo a due domande: quanto indietro nel tempo consulti davvero i log e quali dati devi ancora avere durante un'analisi dell'incidente il mese prossimo. Per un singolo server, da 14 a 30 giorni copre entrambe le esigenze.

Loki non elimina nulla finché non abiliti il compactor. La conservazione è disabilitata per impostazione predefinita. Questo sorprende chi si ritrova il volume pieno mentre retention_period resta nella configurazione senza produrre alcun effetto.

limits_config:
  retention_period: 744h

compactor:
  working_directory: /loki/retention
  compaction_interval: 10m
  retention_enabled: true
  retention_delete_delay: 2h
  retention_delete_worker_count: 150
  delete_request_store: filesystem

744h corrispondono a 31 giorni. Quattro regole documentate governano quel blocco:

  • La conservazione viene applicata dal compactor e la documentazione di Grafana indica di eseguire il compactor come istanza singola. Su un singolo VPS questo avviene automaticamente.
  • Il periodo minimo di conservazione è 24h e la conservazione funziona solo quando il periodo dell'indice è 24h. L'esempio schema_config usa già period: 24h, quindi lascialo invariato.
  • delete_request_store è obbligatorio quando retention_enabled è true. Indica lo store che contiene le richieste di eliminazione. In un nodo singolo basato su filesystem corrisponde a object_store: filesystem, già presente nello schema.
  • I chunk vengono prima contrassegnati e rimossi dopo retention_delete_delay, che in questo caso è 2h. Di conseguenza, lo spazio libero torna disponibile più tardi di quanto suggerisca la policy. Non valutare l'impostazione in base a df cinque minuti dopo un reload.

OpenSearch elimina interi indici, non singole righe. Per questo gli indici dei log vengono creati ogni giorno. Una policy ISM fa avanzare un indice tra diversi stati e lo elimina quando raggiunge l'età prevista. Un ism_template associa la policy ai nuovi indici, così non devi ricordartene ogni volta.

Policy ISM che elimina gli indici dei log dopo 14 giorni
{
  "policy": {
    "description": "delete log indexes after 14 days",
    "default_state": "hot",
    "states": [
      {
        "name": "hot",
        "actions": [],
        "transitions": [
          { "state_name": "delete", "conditions": { "min_index_age": "14d" } }
        ]
      },
      {
        "name": "delete",
        "actions": [ { "delete": {} } ],
        "transitions": []
      }
    ],
    "ism_template": { "index_patterns": ["logs-*"], "priority": 100 }
  }
}

Creala con una richiesta PUT a _plugins/_ism/policies/logs-retention. Il template si applica agli indici creati dopo l'esistenza della policy. Gli indici già presenti sul disco devono quindi ricevere la policy manualmente.

Qualunque sistema tu utilizzi, un valore di conservazione è efficace solo quanto il controllo dello spazio libero che lo accompagna. Eliminare i log dopo 14 giorni non risolve il problema se 10 giorni di log hanno già riempito il volume. Associa quindi la policy a monitoraggio dello stato del disco su un VPS e configura un avviso all'80% di utilizzo.

Quanto spazio su disco serve per 1 GB di log

La risposta corretta dipende dalle righe e dai campi presenti nei log. Misura quindi il consumo sui tuoi dati, invece di affidarti a un rapporto pubblicato. I meccanismi sono abbastanza diversi da permettere di prevedere la direzione della variazione. OpenSearch ed Elasticsearch scrivono un indice invertito per ogni campo indicizzato, oltre al documento memorizzato. Lo spazio su disco occupato è quindi maggiore rispetto al testo non elaborato e ogni replica lo moltiplica. Su un singolo nodo imposta il numero di repliche su 0, perché uno shard di replica sullo stesso nodo non può sopravvivere al guasto di quel nodo. Lasciarlo impostato su 1 raddoppia lo spazio su disco e mantiene lo stato del cluster su yellow in modo permanente. Loki scrive chunk compressi e un indice di piccole dimensioni per le label. Il suo ingombro segue quindi la dimensione compressa delle righe.

sudo du -sh /var/lib/docker/volumes/loki-data/_data
curl -k -u admin:<password> "https://localhost:9200/_cat/indices?v&h=index,docs.count,store.size"

Esegui il metodo applicabile per 2 giorni consecutivi. La differenza rappresenta la crescita giornaliera. Moltiplicala per il numero di giorni di conservazione, aggiungi circa il 30% di margine per compaction e merge, quindi confronta il risultato con lo spazio disponibile sul volume. Se lo spazio non è sufficiente, riduci prima il periodo di conservazione invece di acquistare altro spazio su disco: un volume più grande rimanda lo stesso problema soltanto di alcune settimane.

Cosa si rompe per primo su un server di piccole dimensioni

La memoria è la prima risorsa a esaurirsi. Il killer OOM (out of memory) del kernel seleziona un processo di grandi dimensioni e, su un server dedicato ai log, il processo più grande è la JVM. journalctl -k | grep -i "killed process" mostra l'evento di terminazione con il nome del processo tra parentesi quadre. Il processo terminato non è sempre quello dello stack di logging: può essere scelto anche sshd o il database. È così che un esperimento di logging può arrestare l'applicazione da cui si volevano ottenere i log. Imposta limiti massimi espliciti per i container, in modo che l'errore si verifichi nel punto stabilito. È questo lo scopo dei limiti di memoria in Docker Compose.

Il disco è la seconda risorsa a esaurirsi e i motori di ricerca falliscono in modo specifico e riconoscibile. Elasticsearch e OpenSearch monitorano l'utilizzo del disco a diversi livelli. La soglia bassa è all'85% e quella alta al 90%. Alla soglia di inondazione del 95%, ogni indice con uno shard su quel nodo riceve il blocco index.blocks.read_only_allow_delete e le scritture falliscono con blocked by: [FORBIDDEN/12/index read-only / allow delete (api)]. Il blocco viene rimosso quando l'utilizzo torna sotto la soglia alta. Libera prima spazio, quindi rimuovi il blocco manualmente solo se persiste.

curl -k -u admin:<password> -X PUT "https://localhost:9200/_all/_settings" \
  -H 'Content-Type: application/json' \
  -d '{"index.blocks.read_only_allow_delete": null}'

Loki fallisce in modo meno evidente. Non dispone di una modalità di sola lettura, quindi un volume pieno si manifesta con push non riusciti sul mittente e lacune nei risultati delle query. Il problema della cardinalità si manifesta invece come un aumento lento della memoria, non come un errore. Controlla periodicamente la dimensione della directory chunks, senza aspettare un incidente.

L'ultimo problema consiste nell'inserire dati non adatti. Un sistema di log non è un sistema di metriche: il carico della CPU campionato ogni 10 secondi e memorizzato come testo è costoso da conservare e difficile da rappresentare nei grafici. Questo compito appartiene a strumenti come un server di monitoraggio Zabbix su Ubuntu 24.04. Le eccezioni delle applicazioni richiedono raggruppamento, deduplicazione e una vista dello stack trace. Questo è il compito di un sistema self-hosted per il monitoraggio degli errori. Sapere che il sito è inattivo è ancora un compito distinto, gestito da una pagina di uptime e stato come Uptime Kuma. Usa il sistema di log per le righe di testo che una persona deve leggere.

FAQ

Devo usare Elasticsearch per cercare nei log del server?

Non per uno o due server. journalctl filtra già per unità, priorità, boot e intervallo di tempo, mentre i file ruotati rispondono a grep e zgrep. Un cluster di ricerca giustifica il consumo di memoria quando si gestiscono molti computer, quando serve una ricerca full-text su tutti i sistemi contemporaneamente oppure quando più persone hanno bisogno di un'interfaccia condivisa. Al di sotto di queste esigenze, journald con un limite di dimensione e un periodo di conservazione svolge lo stesso lavoro senza richiedere RAM aggiuntiva.

Quanta RAM serve per gestire i log in self-hosting?

Usa i valori pubblicati da ciascun progetto invece di una regola generale. Loki e Alloy sono programmi Go che non richiedono di riservare heap in anticipo, e Grafana indica per Loki in modalità monolitica fino a circa 20GB al giorno. Il file compose di esempio di OpenSearch imposta 512 MB di heap per una demo e 2 GB nell'esempio per la produzione; Elastic specifica inoltre che l'heap deve restare al massimo pari al 50% della memoria totale. Di conseguenza, un heap da 2 GB richiede una macchina da 4 GB prima di aggiungere Kibana. La documentazione di Logstash raccomanda almeno 4GB di heap solo per il proprio processo. Queste sono impostazioni documentate, non benchmark: misura il tuo carico effettivo prima di definire il dimensionamento.

Qual è la differenza reale tra Loki e OpenSearch per i log?

Il modello di indicizzazione. Loki indicizza solo le label e conserva il corpo del log in chunk compressi, che vengono analizzati al momento della query. Le scritture sono quindi economiche, mentre le query ampie hanno un costo maggiore. OpenSearch indicizza il contenuto dei campi. La ricerca full-text arbitraria è quindi veloce, ma l'indice richiede sia memoria sia spazio su disco. Scegli Loki quando conosci il servizio e l'intervallo di tempo da analizzare. Scegli OpenSearch quando devi cercare testo che non puoi prevedere in anticipo.

Per quanto tempo devo conservare i log su un VPS?

Scegli il numero di giorni prima che lo faccia il disco al posto tuo. Impostalo in un solo punto per ogni sistema: MaxRetentionSec= e SystemMaxUse= per journald, retention_period con il compactor abilitato per Loki e una policy ISM con min_index_age per OpenSearch. Per la maggior parte delle configurazioni con un singolo server, da 14 a 30 giorni sono sufficienti per il debugging e l'analisi degli incidenti. Tutto ciò che devi conservare più a lungo appartiene a una copia archiviata fuori dal server, perché un log conservato solo sul server che ha avuto il guasto non costituisce una registrazione affidabile.

Promtail è ancora il modo corretto per inviare i log a Loki?

No. Promtail ha raggiunto la fine del ciclo di vita il 2 March 2026 e Grafana Alloy lo sostituisce. L'esempio di installazione di Loki per Docker include ora una configurazione di Alloy, mentre Grafana fornisce un convertitore che trasforma una configurazione Promtail esistente nella sintassi di Alloy. Un'installazione Promtail esistente continua a funzionare, ma non riceve correzioni. Considera quindi la migrazione un'attività di manutenzione, non un aggiornamento che puoi rimandare indefinitamente.

#logging#loki#opensearch#journald#monitoring