SSD Nodes Learn 🎉 VPS vanaf $5.50/mnd
Gidsen Matt ConnorDoor Matt Connor · Bijgewerkt 2026-08-13

Claude gebruiken voor Linux systeembeheer

Ontdek zes taken waarbij Claude uw serverbeheer ondersteunt: van het analyseren van logs en systemd units tot het controleren van nginx configuraties. Leer wat u nooit mag plakken.

Claude voor systeembeheerders: eerst advies, dan uitvoering

Claude voor systeembeheerders werkt het best als controleur. U plakt een logfragment, een configuratiebestand, een commando dat u niet herkent of een foutmelding, en u krijgt een uitleg die u kunt verifiëren voordat u wijzigingen op de server doorvoert. Een onjuist antwoord kost u niets zolang u het niet uitvoert; het model aan de adviserende kant van die grens houden is het volledige veiligheidsmodel.

Elke week komen er zes taken voorbij op een gehuurde Linux VPS (virtual private server). Voor elk van de onderstaande taken is er een promptpatroon dat werkt, het commando dat het antwoord verifieert en de foutmodus waar u rekening mee moet houden. Voor geen van deze taken hoeft het model toegang te hebben tot uw server.

De volgorde is van belang op een productieserver: lees de uitleg, voer zelf de controle uit en beslis dan. Autonomie is prima op een test-VM. Op de server die uw klanten bedient, wint controle, omdat het model de status waarover het speculeert niet kan inzien.

Wat u nooit mag plakken

Alles wat u in de prompt invoert, verlaat uw server. Vier categorieën gegevens moeten op de server blijven:

  • Privésleutels: ~/.ssh/id_ed25519, /etc/ssh/ssh_host_*_key en elke TLS (transport layer security) sleutel onder /etc/letsencrypt/live/.
  • Inloggegevens: .env, ~/.aws/credentials, /root/.docker/config.json en databasewachtwoorden in elk bestand of elke logregel.
  • Accountgegevens: /etc/shadow en /etc/gshadow. Geen enkele vraag over systeembeheer vereist een wachtwoordhash om beantwoord te kunnen worden.
  • Alles wat toebehoort aan uw gebruikers: e-mailadressen, orderregels, verzoeklogs met sessiecookies of PII (persoonlijk identificeerbare informatie).

Publieke sleutels zijn veilig om te plakken. Privésleutels zijn dat niet. De twee bestanden lijken op het eerste gezicht op elkaar, dus lees de eerste regel voordat u kopieert: een bestand waarvan de eerste regel BEGIN OPENSSH PRIVATE KEY bevat, mag nooit in een prompt worden geplaatst. Het beheren van uw SSH-sleutelmateriaal is op zichzelf tien minuten tijd waard.

Redigeer gegevens voordat u ze plakt, in plaats van erop te vertrouwen dat u één token in 200 regels tekst opmerkt:

sudo journalctl -u myapp -n 200 --no-pager | sed -E 's/(token|secret|password|api[_-]?key)[=:][^[:space:]]+/\1=REDACTED/gI'

Eén valkuil is specifiek voor Docker. docker compose config interpoleert uw .env-waarden in de uitvoer die het afdrukt; die uitvoer bevat dus geheimen, ook al was het bestand op de schijf dat niet. Gebruik docker compose config -q, dat valideert en niets afdrukt. Voor het bredere beleid over wat een agent mag zien, behandelt geheimen buiten AI-agents houden de kant van de omgeving.

Taak 1: waarom is deze service mislukt?

Begin met de twee commando's die het antwoord bevatten:

systemctl status myapp.service --no-pager
sudo journalctl -u myapp.service -b -n 100 --no-pager -o short-iso

Plak beide, inclusief de context die het model niet kan raden: de distributie en versie, wat u als laatste heeft gewijzigd, of het ooit heeft gewerkt en hoe lang geleden het defect is opgetreden. Vraag eerst naar het mechanisme.

Ubuntu 24.04. myapp.service werkte prima totdat ik een uur geleden de unit bewerkte. Hier is systemctl status en de laatste 100 regels uit het logboek. Welke regel is de eerste echte fout en wat betekent deze? Nog geen oplossing.

"Nog geen oplossing" is essentieel in deze prompt. Logboeken verbergen de eerste fout onder de herstelpogingen die daarop volgden, dus een model dat om een oplossing wordt gevraagd, zal de laatste regel uitleggen die het zag. De relevante regel staat meestal twintig regels boven de ruis.

Het resultaat is een regel zoals Main PID: 1841 (code=exited, status=203/EXEC). Exit status 203/EXEC betekent dat de kernel het bestand dat in ExecStart wordt genoemd niet kon uitvoeren: of het pad bestaat niet, of het bestand bestaat wel maar is niet uitvoerbaar. Een #!-regel die een interpreter noemt die niet is geïnstalleerd, produceert dezelfde status. Dit alles is testbaar met ls -l en head -1.

