Claude per sysadmin: attività quotidiane sui server
Scopri 6 attività utili: analizzare i log di un’unità fallita, scrivere unit systemd e verificare file nginx e Compose, senza incollare dati segreti.
Claude per amministratori di sistema: prima i consigli, poi l'esecuzione
Claude per gli amministratori di sistema funziona meglio come strumento di revisione. Incolla un estratto di log, un file di configurazione, un comando che non riconosci o una stringa di errore e riceverai una spiegazione che puoi verificare prima di modificare il server. Una risposta errata non comporta conseguenze finché non la esegui; per questo, mantenere il modello sul lato dei consigli è l'intero modello di sicurezza.
Su un Linux VPS (virtual private server) a noleggio, ogni settimana ricorrono sei attività. Per ciascuna trovi un modello di prompt efficace, il comando che consente di verificare la risposta e il tipo di errore che devi aspettarti. Nessuna richiede che il modello abbia accesso al server.
Su un server di produzione, l'ordine è importante: leggi la spiegazione, esegui personalmente il controllo, quindi decidi. Su una VM di test l'autonomia è accettabile. Sul server che eroga i servizi ai clienti, invece, la revisione è preferibile, perché il modello non può vedere lo stato reale su cui basa le proprie ipotesi.
Cosa non devi mai incollare
Tutto ciò che inserisci nel prompt lascia il tuo server. Quattro categorie devono restare sul server:
- Chiavi private:
~/.ssh/id_ed25519,/etc/ssh/ssh_host_*_keye qualsiasi chiave TLS (transport layer security) contenuta in/etc/letsencrypt/live/. - File con credenziali:
.env,~/.aws/credentials,/root/.docker/config.jsone le password del database presenti in qualsiasi file o riga di log. - Dati degli account:
/etc/shadowe/etc/gshadow. Per rispondere a una domanda di amministrazione di sistema non serve alcun hash di password. - Qualsiasi dato appartenente ai tuoi utenti: indirizzi email, righe degli ordini, log delle richieste contenenti cookie di sessione o PII (personally identifiable information).
Le chiavi pubbliche possono essere incollate. Le chiavi private no. I due file sembrano simili a prima vista, quindi leggi la prima riga prima di copiare: un file la cui prima riga contiene BEGIN OPENSSH PRIVATE KEY non deve mai essere inserito in un prompt. Gestire correttamente il materiale delle chiavi SSH richiede solo dieci minuti.
Oscura i dati prima di incollarli, invece di affidarti alla capacità di individuare un singolo token in 200 righe:
sudo journalctl -u myapp -n 200 --no-pager | sed -E 's/(token|secret|password|api[_-]?key)[=:][^[:space:]]+/\1=REDACTED/gI'Docker presenta un rischio specifico. docker compose config interpola i valori di .env nell'output che visualizza, quindi quell'output è un secret anche se il file sul disco non lo era. Usa docker compose config -q, che esegue la convalida senza visualizzare nulla. Per la policy più generale su ciò che un agent può vedere, tenere i secret fuori dagli agent AI descrive gli aspetti relativi all'ambiente.
Job 1: perché questo servizio non è riuscito ad avviarsi?
Inizia con i due comandi che contengono la risposta:
systemctl status myapp.service --no-pager
sudo journalctl -u myapp.service -b -n 100 --no-pager -o short-isoIncolla entrambi i risultati e aggiungi il contesto che il modello non può dedurre: distribuzione e versione, ultima modifica effettuata, se il servizio ha mai funzionato e da quanto tempo si è verificato il problema. Chiedi prima di identificare il meccanismo.
Ubuntu 24.04.myapp.servicefunzionava correttamente finché un'ora fa ho modificato l'unità. Eccosystemctl statuse le ultime 100 righe del journal. Qual è la prima riga che mostra un errore reale e che cosa significa? Per ora non indicare soluzioni.
"Per ora non indicare soluzioni" è una parte importante della richiesta. I log nascondono spesso il primo errore sotto i tentativi di riavvio che ha provocato. Se chiedi subito una soluzione, il modello spiegherà l'ultima riga che ha trovato. La riga rilevante si trova spesso circa 20 righe prima del rumore.
Il risultato può essere una riga come Main PID: 1841 (code=exited, status=203/EXEC). Il codice di uscita 203/EXEC indica che il kernel non ha potuto eseguire il file specificato in ExecStart: il percorso non esiste oppure il file esiste ma non ha il bit di esecuzione. Una riga #! che indica un interprete non installato produce lo stesso codice. Tutto questo è verificabile con ls -l e head -1.
Modalità di errore: una causa inventata. Se incolli troppo poco, il modello colma le informazioni mancanti con un'ipotesi generica, ad esempio "la porta è già in uso". La correzione consiste nel porre una domanda di verifica: "Quale riga di ciò che ti ho fornito supporta questa conclusione?" Una causa che nessuno può indicare nel testo è soltanto un'ipotesi.
Attività 2: preparare un'unità systemd o una voce cron
Fornisci tutti i dati necessari al file dell'unità: il comando esatto, l'utente con cui deve essere eseguito, la directory di lavoro, se deve attendere la rete e cosa deve accadere quando termina con un codice diverso da zero. Verifica quindi il risultato prima di abilitare qualsiasi elemento.
sudo systemd-analyze verify /etc/systemd/system/myapp.service
sudo systemctl daemon-reload
sudo systemctl start myapp.service
systemctl status myapp.service --no-pagersystemd-analyze verify analizza il file come farebbe systemd, rilevando anche gli errori che sfuggono a un controllo manuale. Una direttiva scritta in modo errato produce /etc/systemd/system/myapp.service:7: Unknown key name 'Enviroment' in section 'Service', ignoring.. Un binario mancante produce Command /usr/local/bin/myapp is not executable: No such file or directory. Entrambi restano silenziosi durante daemon-reload. Per questo un'unità può essere caricata senza errori e fallire solo quando viene eseguita.
Due errori di preparazione ricorrono spesso. Il primo è After=network.target, che indica soltanto che lo stack di rete è configurato, non che sia già disponibile un indirizzo. Un servizio associato a un IP specifico può quindi fallire durante l'avvio con bind: Cannot assign requested address. La correzione consiste in Wants=network-online.target insieme a After=network-online.target. Il secondo è Type=simple per un programma che si esegue come demone: systemd considera il primo processo come il servizio, il processo padre termina subito e l'unità viene contrassegnata come terminata, mentre il processo reale continua a essere eseguito senza supervisione.
Per una pianificazione, verificala invece di limitarti a leggerla:
systemd-analyze calendar 'Mon *-*-* 04:00:00'Il comando stampa la forma normalizzata e il prossimo momento in cui l'espressione verrà eseguita. In questo modo chiarisce il significato effettivo della pianificazione. Se devi scegliere tra un timer e un crontab, servizi e timer systemd su un VPS illustra i compromessi.
Cron presenta un problema che nessun modello segnala se non lo chiedi esplicitamente. Cron esegue i job con un ambiente minimo. Di conseguenza, PATH è all'incirca /usr/bin:/bin e il profilo della shell non viene mai letto. Un job che funziona quando lo incolli nel terminale fallisce con cron mostrando /bin/sh: 1: docker: not found, perché il binario si trova in /usr/local/bin. Nei crontab usa percorsi assoluti.
Job 3: verifica un file nginx o Compose prima di metterlo in produzione
Questo lavoro offre il miglior ritorno. Incolla il file, descrivi il comportamento previsto e chiedi un'analisi riga per riga di ciò che esegue realmente.
Questo vhost dovrebbe pubblicareexample.comtramite HTTPS e inoltrare/apia un servizio locale sulla porta 8080. Rileggilo e indica tutto ciò che non corrisponde a questa descrizione.
Poi esegui lo strumento che verifica la sintassi:
sudo nginx -t
docker compose config -qnginx -t stampa nginx: configuration file /etc/nginx/nginx.conf test is successful oppure indica il file e la riga, come in nginx: [emerg] unknown directive "proxy_pas" in /etc/nginx/conf.d/app.conf:12. docker compose config -q non stampa nulla quando il file è valido, mentre restituisce un messaggio esplicito come yaml: line 7: did not find expected key se l'indentazione non è corretta.
Nessuno dei due strumenti verifica l'intento. Una configurazione che supera nginx -t può comunque inoltrare le richieste alla porta sbagliata oppure restare in ascolto su 0.0.0.0 quando volevi usare 127.0.0.1. È in questo punto che il modello può essere utile, ma anche commettere errori: se gli chiedi di correggere una direttiva, spesso restituisce l'intero file riscritto e rimuove senza avvisare due direttive esistenti. Chiedi le righe modificate e il motivo di ogni modifica, quindi applica manualmente le correzioni.
Verifica ciò che hai realmente esposto:
sudo ss -tulpnSenza sudo puoi vedere i socket in ascolto, ma non i processi che li gestiscono. Se l'output ti sorprende, leggi cosa sono le porte e come Linux le associa: è una spiegazione più breve.
Job 4: spiega un comando non familiare prima di eseguirlo
Incolla il comando e poni quattro domande: cosa fa ogni flag, cosa scrive, cosa elimina e cosa succede se lo eseguo due volte. L'ultima domanda evita più danni delle altre.
Prendi find /var/log -name '*.gz' -mtime +7 -delete. Una buona risposta spiega che -mtime +7 conta periodi completi di 24 ore e scarta la frazione, quindi corrisponde ai file vecchi di almeno otto giorni, non di sette. Spiega anche che find valuta l'espressione da sinistra a destra: se sposti -delete prima di -name, elimini tutto ciò che si trova sotto il percorso iniziale. Il secondo punto è riportato come avvertenza nella pagina man di find e ha fatto perdere a molte persone il contenuto del loro /var/log.
Oppure prendi rsync -a --delete /srv/app/ /backup/app/. La barra finale nel percorso sorgente significa "il contenuto di questa directory". Se la rimuovi, ottieni /backup/app/app/. Se aggiungi --delete, tutto ciò che nella destinazione manca dalla sorgente viene rimosso. Questo è corretto per un mirror, ma causa un disastro se il percorso sorgente è errato.
Verifica con lo strumento, non con il modello:
rsync -a --delete --dry-run /srv/app/ /backup/app/ | head -20
find /var/log -name '*.gz' -mtime +7Esegui find senza -delete per ottenere un elenco invece di una perdita di dati.
Modalità di errore: allucinazione dei flag. Il modello è affidabile con strumenti documentati da trent'anni, ma molto meno con le CLI (interfacce della riga di comando) dei fornitori e con i subcommand recenti. In questi casi produce un flag che sembra corretto ma non esiste. --help risolve il dubbio in un secondo. Anche il quoting è un punto debole. Quando un comando contiene un'espressione $(...), leggi come si espande la sostituzione dei comandi prima dell'esecuzione del comando invece di fidarti della spiegazione.
Job 5: trasforma la cronologia della shell in una procedura operativa
Hai appena impiegato due ore per far funzionare qualcosa. Quella conoscenza è nella cronologia del terminale e il mese prossimo potrebbe non essere più disponibile.
history 200 > /tmp/session.txtLeggi quel file ed elimina ogni riga contenente una password, un token o un identificativo del cliente prima di utilizzarlo. La cronologia della shell è uno dei punti più affidabili in cui cercare un secret su un sistema Linux, perché prima o poi tutti ne inseriscono almeno uno direttamente nella riga di comando. Imposta HISTCONTROL=ignorespace nel file ~/.bashrc: un comando digitato con uno spazio iniziale non viene mai scritto nella cronologia.
Il prompt che produce una procedura operativa utilizzabile deve richiedere verifiche, non solo passaggi:
Questa è una sessione shell che ha portato un sistema Debian 13 appena installato a un'installazione funzionante di Postgres. Redigila come procedura operativa numerata. Inserisci un comando per ogni passaggio. Dopo ogni passaggio, indica il comando che dimostra che il passaggio è riuscito e descrivi l'aspetto dell'output corretto. Contrassegna ogni passaggio che dipendeva dalle caratteristiche specifiche del mio host.
Rischio: ottenere una ricostruzione ordinata. Nella sessione c'è stato un passaggio eseguito due volte in modo errato prima della correzione, e il modello tende a eliminare proprio quel passaggio perché la trascrizione risulta più chiara senza di esso. Confronta la procedura con la cronologia e reinserisci la correzione. Il modello può inoltre inventare comandi di verifica plausibili: esegui ogni controllo che inserisce prima di salvare il file. Se la procedura riguarda il primo avvio, confrontala con i primi dieci minuti su un nuovo VPS per evitare di documentare una versione peggiore di un problema già risolto.
Attività 6: trasformare un messaggio di errore in una soluzione
Incolla la stringa esatta, il comando che l'ha prodotta e l'unica modifica effettuata prima che comparisse. Chiedi di elencare le cause in ordine di probabilità e di fornire un comando distintivo per ciascuna. In questo modo la risposta diventa verificabile.
nginx: [emerg] bind() to 0.0.0.0:80 failed (98: Address already in use). Elenca le cause più probabili e fornisci un comando per ciascuna, in modo da confermarle o escluderle.
Per questo errore il meccanismo è chiaro: un altro processo sta già usando la porta 80 e sudo ss -tulpn | grep ':80 ' ne indica l'identità. Spesso si tratta di un secondo processo master di nginx rimasto attivo dopo un reload non riuscito, oppure di Apache, installato come dipendenza e avviato dal relativo pacchetto.
Modalità di errore: una soluzione che nasconde la causa. chmod 777, --privileged, la disattivazione di SELinux e l'esecuzione del servizio come root fanno scomparire l'errore. Rifiuta qualsiasi soluzione che aumenti i permessi finché il modello non ha spiegato perché il permesso più restrittivo non era sufficiente. Questa spiegazione è la risposta effettiva. Una soluzione temporanea rende soltanto silenzioso l'errore.
Cosa sbaglia in modo sistematico
- Non può vedere il tuo server. Ogni risposta dipende da ciò che hai incollato e non ti dirà che l'estratto era troppo breve.
- Tende a confondere le versioni. I nomi dei pacchetti e i flag predefiniti cambiano tra distribuzioni e release, mentre il modello fa una media tra tutte.
- È fluido anche quando sbaglia. Un meccanismo inventato sembra identico a uno corretto. Per questo ogni causa precedente include un comando per verificarla.
- Perde il filo nelle sessioni lunghe. I fatti iniziali di una conversazione di due ore smettono di influenzare le risposte finali.
Quest'ultimo è soprattutto un problema operativo, più che un limite del modello. La soluzione pratica è gestire il contesto in una sessione lunga di Claude Code: sessioni più brevi, una sola attività per sessione.
Mettere l’agente direttamente sul server
Tutto quanto riportato sopra consiste in operazioni di copia e incolla, quindi il modello non accede mai alla tua macchina. Quando l’agente viene eseguito sul server, legge file ed esegue comandi; di conseguenza, il profilo di rischio cambia: un comando errato può arrestare un servizio. Assegna all’agente un utente non privilegiato dedicato invece di usare root, non eseguirlo sul server di produzione mentre ne valuti il comportamento e crea prima uno snapshot. Eseguire Claude Code in sicurezza su un VPS descrive il sandboxing e il modello dei permessi. Eseguire Claude Code all’interno di tmux risolve l’altro problema: la chiusura di una sessione SSH (secure shell) interrompe un agente in primo piano mentre sta eseguendo un’attività. Configura l’account come faresti con un normale account di servizio; la procedura è descritta in utenti con privilegi minimi su un VPS.
FAQ
Claude può leggere direttamente i log del mio server?
Non autonomamente. L'interfaccia di chat vede soltanto il testo che incolli. Claude Code, eseguito sul server come strumento da riga di comando, può leggere file ed eseguire comandi con i permessi dell'utente che lo ha avviato: si tratta di una decisione che richiede un livello di fiducia maggiore. Per una normale richiesta di supporto, incollare un estratto di 100 righe con i dati sensibili rimossi è più rapido e sicuro che concedere a un agente l'accesso alla shell.
Cosa non devo mai incollare dal server?
Chiavi private, file .env e altri archivi di credenziali, /etc/shadow e qualsiasi dato appartenente agli utenti. Rimuovi i token dagli estratti dei log prima che raggiungano il prompt. Un caso meno evidente è l'output di docker compose config, che contiene i valori .env interpolati; usa quindi docker compose config -q, che convalida il file senza stampare nulla.
È sicuro consentire a Claude di eseguire comandi su un VPS di produzione?
Trattalo come un nuovo amministratore senza alcun contesto: va bene per la lettura, mentre le modifiche richiedono una revisione. In produzione, chiedi la spiegazione ed esegui personalmente il comando. Se vuoi comunque che sia un agente a eseguire i comandi, assegnagli un account dedicato senza privilegi, privo di accesso sudo generalizzato, e inizia su un server di staging, dove un errore comporta una nuova installazione anziché un'interruzione del servizio.
Perché Claude suggerisce un flag che non esiste?
Perché predice testo plausibile, e un flag plausibile ha lo stesso aspetto di uno reale. Questo accade soprattutto con le CLI dei produttori e con i sottocomandi più recenti, per i quali la documentazione disponibile per il modello è scarsa o nel frattempo è cambiata. --help e man fanno fede; inoltre, per ogni comando che elimina o sovrascrive dati, esegui prima una simulazione.
Come posso controllare un'unità systemd prima di abilitarla?
Esegui sudo systemd-analyze verify /etc/systemd/system/myapp.service. Analizza il file con il parser interno di systemd, segnala le direttive sconosciute indicando i numeri di riga e rileva un binario ExecStart mancante o non eseguibile. Esegui quindi daemon-reload, start e leggi systemctl status prima di enable l'unità, perché un'unità che viene caricata correttamente può comunque non funzionare alla prima esecuzione.