Foutmodus: een verzonnen oorzaak. Plak te weinig informatie en het model vult het gat op met iets algemeens, zoals "de poort is al in gebruik". De remedie is één wedervraag: "welke regel in wat ik u heb gegeven ondersteunt dat?" Een oorzaak waar niemand in de tekst naar kan wijzen, is een gok.

Taak 2: een systemd-unit of een cron-entry opstellen

Geef de benodigde gegevens op voor het unit-bestand: het exacte commando, de gebruiker waaronder het proces draait, de werkmap, of het moet wachten op het netwerk en wat er moet gebeuren bij een exitcode die niet nul is. Controleer vervolgens de output voordat u actie onderneemt.

sudo systemd-analyze verify /etc/systemd/system/myapp.service
sudo systemctl daemon-reload
sudo systemctl start myapp.service
systemctl status myapp.service --no-pager

systemd-analyze verify parseert het bestand op dezelfde wijze als systemd, waardoor fouten worden opgemerkt die bij handmatige controle vaak over het hoofd worden gezien. Een verkeerd gespelde instructie resulteert in /etc/systemd/system/myapp.service:7: Unknown key name 'Enviroment' in section 'Service', ignoring.. Een ontbrekend binair bestand resulteert in Command /usr/local/bin/myapp is not executable: No such file or directory. Beide blijven onopgemerkt tijdens daemon-reload, waardoor een unit correct kan laden maar direct faalt zodra deze wordt uitgevoerd.

Twee fouten bij het opstellen komen regelmatig voor. De eerste is After=network.target; dit betekent enkel dat de netwerkstack is geconfigureerd, niet dat er al een adres beschikbaar is. Een service die bindt aan een specifiek IP-adres faalt dan bij het opstarten met bind: Cannot assign requested address. De oplossing is Wants=network-online.target in combinatie met After=network-online.target. De tweede fout is Type=simple voor een programma dat zichzelf als daemon uitvoert: systemd beschouwt het eerste proces als de service, het ouderproces sluit direct af en de unit wordt als gestopt gemarkeerd, terwijl het eigenlijke proces onbeheerd doorloopt.

Controleer een planning in plaats van deze enkel te lezen:

systemd-analyze calendar 'Mon *-*-* 04:00:00'

Dit commando toont de genormaliseerde vorm en het eerstvolgende tijdstip waarop de expressie wordt uitgevoerd; dit neemt elke onduidelijkheid over de interpretatie weg. Als u twijfelt tussen een timer en een crontab, behandelt systemd services en timers op een VPS de voor- en nadelen.

Cron bevat een valkuil waar geen enkel model u voor waarschuwt tenzij u erom vraagt. Cron voert taken uit met een minimale omgeving; PATH is ongeveer /usr/bin:/bin en uw shell-profiel wordt nooit ingelezen. Een taak die werkt wanneer u deze in uw terminal plakt, faalt onder cron met /bin/sh: 1: docker: not found, omdat dat binaire bestand zich in /usr/local/bin bevindt. Gebruik absolute paden in crontabs.

Taak 3: controleer een Nginx- of Compose-bestand voordat het live gaat

Deze taak levert het meeste op. Plak het bestand, vermeld wat het hoort te doen en vraag om een regel-voor-regel uitleg van wat het daadwerkelijk doet.

Deze vhost moet example.com via HTTPS serveren en /api doorsturen naar een lokale service op poort 8080. Lees het voor mij terug en benoem alles wat niet overeenkomt met die beschrijving.

Voer daarna de tool uit die de grammatica kent:

sudo nginx -t
docker compose config -q

nginx -t geeft nginx: configuration file /etc/nginx/nginx.conf test is successful weer, of het benoemt het bestand en de regel, zoals in nginx: [emerg] unknown directive "proxy_pas" in /etc/nginx/conf.d/app.conf:12. docker compose config -q geeft niets weer als het bestand correct geparsed wordt, en iets kortaf zoals yaml: line 7: did not find expected key wanneer uw inspringing niet klopt.

Geen van beide tools controleert de intentie. Een configuratie die nginx -t doorstaat, kan nog steeds doorsturen naar de verkeerde poort of luisteren op 0.0.0.0 terwijl u 127.0.0.1 bedoelde. Dat gat is waar het model zijn waarde bewijst, en het is ook waar het faalt: als u vraagt om één directive te herstellen, wordt vaak het hele bestand herschreven waarbij twee van uw directives stilletjes verdwijnen. Vraag om de gewijzigde regels en de reden voor elke wijziging, en pas het daarna handmatig aan.

Bevestig wat u daadwerkelijk heeft blootgesteld:

sudo ss -tulpn

Zonder sudo ziet u de luisterende sockets, maar niet de processen die ze bezitten. Als die output u verrast, is wat poorten zijn en hoe Linux ze bindt de kortere leestip.

Taak 4: leg een onbekend commando uit voordat u het uitvoert

Plak het commando en stel vier vragen: wat doet elke vlag, wat schrijft het, wat verwijdert het en wat gebeurt er als ik het twee keer uitvoer? De laatste vraag voorkomt meer schade dan de andere.

Neem find /var/log -name '*.gz' -mtime +7 -delete. Een goed antwoord vertelt u dat -mtime +7 volledige periodes van 24 uur telt en de fractie negeert, waardoor het bestanden van ten minste acht dagen oud matcht in plaats van zeven. Het vertelt u ook dat find de expressie van links naar rechts evalueert, dus het verplaatsen van -delete vóór -name verwijdert alles onder het startpad. Dat tweede punt staat als waarschuwing in de find man-pagina en heeft mensen hun /var/log gekost.

Of neem rsync -a --delete /srv/app/ /backup/app/. De afsluitende slash bij de bron betekent "de inhoud van deze map". Laat deze weg en u krijgt /backup/app/app/. Voeg --delete toe en alles in de bestemming dat ontbreekt in de bron wordt verwijderd; dit is correct voor een mirror, maar een ramp als het bronpad onjuist is.

Controleer dit met de tool, niet met het model:

rsync -a --delete --dry-run /srv/app/ /backup/app/ | head -20
find /var/log -name '*.gz' -mtime +7

Voer de find uit zonder -delete en u krijgt een lijst in plaats van verlies.

Faalmodus: vlag-hallucinatie. Het model is betrouwbaar bij tools met dertig jaar aan documentatie en veel zwakker bij vendor CLI's (command line interfaces) en recente subcommando's, waarbij het een vlag genereert die logisch klinkt maar niet bestaat. --help lost dit in één seconde op. Quoting is het andere zwakke punt; dus wanneer een commando een $(...) expressie omvat, lees dan hoe command substitution expandeert voordat het commando wordt uitgevoerd in plaats van te vertrouwen op de uitleg.

Taak 5: zet uw shell-geschiedenis om in een runbook

U bent zojuist twee uur bezig geweest om iets werkend te krijgen. Die kennis zit nu in uw scrollback en is volgende maand verdwenen.

history 200 > /tmp/session.txt

Lees dat bestand en verwijder elke regel die een wachtwoord, token of klantidentificatie bevat voordat u het ergens anders opslaat. Shell-geschiedenis is een van de meest betrouwbare plekken om een geheim te vinden op een Linux-systeem, omdat iedereen wel eens een keer een wachtwoord direct in de opdrachtregel typt. Stel HISTCONTROL=ignorespace in uw ~/.bashrc in; een commando dat begint met een spatie wordt dan helemaal niet naar de geschiedenis geschreven.

De prompt die een bruikbaar runbook oplevert, vraagt om controles, niet alleen om stappen:

Dit is een shell-sessie die een verse Debian 13-server heeft omgezet naar een werkende Postgres-installatie. Schrijf dit uit als een genummerd runbook. Eén commando per stap. Geef na elke stap het commando dat bewijst dat het werkte en beschrijf hoe gezonde output eruitziet. Markeer elke stap die afhankelijk was van mijn specifieke host.

Faalmodus: een te netjes verhaal. Uw sessie bevatte een stap die u twee keer fout deed voordat u deze herstelde, en dat is precies de stap die het model wegpoetst omdat het transcript zonder die fout schoner leest. Vergelijk het runbook met uw geschiedenis en voeg de correctie weer toe. Het model verzint ook aannemelijke verificatiecommando's, dus voer elke controle die het schrijft uit voordat u het bestand opslaat. Als het runbook een eerste opstart betreft, vergelijk het dan met de eerste tien minuten op een nieuwe VPS zodat u geen slechtere versie van een reeds opgelost probleem documenteert.

Taak 6: een foutmelding omzetten in een oplossing

Plak de exacte tekenreeks, het commando dat deze genereerde en het ene ding dat u wijzigde voordat deze verscheen. Vraag om een rangschikking van oorzaken met een onderscheidend commando voor elk, wat het antwoord dwingt tot iets testbaars.

nginx: [emerg] bind() to 0.0.0.0:80 failed (98: Address already in use). Rangschik de waarschijnlijke oorzaken en geef mij één commando per oorzaak dat deze bevestigt of uitsluit.

Voor die fout is het mechanisme niet dubbelzinnig: een ander proces houdt al poort 80 bezet en sudo ss -tulpn | grep ':80 ' benoemt dit. Vaak is het een tweede nginx master die is achtergebleven na een mislukte herlaadactie, of Apache dat als afhankelijkheid is meegekomen en door zijn eigen pakket is gestart.

Faalmodus: een oplossing die werkt door de oorzaak te verbergen. chmod 777, --privileged, het uitschakelen van SELinux en het uitvoeren van de service als root laten de fout allemaal verdwijnen. Weiger elke oplossing die de rechten verruimt totdat het model heeft uitgelegd waarom de beperkte rechten faalden. Die uitleg is het eigenlijke antwoord. Een workaround maakt de fout alleen maar stil.

Wat er steevast misgaat

  • Het kan uw server niet inzien. Elk antwoord is gebaseerd op wat u heeft geplakt, en het zal niet aangeven dat het fragment te kort was.
  • Het loopt achter op versies. Pakketnamen en standaard-flags veranderen tussen distributies en releases, en het model middelt over al deze varianten heen.
  • Het is overtuigend wanneer het onjuist is. Een gefantaseerd mechanisme leest exact als een correcte procedure; daarom is elke hierboven genoemde oorzaak voorzien van een commando om dit te verifiëren.
  • Het verliest de draad tijdens lange sessies. Feiten van het begin van een gesprek van twee uur beïnvloeden de antwoorden aan het einde niet meer.

Dat laatste punt is eerder een werkmethodeprobleem dan een probleem van het model zelf, en contextbeheer in een lange Claude Code-sessie is de praktische oplossing: kortere sessies, één taak per keer.

De agent op de server zelf plaatsen

Alles hierboven is kopiëren en plakken, waardoor het model uw machine nooit aanraakt. Zodra het op de server draait, bestanden leest en commando's uitvoert, verandert de aard van het risico: een foutief commando kost u nu een service. Geef de agent een eigen gebruiker zonder privileges in plaats van root, houd deze weg van de productieserver totdat u de werking kent, en maak eerst een snapshot. Claude Code veilig draaien op een VPS behandelt de sandboxing en het permissiemodel. Claude Code aansturen binnen tmux lost het andere deel op, aangezien een verbroken SSH (secure shell)-sessie een agent op de voorgrond halverwege zijn werk beëindigt. Richt het account in zoals u elk service-account zou inrichten, wat gebruikers met minimale rechten op een VPS in detail beschrijft.

FAQ

Kan Claude mijn serverlogs direct inzien?

Niet uit zichzelf. De chatinterface ziet alleen de tekst die u erin plakt. Claude Code, uitgevoerd op de server als command-line tool, kan bestanden lezen en commando's uitvoeren met de rechten van de gebruiker die het heeft gestart; dit is een ingrijpendere beslissing wat betreft vertrouwen. Voor een algemene ondersteuningsvraag is het plakken van een geanonimiseerd fragment van 100 regels sneller en veiliger dan het verlenen van shell-toegang aan een agent.

Wat mag ik nooit kopiëren vanaf een server?

Private keys, .env-bestanden en andere credential stores, /etc/shadow, en alle gegevens die toebehoren aan uw gebruikers. Verwijder tokens uit logfragmenten voordat deze in de prompt terechtkomen. Een minder voor de hand liggend geval: de output van docker compose config bevat uw .env-waarden; gebruik daarom docker compose config -q, dat het bestand valideert zonder output te tonen.

Is het veilig om Claude commando's te laten uitvoeren op een productie-VPS?

Behandel het als een nieuwe beheerder zonder context: prima voor het lezen, maar controle is vereist voor het schrijven. Vraag op productieomgevingen om uitleg en voer het commando zelf uit. Als u een agent wilt laten uitvoeren, geef deze dan een toegewezen account zonder sudo-rechten en start op een staging-omgeving waar een fout slechts een herbouw kost in plaats van een storing.

Waarom stelt Claude een flag voor die niet bestaat?

Omdat het model aannemelijke tekst voorspelt, en een aannemelijke flag ziet er hetzelfde uit als een echte. Dit gebeurt vooral bij vendor-CLI's en nieuwere subcommands, waarvoor de documentatie achter het model beperkt is of inmiddels is gewijzigd. --help en man zijn de enige bron van waarheid; elk commando dat gegevens verwijdert of overschrijft, verdient eerst een dry run.

Hoe controleer ik een systemd-unit voordat ik deze inschakel?

Voer sudo systemd-analyze verify /etc/systemd/system/myapp.service uit. Dit parseert het bestand met de eigen parser van systemd, rapporteert onbekende richtlijnen met hun regelnummers en markeert een ExecStart-binary die ontbreekt of niet uitvoerbaar is. Voer daarna daemon-reload en start uit en lees systemctl status voordat u het enable, omdat een unit die correct laadt, bij de eerste uitvoering alsnog kan falen.